Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/modern-moons-judge.md
Original file line number Diff line number Diff line change
@@ -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
12 changes: 6 additions & 6 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
},
"packages/colors": {
"name": "@gitbook/colors",
"version": "0.1.0",
"version": "0.2.0",
"devDependencies": {
"typescript": "^5.5.3",
},
Expand All @@ -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:*",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -4651,7 +4651,7 @@

"gaxios/https-proxy-agent": ["[email protected]", "", { "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": ["[email protected]", "", { "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=="],

Expand Down
6 changes: 5 additions & 1 deletion packages/gitbook/e2e/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/gitbook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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:*",
Expand Down
17 changes: 6 additions & 11 deletions packages/gitbook/src/components/DocumentView/Heading.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -24,6 +24,7 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
>
<div
className={tcls(
'hash',
'grid',
'grid-area-1-1',
'relative',
Expand All @@ -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',
Expand Down
182 changes: 103 additions & 79 deletions packages/gitbook/src/components/DocumentView/Hint.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -13,119 +13,143 @@ 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,
)}
className={tcls('size-[1.2em]', 'mt-0.5', firstLine.lineHeight)}
/>
<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',
</div>
{hasHeading ? (
<Block
style={tcls(
'text-[1em] *:mt-0 p-3 flip-heading-hash',
hasHeading ? hintStyle.header : null,
)}
style={['flex-1', 'space-y-4', '[&_.hint]:border', '[&_pre]:border']}
ancestorBlocks={[...ancestorBlocks, block]}
{...contextProps}
block={firstNode}
/>
</div>
) : 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>
);
}

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',
},
};
Loading
Loading