mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-10-03 12:10:34 +00:00
Add icons and color to hint
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"@geist-ui/icons": "^1.0.2",
|
||||
"@gitbook/api": "^0.11.1",
|
||||
"@readme/openapi-parser": "^2.5.0",
|
||||
"assert-never": "^1.2.1",
|
||||
"bun-types": "^1.0.7",
|
||||
"next": "13.5.6",
|
||||
"react": "^18",
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Tabs } from './Tabs';
|
||||
import { Expandable } from './Expandable';
|
||||
import { Table } from './Table';
|
||||
import { Swagger } from './Swagger';
|
||||
import { Embed } from './Embed';
|
||||
|
||||
export interface BlockProps<T> extends DocumentContextProps {
|
||||
block: T;
|
||||
@@ -49,6 +50,8 @@ export function Block<T>(props: BlockProps<T>) {
|
||||
return <Table {...props} {...contextProps} />;
|
||||
case 'swagger':
|
||||
return <Swagger {...props} {...contextProps} />;
|
||||
case 'embed':
|
||||
return <Embed {...props} {...contextProps} />;
|
||||
default:
|
||||
return <div className={tcls(style)}>Unsupported block {block.type}</div>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import { BlockProps } from './Block';
|
||||
import { Blocks } from './Blocks';
|
||||
import { DocumentBlockEmbed } from '@gitbook/api';
|
||||
import { api } from '@/lib/api';
|
||||
|
||||
export async function Embed(props: BlockProps<DocumentBlockEmbed>) {
|
||||
const { block, style, ...contextProps } = props;
|
||||
|
||||
const { data: embed } = await api().urls.getEmbedByUrl({ url: block.data.url });
|
||||
|
||||
// TODO caption
|
||||
|
||||
if (embed.type === 'rich') {
|
||||
return (
|
||||
<div
|
||||
className={tcls(style)}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: embed.html,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className={tcls(style)}>
|
||||
<div>{embed.title}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,18 @@ import IconHash from '@geist-ui/icons/hash';
|
||||
import { BlockProps } from './Block';
|
||||
import { Inlines } from './Inlines';
|
||||
import { DocumentBlockHeading } from '@gitbook/api';
|
||||
import { getBlockTextStyle } from './spacing';
|
||||
|
||||
export function Heading(props: BlockProps<DocumentBlockHeading>) {
|
||||
const { block, style, ...contextProps } = props;
|
||||
|
||||
const headingStyle = STYLES[block.type];
|
||||
const textStyle = getBlockTextStyle(block);
|
||||
const Tag = TAGS[block.type];
|
||||
|
||||
const id = block.meta?.id ?? '';
|
||||
|
||||
return (
|
||||
<headingStyle.tag
|
||||
id={id}
|
||||
className={tcls(headingStyle.className, 'group', 'relative', style)}
|
||||
>
|
||||
<Tag id={id} className={tcls(textStyle.textSize, 'group', 'relative', style)}>
|
||||
<div
|
||||
className={tcls(
|
||||
'absolute',
|
||||
@@ -27,7 +26,7 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
|
||||
'group-hover:opacity-100',
|
||||
'group-focus:opacity-100',
|
||||
'lg:flex',
|
||||
headingStyle.lineHeight,
|
||||
textStyle.lineHeight,
|
||||
)}
|
||||
>
|
||||
<a
|
||||
@@ -58,24 +57,13 @@ export function Heading(props: BlockProps<DocumentBlockHeading>) {
|
||||
</div>
|
||||
|
||||
<Inlines {...contextProps} nodes={block.nodes} />
|
||||
</headingStyle.tag>
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
const STYLES = {
|
||||
'heading-1': {
|
||||
tag: 'h2',
|
||||
lineHeight: 'h-9',
|
||||
className: ['text-3xl', 'font-semibold'],
|
||||
},
|
||||
'heading-2': {
|
||||
tag: 'h3',
|
||||
lineHeight: 'h-8',
|
||||
className: ['text-2xl', 'font-semibold'],
|
||||
},
|
||||
'heading-3': {
|
||||
tag: 'h4',
|
||||
lineHeight: 'h-6',
|
||||
className: ['text-base', 'font-semibold'],
|
||||
},
|
||||
const TAGS: { [type in DocumentBlockHeading['type']]: string } = {
|
||||
// The h1 is reserved for the page title
|
||||
'heading-1': 'h2',
|
||||
'heading-2': 'h3',
|
||||
'heading-3': 'h4',
|
||||
};
|
||||
|
||||
@@ -1,17 +1,75 @@
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import { ClassValue, tcls } from '@/lib/tailwind';
|
||||
import { BlockProps } from './Block';
|
||||
import { Blocks } from './Blocks';
|
||||
import { DocumentBlockHint } from '@gitbook/api';
|
||||
import IconInfo from '@geist-ui/icons/info';
|
||||
import IconAlertTriangle from '@geist-ui/icons/alertTriangle';
|
||||
import IconAlertCircle from '@geist-ui/icons/alertCircle';
|
||||
import IconCheckInCircle from '@geist-ui/icons/checkInCircle';
|
||||
import { getBlockTextStyle } from './spacing';
|
||||
|
||||
export function Hint(props: BlockProps<DocumentBlockHint>) {
|
||||
const { block, style, ...contextProps } = props;
|
||||
const hintStyle = HINT_STYLES[block.data.style];
|
||||
const firstLine = getBlockTextStyle(block.nodes[0]);
|
||||
|
||||
return (
|
||||
<div className={tcls('flex', 'flex-row', 'px-4', 'py-4', 'bg-slate-100', 'rounded', style)}>
|
||||
<div className={tcls('w-7')}>
|
||||
<div /> {/* TODO icon */}
|
||||
<div
|
||||
className={tcls(
|
||||
'flex',
|
||||
'flex-row',
|
||||
'px-4',
|
||||
'py-4',
|
||||
'bg-slate-50',
|
||||
'dark:bg-slate-900',
|
||||
'rounded',
|
||||
'border-l-4',
|
||||
hintStyle.style,
|
||||
style,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={tcls(
|
||||
'flex',
|
||||
'items-center',
|
||||
'justify-center',
|
||||
'pr-3',
|
||||
firstLine.lineHeight,
|
||||
hintStyle.iconStyle,
|
||||
)}
|
||||
>
|
||||
<hintStyle.icon className={tcls('w-5', 'h-5')} />
|
||||
</div>
|
||||
<Blocks {...contextProps} nodes={block.nodes} style={['flex-1']} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const HINT_STYLES: {
|
||||
[style in DocumentBlockHint['data']['style']]: {
|
||||
icon: React.ComponentType<{ className?: string }>;
|
||||
iconStyle: ClassValue;
|
||||
style: ClassValue;
|
||||
};
|
||||
} = {
|
||||
info: {
|
||||
icon: IconInfo,
|
||||
iconStyle: ['text-blue-500'],
|
||||
style: ['border-blue-500'],
|
||||
},
|
||||
warning: {
|
||||
icon: IconAlertCircle,
|
||||
iconStyle: ['text-orange-500'],
|
||||
style: ['border-orange-500'],
|
||||
},
|
||||
danger: {
|
||||
icon: IconAlertTriangle,
|
||||
iconStyle: ['text-red-500'],
|
||||
style: ['border-red-500'],
|
||||
},
|
||||
success: {
|
||||
icon: IconCheckInCircle,
|
||||
iconStyle: ['text-green-500'],
|
||||
style: ['border-green-500'],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { ClassValue } from '@/lib/tailwind';
|
||||
import { DocumentBlockListItem, DocumentBlocksEssentials } from '@gitbook/api';
|
||||
import { assertNever } from 'assert-never';
|
||||
|
||||
/**
|
||||
* Get the line height of a block
|
||||
*/
|
||||
export function getBlockTextStyle(block: DocumentBlocksEssentials | DocumentBlockListItem): {
|
||||
/** Tailwind class for the text size */
|
||||
textSize: ClassValue;
|
||||
/** Tailwind class for the height (h-*) */
|
||||
lineHeight: ClassValue;
|
||||
} {
|
||||
switch (block.type) {
|
||||
case 'paragraph':
|
||||
return {
|
||||
textSize: ['text-base'],
|
||||
lineHeight: 'h-6',
|
||||
};
|
||||
case 'heading-1':
|
||||
return {
|
||||
textSize: ['text-3xl', 'font-semibold'],
|
||||
lineHeight: 'h-9',
|
||||
};
|
||||
case 'heading-2':
|
||||
return {
|
||||
textSize: ['text-2xl', 'font-semibold'],
|
||||
lineHeight: 'h-8',
|
||||
};
|
||||
case 'heading-3':
|
||||
return {
|
||||
textSize: ['text-base', 'font-semibold'],
|
||||
lineHeight: 'h-6',
|
||||
};
|
||||
case 'divider':
|
||||
return {
|
||||
textSize: [],
|
||||
lineHeight: 'h-6',
|
||||
};
|
||||
case 'list-ordered':
|
||||
case 'list-tasks':
|
||||
case 'list-unordered':
|
||||
return getBlockTextStyle(block.nodes[0]);
|
||||
case 'list-item':
|
||||
return getBlockTextStyle(block.nodes[0]);
|
||||
default:
|
||||
assertNever(block);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user