mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-21 01:53:26 +00:00
Update hint block (#2840)
Co-authored-by: Valentino Hudhra <v.hudhra@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'gitbook': patch
|
||||
---
|
||||
|
||||
Update design for hint block: use semantic colors (info, warning, danger, success) and add alternative styling for hints with headings
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"packages/colors": {
|
||||
"name": "@gitbook/colors",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"devDependencies": {
|
||||
"typescript": "^5.5.3",
|
||||
},
|
||||
@@ -38,9 +38,9 @@
|
||||
},
|
||||
"packages/gitbook": {
|
||||
"name": "gitbook",
|
||||
"version": "0.6.1",
|
||||
"version": "0.6.2",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "^0.94.0",
|
||||
"@gitbook/api": "^0.95.0",
|
||||
"@gitbook/cache-do": "workspace:*",
|
||||
"@gitbook/colors": "workspace:*",
|
||||
"@gitbook/emoji-codepoints": "workspace:*",
|
||||
@@ -155,7 +155,7 @@
|
||||
},
|
||||
"packages/openapi-parser": {
|
||||
"name": "@gitbook/openapi-parser",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"dependencies": {
|
||||
"@scalar/openapi-parser": "^0.10.4",
|
||||
"@scalar/openapi-types": "^0.1.6",
|
||||
@@ -211,7 +211,7 @@
|
||||
},
|
||||
"packages/react-openapi": {
|
||||
"name": "@gitbook/react-openapi",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"dependencies": {
|
||||
"@gitbook/openapi-parser": "workspace:*",
|
||||
"@scalar/api-client-react": "1.0.87",
|
||||
@@ -4651,7 +4651,7 @@
|
||||
|
||||
"gaxios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
|
||||
|
||||
"gitbook/@gitbook/api": ["@gitbook/api@0.94.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-jOvqUSdyXeuPpBiujkQLb14uVQA5A0XL+P89MmC/53hV7v/8gR8WlJN9RJVDrP0LX51dsLT+/zYN8xWp19nPwA=="],
|
||||
"gitbook/@gitbook/api": ["@gitbook/api@0.95.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-9KAbt27Ile6cqAch7QEbiJHALQHojYlhsPzilgdQ5wpHgLwsrd7Smd58A3/8bWBKq4KV0vP4rh3oYhIw+LlWFw=="],
|
||||
|
||||
"gitbook-v2/next": ["next@15.2.0-canary.45", "", { "dependencies": { "@next/env": "15.2.0-canary.45", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.2.0-canary.45", "@next/swc-darwin-x64": "15.2.0-canary.45", "@next/swc-linux-arm64-gnu": "15.2.0-canary.45", "@next/swc-linux-arm64-musl": "15.2.0-canary.45", "@next/swc-linux-x64-gnu": "15.2.0-canary.45", "@next/swc-linux-x64-musl": "15.2.0-canary.45", "@next/swc-win32-arm64-msvc": "15.2.0-canary.45", "@next/swc-win32-x64-msvc": "15.2.0-canary.45", "sharp": "^0.33.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-UsneTQn9tntbiAaXpvoXhhsTBb58Q2XIs2Dfka+qWA8motBz0ZvW297YHLxhdur4xN0IJvknnZKl5Bs7wAGlOg=="],
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
CustomizationThemeMode,
|
||||
SiteCustomizationSettings,
|
||||
} from '@gitbook/api';
|
||||
import { test, expect, Page, BrowserContext } from '@playwright/test';
|
||||
import { BrowserContext, expect, Page, test } from '@playwright/test';
|
||||
import deepMerge from 'deepmerge';
|
||||
import rison from 'rison';
|
||||
import { DeepPartial } from 'ts-essentials';
|
||||
@@ -222,6 +222,10 @@ export function getCustomizationURL(partial: DeepPartial<SiteCustomizationSettin
|
||||
styling: {
|
||||
theme: newTheme,
|
||||
primaryColor: { light: '#346DDB', dark: '#346DDB' },
|
||||
infoColor: { light: '#787878', dark: '#787878' },
|
||||
warningColor: { light: '#FE9A00', dark: '#FE9A00' },
|
||||
dangerColor: { light: '#FB2C36', dark: '#FB2C36' },
|
||||
successColor: { light: '#00C950', dark: '#00C950' },
|
||||
corners: CustomizationCorners.Rounded,
|
||||
font: CustomizationFont.Inter,
|
||||
background: CustomizationBackground.Plain,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"clean": "rm -rf ./.next && rm -rf ./public/~gitbook/static/icons && rm -rf ./public/~gitbook/static/math"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gitbook/api": "^0.94.0",
|
||||
"@gitbook/api": "^0.95.0",
|
||||
"@gitbook/cache-do": "workspace:*",
|
||||
"@gitbook/colors": "workspace:*",
|
||||
"@gitbook/emoji-codepoints": "workspace:*",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { DocumentBlockHeading } from '@gitbook/api';
|
||||
import type { DocumentBlockHeading } from '@gitbook/api';
|
||||
import { Icon } from '@gitbook/icons';
|
||||
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
|
||||
import { BlockProps } from './Block';
|
||||
import type { BlockProps } from './Block';
|
||||
import { Inlines } from './Inlines';
|
||||
import { getBlockTextStyle } from './spacing';
|
||||
|
||||
@@ -24,6 +24,7 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
|
||||
>
|
||||
<div
|
||||
className={tcls(
|
||||
'hash',
|
||||
'grid',
|
||||
'grid-area-1-1',
|
||||
'relative',
|
||||
@@ -41,20 +42,14 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
|
||||
<a
|
||||
href={`#${id}`}
|
||||
aria-label="Direct link to heading"
|
||||
className={tcls(
|
||||
'inline-flex',
|
||||
'h-full',
|
||||
'items-start',
|
||||
'dark:shadow-none',
|
||||
'dark:ring-0',
|
||||
textStyle.lineHeight,
|
||||
)}
|
||||
className={tcls('inline-flex', 'h-full', 'items-start', textStyle.lineHeight)}
|
||||
>
|
||||
<Icon
|
||||
icon="hashtag"
|
||||
className={tcls(
|
||||
'w-3.5',
|
||||
'h-[1lh]',
|
||||
'h-[1em]',
|
||||
'mt-0.5',
|
||||
'transition-colors',
|
||||
'text-transparent',
|
||||
'group-hover:text-tint-subtle',
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { DocumentBlockHint } from '@gitbook/api';
|
||||
import { Icon, IconName } from '@gitbook/icons';
|
||||
import type { DocumentBlockHeading, DocumentBlockHint } from '@gitbook/api';
|
||||
import { Icon, type IconName } from '@gitbook/icons';
|
||||
import React from 'react';
|
||||
|
||||
import { ClassValue, tcls } from '@/lib/tailwind';
|
||||
import { type ClassValue, tcls } from '@/lib/tailwind';
|
||||
|
||||
import { BlockProps } from './Block';
|
||||
import { Block, type BlockProps } from './Block';
|
||||
import { Blocks } from './Blocks';
|
||||
import { getBlockTextStyle } from './spacing';
|
||||
|
||||
@@ -13,41 +13,73 @@ export function Hint(props: BlockProps<DocumentBlockHint>) {
|
||||
const hintStyle = HINT_STYLES[block.data.style] ?? HINT_STYLES.info;
|
||||
const firstLine = getBlockTextStyle(block.nodes[0]);
|
||||
|
||||
const firstNode = block.nodes[0];
|
||||
const hasHeading = ['heading-1', 'heading-2', 'heading-3'].includes(block.nodes[0].type);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={tcls(
|
||||
'hint',
|
||||
'p-4',
|
||||
'transition-colors',
|
||||
'rounded-md',
|
||||
hasHeading ? 'rounded-l' : null,
|
||||
'straight-corners:rounded-none',
|
||||
hintStyle.style,
|
||||
'overflow-hidden',
|
||||
hasHeading ? ['border-l-2', hintStyle.containerWithHeader] : hintStyle.container,
|
||||
|
||||
'text-sm',
|
||||
|
||||
'grid',
|
||||
'grid-cols-[auto_1fr]',
|
||||
hasHeading ? 'grid-rows-[auto_auto]' : '',
|
||||
|
||||
style,
|
||||
)}
|
||||
>
|
||||
<div className={tcls('flex', 'flex-row')}>
|
||||
<div
|
||||
className={tcls(
|
||||
'py-3',
|
||||
'pl-3',
|
||||
hasHeading ? hintStyle.header : null,
|
||||
hintStyle.iconColor,
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
icon={hintStyle.icon}
|
||||
className={tcls(
|
||||
'size-5',
|
||||
'mr-4',
|
||||
'mt-0.5',
|
||||
firstLine.lineHeight,
|
||||
hintStyle.iconColor,
|
||||
)}
|
||||
/>
|
||||
<Blocks
|
||||
{...contextProps}
|
||||
ancestorBlocks={[...ancestorBlocks, block]}
|
||||
nodes={block.nodes}
|
||||
blockStyle={tcls(
|
||||
hintStyle.bodyColor,
|
||||
// render hash icon on the other side of the heading
|
||||
'flip-heading-hash',
|
||||
)}
|
||||
style={['flex-1', 'space-y-4', '[&_.hint]:border', '[&_pre]:border']}
|
||||
className={tcls('size-[1.2em]', 'mt-0.5', firstLine.lineHeight)}
|
||||
/>
|
||||
</div>
|
||||
{hasHeading ? (
|
||||
<Block
|
||||
style={tcls(
|
||||
'text-[1em] *:mt-0 p-3 flip-heading-hash',
|
||||
hasHeading ? hintStyle.header : null,
|
||||
)}
|
||||
ancestorBlocks={[...ancestorBlocks, block]}
|
||||
{...contextProps}
|
||||
block={firstNode}
|
||||
/>
|
||||
) : null}
|
||||
<Blocks
|
||||
{...contextProps}
|
||||
ancestorBlocks={[...ancestorBlocks, block]}
|
||||
nodes={hasHeading ? block.nodes.slice(1) : block.nodes}
|
||||
blockStyle={tcls(
|
||||
hintStyle.body,
|
||||
// render hash icon on the other side of the heading
|
||||
'flip-heading-hash',
|
||||
)}
|
||||
style={[
|
||||
'p-3',
|
||||
'empty:p-0',
|
||||
'-row-end-1',
|
||||
'-col-end-1',
|
||||
'space-y-4',
|
||||
'[&_.hint]:border',
|
||||
'[&_pre]:border',
|
||||
'[&_pre]:border-neutral',
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -55,77 +87,69 @@ export function Hint(props: BlockProps<DocumentBlockHint>) {
|
||||
const HINT_STYLES: {
|
||||
[style in DocumentBlockHint['data']['style']]: {
|
||||
icon: IconName;
|
||||
iconColor: ClassValue;
|
||||
bodyColor: ClassValue;
|
||||
style: ClassValue;
|
||||
iconColor?: ClassValue;
|
||||
body?: ClassValue;
|
||||
header?: ClassValue;
|
||||
container?: ClassValue;
|
||||
containerWithHeader?: ClassValue;
|
||||
};
|
||||
} = {
|
||||
info: {
|
||||
icon: 'circle-info',
|
||||
iconColor: ['text-primary'],
|
||||
bodyColor: ['[&_a]:text-primary', '[&_a:hover]:text-primary-strong'],
|
||||
style: [
|
||||
'bg-tint',
|
||||
'print-mode:!bg-tint',
|
||||
'theme-muted:bg-tint-base',
|
||||
'theme-bold-tint:bg-tint-base',
|
||||
'theme-gradient:bg-tint-12/1',
|
||||
'border-tint',
|
||||
'[&_.can-override-bg]:bg-tint-active',
|
||||
'[&_.can-override-text]:text-tint-strong',
|
||||
iconColor: 'text-info-subtle contrast-more:text-info',
|
||||
header: 'bg-info-active',
|
||||
body: [
|
||||
'text-neutral-strong',
|
||||
'[&_.can-override-bg]:bg-neutral-active',
|
||||
'[&_.can-override-text]:text-neutral-strong',
|
||||
],
|
||||
container:
|
||||
'bg-neutral theme-muted:bg-neutral-base theme-bold-tint:bg-neutral-base theme-gradient:bg-neutral-12/1 border-neutral',
|
||||
containerWithHeader: 'border-info-solid bg-neutral-subtle theme-gradient:bg-neutral-12/1',
|
||||
},
|
||||
warning: {
|
||||
icon: 'circle-exclamation',
|
||||
iconColor: ['text-amber-500', 'dark:text-orange-400'], // Darker shades of orange-* mismatch with lighter shades, so in light mode we use amber text on top of orange bg.
|
||||
bodyColor: [
|
||||
'text-orange-950',
|
||||
'dark:text-orange-50',
|
||||
'[&_a]:text-orange-800',
|
||||
'[&_a:hover]:text-orange-900',
|
||||
'dark:[&_a]:text-orange-400',
|
||||
'dark:[&_a:hover]:text-orange-300',
|
||||
'[&_.can-override-bg]:bg-orange-500/3',
|
||||
'[&_.can-override-text]:text-orange-800',
|
||||
'dark:[&_.can-override-text]:text-orange-400',
|
||||
'decoration-orange-800/6',
|
||||
'dark:decoration-orange-400/6',
|
||||
iconColor: 'text-warning-subtle contrast-more:text-warning',
|
||||
header: 'bg-warning-active',
|
||||
body: [
|
||||
'text-neutral-strong',
|
||||
'[&_a]:text-warning',
|
||||
'[&_a:hover]:text-warning-strong',
|
||||
'[&_.can-override-bg]:bg-warning-active',
|
||||
'[&_.can-override-text]:text-warning-strong',
|
||||
'decoration-warning/6',
|
||||
],
|
||||
style: ['bg-orange-500/2', 'border-orange-500/4'],
|
||||
container: 'bg-warning border-warning',
|
||||
containerWithHeader: 'border-warning-solid bg-warning-subtle',
|
||||
},
|
||||
danger: {
|
||||
icon: 'triangle-exclamation',
|
||||
iconColor: ['text-red-500', 'dark:text-red-400'],
|
||||
bodyColor: [
|
||||
'text-red-950',
|
||||
'dark:text-red-50',
|
||||
'[&_a]:text-red-800',
|
||||
'[&_a:hover]:text-red-900',
|
||||
'dark:[&_a]:text-red-400',
|
||||
'dark:[&_a:hover]:text-red-300',
|
||||
'[&_.can-override-bg]:bg-red-500/3',
|
||||
'[&_.can-override-text]:text-red-400',
|
||||
'decoration-red-800/6',
|
||||
'dark:decoration-red-400/6',
|
||||
iconColor: 'text-danger-subtle contrast-more:text-danger',
|
||||
header: 'bg-danger-active',
|
||||
body: [
|
||||
'text-neutral-strong',
|
||||
'[&_a]:text-danger',
|
||||
'[&_a:hover]:text-danger-strong',
|
||||
'[&_.can-override-bg]:bg-danger-active',
|
||||
'[&_.can-override-text]:text-danger-strong',
|
||||
'decoration-danger/6',
|
||||
],
|
||||
style: ['bg-red-500/2', 'border-red-500/4'],
|
||||
container: 'bg-danger border-danger',
|
||||
containerWithHeader: 'border-danger-solid bg-danger-subtle',
|
||||
},
|
||||
success: {
|
||||
icon: 'circle-check',
|
||||
iconColor: ['text-green-500', 'dark:text-green-400'],
|
||||
bodyColor: [
|
||||
'text-green-950',
|
||||
'dark:text-green-50',
|
||||
'[&_a]:text-green-800',
|
||||
'[&_a:hover]:text-green-900',
|
||||
'dark:[&_a]:text-green-400',
|
||||
'dark:[&_a:hover]:text-green-300',
|
||||
'[&_.can-override-bg]:bg-green-500/3',
|
||||
'[&_.can-override-text]:text-green-800',
|
||||
'dark:[&_.can-override-text]:text-green-400',
|
||||
'decoration-green-800/6',
|
||||
'dark:decoration-green-400/6',
|
||||
iconColor: 'text-success-subtle contrast-more:text-success',
|
||||
header: 'bg-success-active',
|
||||
body: [
|
||||
'text-neutral-strong',
|
||||
'[&_a]:text-success',
|
||||
'[&_a:hover]:text-success-strong',
|
||||
'[&_.can-override-bg]:bg-success-active',
|
||||
'[&_.can-override-text]:text-success-strong',
|
||||
'decoration-success/6',
|
||||
],
|
||||
style: ['bg-green-500/2', 'border-green-500/4'],
|
||||
container: 'bg-success border-success',
|
||||
containerWithHeader: 'border-success-solid bg-success-subtle',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -14,6 +14,10 @@ import {
|
||||
colorScale,
|
||||
type ColorScaleOptions,
|
||||
DEFAULT_TINT_COLOR,
|
||||
DEFAULT_HINT_INFO_COLOR,
|
||||
DEFAULT_HINT_SUCCESS_COLOR,
|
||||
DEFAULT_HINT_DANGER_COLOR,
|
||||
DEFAULT_HINT_WARNING_COLOR,
|
||||
hexToRgb,
|
||||
} from '@gitbook/colors';
|
||||
import { IconsProvider, IconStyle } from '@gitbook/icons';
|
||||
@@ -42,6 +46,7 @@ export async function CustomizationRootLayout(props: {
|
||||
const tintColor = getTintColor(customization);
|
||||
const mixColor = getTintMixColor(customization.styling.primaryColor, tintColor);
|
||||
const sidebarStyles = getSidebarStyles(customization);
|
||||
const { infoColor, successColor, warningColor, dangerColor } = getSemanticColors(customization);
|
||||
|
||||
return (
|
||||
<html
|
||||
@@ -85,6 +90,11 @@ export async function CustomizationRootLayout(props: {
|
||||
)
|
||||
};
|
||||
--header-link: ${hexToRgb(customization.header.linkColor?.light ?? colorContrast(tintColor?.light ?? customization.styling.primaryColor.light))};
|
||||
|
||||
${generateColorVariable('info', infoColor.light)}
|
||||
${generateColorVariable('warning', warningColor.light)}
|
||||
${generateColorVariable('danger', dangerColor.light)}
|
||||
${generateColorVariable('success', successColor.light)}
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -94,6 +104,11 @@ export async function CustomizationRootLayout(props: {
|
||||
|
||||
--header-background: ${hexToRgb(customization.header.backgroundColor?.dark ?? tintColor?.dark ?? customization.styling.primaryColor.dark)};
|
||||
--header-link: ${hexToRgb(customization.header.linkColor?.dark ?? colorContrast(tintColor?.dark ?? customization.styling.primaryColor.dark))};
|
||||
|
||||
${generateColorVariable('info', infoColor.dark, { darkMode: true })}
|
||||
${generateColorVariable('warning', warningColor.dark, { darkMode: true })}
|
||||
${generateColorVariable('danger', dangerColor.dark, { darkMode: true })}
|
||||
${generateColorVariable('success', successColor.dark, { darkMode: true })}
|
||||
}
|
||||
`}</style>
|
||||
</head>
|
||||
@@ -198,6 +213,45 @@ function getSidebarStyles(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the semnatic color customization settings.
|
||||
* If it is a space customization, it will return the default styles.
|
||||
*/
|
||||
function getSemanticColors(
|
||||
customization: CustomizationSettings | SiteCustomizationSettings,
|
||||
): Pick<
|
||||
SiteCustomizationSettings['styling'],
|
||||
'infoColor' | 'successColor' | 'warningColor' | 'dangerColor'
|
||||
> {
|
||||
if ('infoColor' in customization.styling) {
|
||||
return {
|
||||
infoColor: customization.styling.infoColor,
|
||||
successColor: customization.styling.successColor,
|
||||
warningColor: customization.styling.warningColor,
|
||||
dangerColor: customization.styling.dangerColor,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
infoColor: {
|
||||
light: DEFAULT_HINT_INFO_COLOR,
|
||||
dark: DEFAULT_HINT_INFO_COLOR,
|
||||
},
|
||||
successColor: {
|
||||
light: DEFAULT_HINT_SUCCESS_COLOR,
|
||||
dark: DEFAULT_HINT_SUCCESS_COLOR,
|
||||
},
|
||||
warningColor: {
|
||||
light: DEFAULT_HINT_WARNING_COLOR,
|
||||
dark: DEFAULT_HINT_WARNING_COLOR,
|
||||
},
|
||||
dangerColor: {
|
||||
light: DEFAULT_HINT_DANGER_COLOR,
|
||||
dark: DEFAULT_HINT_DANGER_COLOR,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
type ColorInput = string;
|
||||
function generateColorVariable(
|
||||
name: string,
|
||||
|
||||
@@ -208,42 +208,6 @@ export const getUserById = cache({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the latest version of an OpenAPI spec by its slug.
|
||||
*/
|
||||
export const getLatestOpenAPISpecVersion = cache({
|
||||
name: 'api.getLatestOpenApiSpecVersion',
|
||||
tag: (organization, openAPISpec) =>
|
||||
getAPICacheTag({
|
||||
tag: 'openapi',
|
||||
organization,
|
||||
openAPISpec,
|
||||
}),
|
||||
get: async (organizationId: string, slug: string, options: CacheFunctionOptions) => {
|
||||
try {
|
||||
const apiCtx = await api();
|
||||
const response = await apiCtx.client.orgs.getLatestOpenApiSpecVersion(
|
||||
organizationId,
|
||||
slug,
|
||||
{
|
||||
...noCacheFetchOptions,
|
||||
signal: options.signal,
|
||||
},
|
||||
);
|
||||
return cacheResponse(response, { revalidateBefore: 60 * 60 });
|
||||
} catch (error) {
|
||||
if (checkHasErrorCode(error, 404)) {
|
||||
return {
|
||||
revalidateBefore: 5,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the latest version of an OpenAPI spec by its slug.
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
SpaceContentPointer,
|
||||
getCollection,
|
||||
getDocument,
|
||||
getLatestOpenAPISpecVersion,
|
||||
getLatestOpenAPISpecVersionContent,
|
||||
getPageDocument,
|
||||
getPublishedContentSite,
|
||||
@@ -282,19 +281,19 @@ export async function resolveContentRef(
|
||||
return null;
|
||||
}
|
||||
const { organizationId } = siteContext;
|
||||
const [openAPISpecVersion, openAPISpecVersionContent] = await Promise.all([
|
||||
getLatestOpenAPISpecVersion(organizationId, contentRef.spec),
|
||||
getLatestOpenAPISpecVersionContent(organizationId, contentRef.spec),
|
||||
]);
|
||||
const openAPISpecVersionContent = await getLatestOpenAPISpecVersionContent(
|
||||
organizationId,
|
||||
contentRef.spec,
|
||||
);
|
||||
|
||||
if (!openAPISpecVersion || !openAPISpecVersionContent) {
|
||||
if (!openAPISpecVersionContent) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
href: openAPISpecVersion.url,
|
||||
href: openAPISpecVersionContent.url,
|
||||
text: contentRef.spec,
|
||||
active: false,
|
||||
openAPIFilesystem: openAPISpecVersionContent as Filesystem,
|
||||
openAPIFilesystem: openAPISpecVersionContent.filesystem as Filesystem,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import { ColorCategory, hexToRgb, scale, shadesOfColor } from '@gitbook/colors';
|
||||
export const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
|
||||
export const opacities = [0, 4, 8, 12, 16, 24, 40, 64, 72, 88, 96, 100];
|
||||
|
||||
export const semanticColors = ['info', 'warning', 'danger', 'success'];
|
||||
|
||||
/**
|
||||
* Generate a Tailwind color shades from a variable.
|
||||
*/
|
||||
@@ -100,6 +102,18 @@ const config: Config = {
|
||||
|
||||
'header-background': 'rgb(var(--header-background))',
|
||||
'header-link': 'rgb(var(--header-link))',
|
||||
|
||||
// Add each semantic color
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [color, generateVarShades(color)]),
|
||||
),
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [
|
||||
`contrast-${color}`,
|
||||
generateVarShades(`contrast-${color}`),
|
||||
]),
|
||||
),
|
||||
|
||||
yellow: generateShades('#f4e28d'),
|
||||
teal: generateShades('#3f89a1'),
|
||||
pomegranate: generateShades('#f25b3a'),
|
||||
@@ -127,6 +141,17 @@ const config: Config = {
|
||||
ColorCategory.components,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
// Semantic colors
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [
|
||||
color,
|
||||
generateVarShades(color, [
|
||||
ColorCategory.backgrounds,
|
||||
ColorCategory.components,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
]),
|
||||
),
|
||||
},
|
||||
gradientColorStops: {
|
||||
primary: generateVarShades('primary', [
|
||||
@@ -144,26 +169,71 @@ const config: Config = {
|
||||
ColorCategory.components,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
// Semantic colors
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [
|
||||
color,
|
||||
generateVarShades(color, [
|
||||
ColorCategory.backgrounds,
|
||||
ColorCategory.components,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
]),
|
||||
),
|
||||
},
|
||||
borderColor: {
|
||||
primary: generateVarShades('primary', [ColorCategory.borders]),
|
||||
tint: generateVarShades('tint', [ColorCategory.borders]),
|
||||
neutral: generateVarShades('neutral', [ColorCategory.borders]),
|
||||
primary: generateVarShades('primary', [
|
||||
ColorCategory.borders,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
tint: generateVarShades('tint', [ColorCategory.borders, ColorCategory.accents]),
|
||||
neutral: generateVarShades('neutral', [
|
||||
ColorCategory.borders,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
// Semantic colors
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [
|
||||
color,
|
||||
generateVarShades(color, [ColorCategory.borders, ColorCategory.accents]),
|
||||
]),
|
||||
),
|
||||
},
|
||||
ringColor: {
|
||||
primary: generateVarShades('primary', [ColorCategory.borders]),
|
||||
tint: generateVarShades('tint', [ColorCategory.borders]),
|
||||
neutral: generateVarShades('neutral', [ColorCategory.borders]),
|
||||
// Semantic colors
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [
|
||||
color,
|
||||
generateVarShades(color, [ColorCategory.borders]),
|
||||
]),
|
||||
),
|
||||
},
|
||||
outlineColor: {
|
||||
primary: generateVarShades('primary', [ColorCategory.borders]),
|
||||
tint: generateVarShades('tint', [ColorCategory.borders]),
|
||||
neutral: generateVarShades('neutral', [ColorCategory.borders]),
|
||||
// Semantic colors
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [
|
||||
color,
|
||||
generateVarShades(color, [ColorCategory.borders]),
|
||||
]),
|
||||
),
|
||||
},
|
||||
boxShadowColor: {
|
||||
primary: generateVarShades('primary', [ColorCategory.borders]),
|
||||
tint: generateVarShades('tint', [ColorCategory.borders]),
|
||||
neutral: generateVarShades('neutral', [ColorCategory.borders]),
|
||||
// Semantic colors
|
||||
...Object.fromEntries(
|
||||
semanticColors.map((color) => [
|
||||
color,
|
||||
generateVarShades(color, [ColorCategory.borders]),
|
||||
]),
|
||||
),
|
||||
},
|
||||
textColor: {
|
||||
primary: generateVarShades('primary', [ColorCategory.text]),
|
||||
@@ -181,6 +251,18 @@ const config: Config = {
|
||||
ColorCategory.backgrounds,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
...Object.fromEntries(
|
||||
semanticColors.flatMap((color) => [
|
||||
[color, generateVarShades(color, [ColorCategory.text])],
|
||||
[
|
||||
`contrast-${color}`,
|
||||
generateVarShades(`contrast-${color}`, [
|
||||
ColorCategory.backgrounds,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
],
|
||||
]),
|
||||
),
|
||||
},
|
||||
textDecorationColor: {
|
||||
primary: generateVarShades('primary', [ColorCategory.text]),
|
||||
@@ -198,6 +280,18 @@ const config: Config = {
|
||||
ColorCategory.backgrounds,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
...Object.fromEntries(
|
||||
semanticColors.flatMap((color) => [
|
||||
[color, generateVarShades(color, [ColorCategory.text])],
|
||||
[
|
||||
`contrast-${color}`,
|
||||
generateVarShades(`contrast-${color}`, [
|
||||
ColorCategory.backgrounds,
|
||||
ColorCategory.accents,
|
||||
]),
|
||||
],
|
||||
]),
|
||||
),
|
||||
},
|
||||
animation: {
|
||||
present: 'present .5s ease-out both',
|
||||
|
||||
Reference in New Issue
Block a user