diff --git a/README.md b/README.md index 6b7d51ee7..1fb611c64 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,39 @@ # GitBook -## TODOs +Next.js application to render GitBook published content. -- OG cover image - - [ ] Redirect to the customization one if any -- Favicon - - [ ] Redirect to the customization one if any - - [ ] Render one -- Blocks - - [ ] Code block syntax highlighting -- Theme - - [ ] Toggler -- Page feedback -- Edit on GitHub -- Header links +## Development + +#### Installation + +Clone the repository and use [Bun](https://bun.sh/) to install dependencies and run the local development server. + +``` +bun install +``` + +#### Configuration + +To develop and test a GitBook space locally, first create a [GitBook API token](https://app.gitbook.com/account/developer) and put it in a `.env.local` file: + +``` +GITBOOK_TOKEN=gb_api_abc +``` + +#### Start the local server + +Run the Next.js development server. + +``` +bun dev +``` + +Then open the space in your web browser: `http://localhost:3000//`. + +#### Other commands + +- `bun format`: format the code +- `bun lint`: lint the code ## Differences diff --git a/bun.lockb b/bun.lockb index 04d173326..63783f752 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 475f738fd..12481709d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@geist-ui/icons": "^1.0.2", "@gitbook/api": "^0.11.1", "@readme/openapi-parser": "^2.5.0", + "ajv": "^8.12.0", "assert-never": "^1.2.1", "bun-types": "^1.0.7", "katex": "^0.16.9", diff --git a/src/components/DocumentView/Block.tsx b/src/components/DocumentView/Block.tsx index e0b965532..3d7488ec9 100644 --- a/src/components/DocumentView/Block.tsx +++ b/src/components/DocumentView/Block.tsx @@ -5,7 +5,6 @@ import { ListOrdered } from './ListOrdered'; import { ListUnordered } from './ListUnordered'; import { ListItem } from './ListItem'; import { CodeBlock } from './CodeBlock'; -import { tcls } from '@/lib/tailwind'; import { Hint } from './Hint'; import { DocumentContextProps } from './DocumentView'; import { Images } from './Images'; @@ -17,6 +16,8 @@ import { Embed } from './Embed'; import { Quote } from './Quote'; import { DocumentBlockCode, + DocumentBlockDivider, + DocumentBlockDrawing, DocumentBlockEmbed, DocumentBlockExpandable, DocumentBlockFile, @@ -33,10 +34,15 @@ import { DocumentBlockSwagger, DocumentBlockTable, DocumentBlockTabs, + DocumentBlockTabsItem, DocumentBlockTaskListItem, } from '@gitbook/api'; import { BlockMath } from './Math'; import { File } from './File'; +import { ListTasks } from './ListTasks'; +import { Divider } from './Divider'; +import assertNever from 'assert-never'; +import { Drawing } from './Drawing'; export type SupportedBlock = | DocumentBlockParagraph @@ -56,10 +62,15 @@ export type SupportedBlock = | DocumentBlockEmbed | DocumentBlockQuote | DocumentBlockMath - | DocumentBlockFile; + | DocumentBlockFile + | DocumentBlockDivider + | DocumentBlockDrawing; + +export type AncestorBlock = SupportedBlock | DocumentBlockTabsItem; export interface BlockProps extends DocumentContextProps { block: Block; + ancestorBlocks: AncestorBlock[]; style?: ClassValue; } @@ -77,6 +88,8 @@ export function Block(props: BlockProps) { return ; case 'list-unordered': return ; + case 'list-tasks': + return ; case 'list-item': return ; case 'code': @@ -101,7 +114,11 @@ export function Block(props: BlockProps) { return ; case 'file': return ; + case 'divider': + return ; + case 'drawing': + return ; default: - return
Unsupported block {block.type}
; + assertNever(block); } } diff --git a/src/components/DocumentView/Blocks.tsx b/src/components/DocumentView/Blocks.tsx index a37457e5b..de9064908 100644 --- a/src/components/DocumentView/Blocks.tsx +++ b/src/components/DocumentView/Blocks.tsx @@ -1,12 +1,15 @@ -import { Block } from './Block'; +import { AncestorBlock, Block, SupportedBlock } from './Block'; import { DocumentContextProps } from './DocumentView'; import { tcls, ClassValue } from '@/lib/tailwind'; -export function Blocks( +export function Blocks( props: DocumentContextProps & { /** Blocks to render */ nodes: T[]; + /** Ancestors of the blocks */ + ancestorBlocks: AncestorBlock[]; + /** HTML tag to use */ tag?: Tag; diff --git a/src/components/DocumentView/Divider.tsx b/src/components/DocumentView/Divider.tsx new file mode 100644 index 000000000..94e85d430 --- /dev/null +++ b/src/components/DocumentView/Divider.tsx @@ -0,0 +1,9 @@ +import { DocumentBlockDivider } from '@gitbook/api'; +import { BlockProps } from './Block'; +import { tcls } from '@/lib/tailwind'; + +export function Divider(props: BlockProps) { + const { style } = props; + + return
; +} diff --git a/src/components/DocumentView/DocumentView.tsx b/src/components/DocumentView/DocumentView.tsx index 835f24dd8..334c30372 100644 --- a/src/components/DocumentView/DocumentView.tsx +++ b/src/components/DocumentView/DocumentView.tsx @@ -18,5 +18,13 @@ export function DocumentView( ) { const { document, style, ...context } = props; - return ; + return ( + + ); } diff --git a/src/components/DocumentView/Drawing.tsx b/src/components/DocumentView/Drawing.tsx new file mode 100644 index 000000000..a77815e30 --- /dev/null +++ b/src/components/DocumentView/Drawing.tsx @@ -0,0 +1,9 @@ +import { DocumentBlockDrawing } from '@gitbook/api'; +import { BlockProps } from './Block'; +import { tcls } from '@/lib/tailwind'; + +export function Drawing(props: BlockProps) { + const { style } = props; + + return
TODO
; +} diff --git a/src/components/DocumentView/Expandable/Expandable.tsx b/src/components/DocumentView/Expandable/Expandable.tsx index d7a67b752..29e4dff55 100644 --- a/src/components/DocumentView/Expandable/Expandable.tsx +++ b/src/components/DocumentView/Expandable/Expandable.tsx @@ -6,7 +6,7 @@ import { DocumentBlockExpandable } from '@gitbook/api'; import { Inlines } from '../Inlines'; export function Expandable(props: BlockProps) { - const { block, style, context } = props; + const { block, style, ancestorBlocks, context } = props; const title = getNodeFragmentByType(block, 'expandable-title'); const body = getNodeFragmentByType(block, 'expandable-body'); @@ -16,7 +16,12 @@ export function Expandable(props: BlockProps) { - + ); } diff --git a/src/components/DocumentView/Hint.tsx b/src/components/DocumentView/Hint.tsx index c08001fcb..80d9b18ee 100644 --- a/src/components/DocumentView/Hint.tsx +++ b/src/components/DocumentView/Hint.tsx @@ -9,7 +9,7 @@ import IconCheckInCircle from '@geist-ui/icons/checkInCircle'; import { getBlockTextStyle } from './spacing'; export function Hint(props: BlockProps) { - const { block, style, ...contextProps } = props; + const { block, style, ancestorBlocks, ...contextProps } = props; const hintStyle = HINT_STYLES[block.data.style]; const firstLine = getBlockTextStyle(block.nodes[0]); @@ -40,7 +40,12 @@ export function Hint(props: BlockProps) { > - + ); } diff --git a/src/components/DocumentView/ListItem.tsx b/src/components/DocumentView/ListItem.tsx index 5659b39ff..4ce8e8f9f 100644 --- a/src/components/DocumentView/ListItem.tsx +++ b/src/components/DocumentView/ListItem.tsx @@ -1,18 +1,33 @@ import { tcls } from '@/lib/tailwind'; import { BlockProps } from './Block'; import { Blocks } from './Blocks'; -import { DocumentBlockListItem } from '@gitbook/api'; +import { DocumentBlockListItem, DocumentBlockTaskListItem } from '@gitbook/api'; -export function ListItem(props: BlockProps) { - const { block, ...contextProps } = props; +export function ListItem(props: BlockProps) { + const { block, ancestorBlocks, ...contextProps } = props; + + const isTaskList = ancestorBlocks[ancestorBlocks.length - 1]?.type === 'list-tasks'; return (
  • - + {isTaskList ? ( +
    + + +
    + ) : ( + + )}
  • ); } diff --git a/src/components/DocumentView/ListOrdered.tsx b/src/components/DocumentView/ListOrdered.tsx index c8690402b..8eb5254b6 100644 --- a/src/components/DocumentView/ListOrdered.tsx +++ b/src/components/DocumentView/ListOrdered.tsx @@ -3,13 +3,14 @@ import { BlockProps } from './Block'; import { Blocks } from './Blocks'; export function ListOrdered(props: BlockProps) { - const { block, style, ...contextProps } = props; + const { block, style, ancestorBlocks, ...contextProps } = props; return ( ); diff --git a/src/components/DocumentView/ListTasks.tsx b/src/components/DocumentView/ListTasks.tsx new file mode 100644 index 000000000..5cfe2a36d --- /dev/null +++ b/src/components/DocumentView/ListTasks.tsx @@ -0,0 +1,17 @@ +import { DocumentBlockListTasks, DocumentBlockListUnordered } from '@gitbook/api'; +import { BlockProps } from './Block'; +import { Blocks } from './Blocks'; + +export function ListTasks(props: BlockProps) { + const { block, style, ancestorBlocks, ...contextProps } = props; + + return ( + + ); +} diff --git a/src/components/DocumentView/ListUnordered.tsx b/src/components/DocumentView/ListUnordered.tsx index 711bcb8ff..5d60cac9a 100644 --- a/src/components/DocumentView/ListUnordered.tsx +++ b/src/components/DocumentView/ListUnordered.tsx @@ -3,13 +3,14 @@ import { BlockProps } from './Block'; import { Blocks } from './Blocks'; export function ListUnordered(props: BlockProps) { - const { block, style, ...contextProps } = props; + const { block, style, ancestorBlocks, ...contextProps } = props; return ( ); diff --git a/src/components/DocumentView/Quote.tsx b/src/components/DocumentView/Quote.tsx index b7e6130c3..7e0e7f91f 100644 --- a/src/components/DocumentView/Quote.tsx +++ b/src/components/DocumentView/Quote.tsx @@ -3,13 +3,14 @@ import { Blocks } from './Blocks'; import { DocumentBlockQuote } from '@gitbook/api'; export function Quote(props: BlockProps) { - const { block, style, ...contextProps } = props; + const { block, style, ancestorBlocks, ...contextProps } = props; return ( ); diff --git a/src/components/DocumentView/Table/RecordColumnValue.tsx b/src/components/DocumentView/Table/RecordColumnValue.tsx index e3265867c..2deeacfff 100644 --- a/src/components/DocumentView/Table/RecordColumnValue.tsx +++ b/src/components/DocumentView/Table/RecordColumnValue.tsx @@ -34,6 +34,7 @@ export async function RecordColumnValue( return ( ) { - const { block, style, context } = props; + const { block, ancestorBlocks, style, context } = props; return ( ({ id: tab.key!, - title: tab.data.title, - children: , + title: tab.data.title ?? '', + children: ( + + ), }))} style={style} />