From 0b6910951dfdca1b0e5304a6d5449a1e75972e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Sun, 22 Oct 2023 23:48:31 +0200 Subject: [PATCH] Start --- .env.example | 6 + .eslintrc.json | 2 +- .prettierignore | 1 + .prettierrc.json | 5 + README.md | 36 ------ bun.lockb | Bin 140067 -> 166893 bytes next.config.js | 4 +- package.json | 56 +++++---- postcss.config.js | 10 +- public/next.svg | 1 - public/vercel.svg | 1 - src/app/[[...pathname]]/page.tsx | 30 +++++ src/app/favicon.ico | Bin 25931 -> 0 bytes src/app/globals.css | 21 ---- src/app/layout.tsx | 28 ++--- src/app/page.tsx | 113 ------------------ src/components/DocumentView/Block.tsx | 32 +++++ src/components/DocumentView/Blocks.tsx | 41 +++++++ src/components/DocumentView/DocumentView.tsx | 11 ++ src/components/DocumentView/Heading.tsx | 30 +++++ src/components/DocumentView/Inline.tsx | 14 +++ src/components/DocumentView/Inlines.tsx | 19 +++ src/components/DocumentView/ListItem.tsx | 13 ++ src/components/DocumentView/ListOrdered.tsx | 8 ++ src/components/DocumentView/ListUnordered.tsx | 8 ++ src/components/DocumentView/Paragraph.tsx | 13 ++ src/components/DocumentView/Text.tsx | 14 +++ src/components/DocumentView/index.ts | 1 + src/components/Header/Header.tsx | 27 +++++ src/components/Header/index.ts | 1 + src/components/PageBody/PageBody.tsx | 14 +++ src/components/PageBody/PageDocument.tsx | 20 ++++ src/components/PageBody/PageHeader.tsx | 15 +++ src/components/PageBody/index.ts | 1 + src/components/SpaceContent/SpaceContent.tsx | 95 +++++++++++++++ src/components/SpaceContent/index.ts | 1 + .../TableOfContents/PageDocumentItem.tsx | 36 ++++++ .../TableOfContents/PageGroupItem.tsx | 21 ++++ src/components/TableOfContents/PagesList.tsx | 24 ++++ .../TableOfContents/TableOfContents.tsx | 22 ++++ src/components/TableOfContents/Trademark.tsx | 28 +++++ src/components/TableOfContents/index.ts | 1 + src/lib/api.ts | 19 +++ src/lib/links.ts | 13 ++ src/middleware.ts | 25 ++++ tailwind.config.ts | 33 +++-- tsconfig.json | 50 ++++---- 47 files changed, 698 insertions(+), 266 deletions(-) create mode 100644 .env.example create mode 100644 .prettierignore create mode 100644 .prettierrc.json delete mode 100644 public/next.svg delete mode 100644 public/vercel.svg create mode 100644 src/app/[[...pathname]]/page.tsx delete mode 100644 src/app/favicon.ico delete mode 100644 src/app/page.tsx create mode 100644 src/components/DocumentView/Block.tsx create mode 100644 src/components/DocumentView/Blocks.tsx create mode 100644 src/components/DocumentView/DocumentView.tsx create mode 100644 src/components/DocumentView/Heading.tsx create mode 100644 src/components/DocumentView/Inline.tsx create mode 100644 src/components/DocumentView/Inlines.tsx create mode 100644 src/components/DocumentView/ListItem.tsx create mode 100644 src/components/DocumentView/ListOrdered.tsx create mode 100644 src/components/DocumentView/ListUnordered.tsx create mode 100644 src/components/DocumentView/Paragraph.tsx create mode 100644 src/components/DocumentView/Text.tsx create mode 100644 src/components/DocumentView/index.ts create mode 100644 src/components/Header/Header.tsx create mode 100644 src/components/Header/index.ts create mode 100644 src/components/PageBody/PageBody.tsx create mode 100644 src/components/PageBody/PageDocument.tsx create mode 100644 src/components/PageBody/PageHeader.tsx create mode 100644 src/components/PageBody/index.ts create mode 100644 src/components/SpaceContent/SpaceContent.tsx create mode 100644 src/components/SpaceContent/index.ts create mode 100644 src/components/TableOfContents/PageDocumentItem.tsx create mode 100644 src/components/TableOfContents/PageGroupItem.tsx create mode 100644 src/components/TableOfContents/PagesList.tsx create mode 100644 src/components/TableOfContents/TableOfContents.tsx create mode 100644 src/components/TableOfContents/Trademark.tsx create mode 100644 src/components/TableOfContents/index.ts create mode 100644 src/lib/api.ts create mode 100644 src/lib/links.ts create mode 100644 src/middleware.ts diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..f6640d765 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +# Go to https://app.gitbook.com/account/developer and create a new token +# Copy the token and paste it in the .env file +# GITBOOK_TOKEN=your_token_here + +# Other options: +# GITBOOK_API_URL=https://api.gitbook.com diff --git a/.eslintrc.json b/.eslintrc.json index bffb357a7..1c2aa65d7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "next/core-web-vitals" + "extends": "next/core-web-vitals" } diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..a680367ef --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +.next diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..581887eed --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "printWidth": 100, + "singleQuote": true, + "tabWidth": 4 +} diff --git a/README.md b/README.md index c4033664f..e69de29bb 100644 --- a/README.md +++ b/README.md @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/bun.lockb b/bun.lockb index b4730dd56b4116d02cc5ad50b95454ca397c92b0..bad6bd4d16503be4128fd74fa11401f99f34e71a 100755 GIT binary patch delta 46039 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 diff --git a/next.config.js b/next.config.js index 767719fc4..658404ac6 100644 --- a/next.config.js +++ b/next.config.js @@ -1,4 +1,4 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {} +const nextConfig = {}; -module.exports = nextConfig +module.exports = nextConfig; diff --git a/package.json b/package.json index 258fe4591..e1eeb10eb 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,33 @@ { - "name": "gitbook", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "react": "^18", - "react-dom": "^18", - "next": "13.5.6" - }, - "devDependencies": { - "typescript": "^5", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "autoprefixer": "^10", - "postcss": "^8", - "tailwindcss": "^3", - "eslint": "^8", - "eslint-config-next": "13.5.6" - } + "name": "gitbook", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "format": "prettier ./ --ignore-unknown --write", + "format:check": "prettier ./ --ignore-unknown --list-different" + }, + "dependencies": { + "@gitbook/api": "^0.11.0", + "clsx": "^2.0.0", + "next": "13.5.6", + "react": "^18", + "react-dom": "^18", + "server-only": "^0.0.1" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "autoprefixer": "^10", + "eslint": "^8", + "eslint-config-next": "13.5.6", + "postcss": "^8", + "prettier": "^3.0.3", + "tailwindcss": "^3", + "typescript": "^5" + } } diff --git a/postcss.config.js b/postcss.config.js index 33ad091d2..67cdf1a55 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,6 @@ module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28c5..000000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index d2f842227..000000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/[[...pathname]]/page.tsx b/src/app/[[...pathname]]/page.tsx new file mode 100644 index 000000000..a48368ef7 --- /dev/null +++ b/src/app/[[...pathname]]/page.tsx @@ -0,0 +1,30 @@ +import { headers } from 'next/headers'; + +import { api } from '@/lib/api'; +import { SpaceContent } from '@/components/SpaceContent'; + +export default async function Page(props: { params: { pathname?: string[] } }) { + const { + params: { pathname }, + } = props; + + const headersList = headers(); + const spaceId = headersList.get('x-gitbook-space'); + + if (!spaceId) { + throw new Error('Missing space id'); + } + + const [{ data: space }, { data: revision }] = await Promise.all([ + api().spaces.getSpaceById(spaceId), + api().spaces.getCurrentRevision(spaceId), + ]); + + return ( + + ); +} diff --git a/src/app/favicon.ico b/src/app/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 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 LrJugUA?W`A8`#=m diff --git a/src/app/globals.css b/src/app/globals.css index fd81e8858..68cb03319 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2,26 +2,5 @@ @tailwind components; @tailwind utilities; -:root { - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; -} - -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - } -} - body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 40e027fbe..bc255000d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,22 +1,12 @@ -import type { Metadata } from 'next' -import { Inter } from 'next/font/google' -import './globals.css' +import { Inter } from 'next/font/google'; +import './globals.css'; -const inter = Inter({ subsets: ['latin'] }) +const inter = Inter({ subsets: ['latin'] }); -export const metadata: Metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -} - -export default function RootLayout({ - children, -}: { - children: React.ReactNode -}) { - return ( - - {children} - - ) +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx deleted file mode 100644 index e38c626e1..000000000 --- a/src/app/page.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import Image from 'next/image' - -export default function Home() { - return ( -
-
-

- Get started by editing  - src/app/page.tsx -

- -
- -
- Next.js Logo -
- - -
- ) -} diff --git a/src/components/DocumentView/Block.tsx b/src/components/DocumentView/Block.tsx new file mode 100644 index 000000000..4667f0afd --- /dev/null +++ b/src/components/DocumentView/Block.tsx @@ -0,0 +1,32 @@ +import { ClassValue } from 'clsx'; +import { Paragraph } from './Paragraph'; +import { Heading } from './Heading'; +import { ListOrdered } from './ListOrdered'; +import { ListUnordered } from './ListUnordered'; +import { ListItem } from './ListItem'; + +export interface BlockProps { + block: T; + style?: ClassValue; +} + +export function Block(props: BlockProps) { + const { block } = props; + + switch (block.type) { + case 'paragraph': + return ; + case 'heading-1': + case 'heading-2': + case 'heading-3': + return ; + case 'list-ordered': + return ; + case 'list-unordered': + return ; + case 'list-item': + return ; + default: + return
Unsupported block {block.type}
; + } +} diff --git a/src/components/DocumentView/Blocks.tsx b/src/components/DocumentView/Blocks.tsx new file mode 100644 index 000000000..765533631 --- /dev/null +++ b/src/components/DocumentView/Blocks.tsx @@ -0,0 +1,41 @@ +import clsx from 'clsx'; +import { ClassValue } from 'clsx'; +import { Block } from './Block'; + +export function Blocks(props: { + /** Blocks to render */ + nodes: T[]; + + /** HTML tag to use */ + tag?: string; + + /** Style passed to the wrapper */ + style?: ClassValue; + + /** Style passed to all blocks */ + blockStyle?: ClassValue; + + /** Style passed to the first block */ + firstBlockStyle?: ClassValue; + + /** Style passed to the last block */ + lastBlockStyle?: ClassValue; +}) { + const { nodes, tag: Tag = 'div', style, blockStyle, firstBlockStyle, lastBlockStyle } = props; + + return ( + + {nodes.map((node, index) => ( + + ))} + + ); +} diff --git a/src/components/DocumentView/DocumentView.tsx b/src/components/DocumentView/DocumentView.tsx new file mode 100644 index 000000000..b29481835 --- /dev/null +++ b/src/components/DocumentView/DocumentView.tsx @@ -0,0 +1,11 @@ +import clsx from 'clsx'; +import { Blocks } from './Blocks'; + +/** + * Render an entire document. + */ +export function DocumentView(props: { document: any }) { + const { document } = props; + + return ; +} diff --git a/src/components/DocumentView/Heading.tsx b/src/components/DocumentView/Heading.tsx new file mode 100644 index 000000000..f5cf0b589 --- /dev/null +++ b/src/components/DocumentView/Heading.tsx @@ -0,0 +1,30 @@ +import clsx from 'clsx'; +import { BlockProps } from './Block'; +import { Inlines } from './Inlines'; + +export function Heading(props: BlockProps) { + const { block, style } = props; + + const headingStyle = STYLES[block.type]; + + return ( + + + + ); +} + +const STYLES = { + 'heading-1': { + tag: 'h2', + className: ['text-3xl', 'font-semibold'], + }, + 'heading-2': { + tag: 'h3', + className: ['text-2xl', 'font-semibold'], + }, + 'heading-3': { + tag: 'h4', + className: ['text-3xl', 'font-semibold'], + }, +}; diff --git a/src/components/DocumentView/Inline.tsx b/src/components/DocumentView/Inline.tsx new file mode 100644 index 000000000..13d9221ab --- /dev/null +++ b/src/components/DocumentView/Inline.tsx @@ -0,0 +1,14 @@ +import { ClassValue } from 'clsx'; + +export interface InlineProps { + inline: T; +} + +export function Inline(props: InlineProps) { + const { inline } = props; + + switch (inline.type) { + default: + return Unsupported inline {inline.type}; + } +} diff --git a/src/components/DocumentView/Inlines.tsx b/src/components/DocumentView/Inlines.tsx new file mode 100644 index 000000000..4ced5b699 --- /dev/null +++ b/src/components/DocumentView/Inlines.tsx @@ -0,0 +1,19 @@ +import clsx from 'clsx'; +import { Text } from './Text'; +import { Inline } from './Inline'; + +export function Inlines(props: { nodes: T[] }) { + const { nodes } = props; + + return ( + <> + {nodes.map((node, index) => { + if (node.object === 'text') { + return ; + } + + return ; + })} + + ); +} diff --git a/src/components/DocumentView/ListItem.tsx b/src/components/DocumentView/ListItem.tsx new file mode 100644 index 000000000..60ae4eb05 --- /dev/null +++ b/src/components/DocumentView/ListItem.tsx @@ -0,0 +1,13 @@ +import clsx from 'clsx'; +import { BlockProps } from './Block'; +import { Blocks } from './Blocks'; + +export function ListItem(props: BlockProps) { + const { block } = props; + + return ( +
  • + +
  • + ); +} diff --git a/src/components/DocumentView/ListOrdered.tsx b/src/components/DocumentView/ListOrdered.tsx new file mode 100644 index 000000000..ad251441b --- /dev/null +++ b/src/components/DocumentView/ListOrdered.tsx @@ -0,0 +1,8 @@ +import { BlockProps } from './Block'; +import { Blocks } from './Blocks'; + +export function ListOrdered(props: BlockProps) { + const { block, style } = props; + + return ; +} diff --git a/src/components/DocumentView/ListUnordered.tsx b/src/components/DocumentView/ListUnordered.tsx new file mode 100644 index 000000000..c487698d1 --- /dev/null +++ b/src/components/DocumentView/ListUnordered.tsx @@ -0,0 +1,8 @@ +import { BlockProps } from './Block'; +import { Blocks } from './Blocks'; + +export function ListUnordered(props: BlockProps) { + const { block, style } = props; + + return ; +} diff --git a/src/components/DocumentView/Paragraph.tsx b/src/components/DocumentView/Paragraph.tsx new file mode 100644 index 000000000..9ffcfc163 --- /dev/null +++ b/src/components/DocumentView/Paragraph.tsx @@ -0,0 +1,13 @@ +import clsx from 'clsx'; +import { BlockProps } from './Block'; +import { Inlines } from './Inlines'; + +export function Paragraph(props: BlockProps) { + const { block, style } = props; + + return ( +

    + +

    + ); +} diff --git a/src/components/DocumentView/Text.tsx b/src/components/DocumentView/Text.tsx new file mode 100644 index 000000000..552fde952 --- /dev/null +++ b/src/components/DocumentView/Text.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +export function Text(props: { text: any }) { + const { text } = props; + + return ( + <> + {text.leaves.map((leaf, index) => { + // TODO: marks + return {leaf.text}; + })} + + ); +} diff --git a/src/components/DocumentView/index.ts b/src/components/DocumentView/index.ts new file mode 100644 index 000000000..2b742d2d5 --- /dev/null +++ b/src/components/DocumentView/index.ts @@ -0,0 +1 @@ +export * from './DocumentView'; diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx new file mode 100644 index 000000000..b345e9c93 --- /dev/null +++ b/src/components/Header/Header.tsx @@ -0,0 +1,27 @@ +import { pageHref } from '@/lib/links'; +import { Space } from '@gitbook/api'; + +import clsx from 'clsx'; +import Link from 'next/link'; + +/** + * Render the header for the space. + */ +export function Header(props: { space: Space }) { + const { space } = props; + + return ( +
    +
    + +

    {space.title}

    + +
    +
    + ); +} diff --git a/src/components/Header/index.ts b/src/components/Header/index.ts new file mode 100644 index 000000000..266dec8a1 --- /dev/null +++ b/src/components/Header/index.ts @@ -0,0 +1 @@ +export * from './Header'; diff --git a/src/components/PageBody/PageBody.tsx b/src/components/PageBody/PageBody.tsx new file mode 100644 index 000000000..ae65a897f --- /dev/null +++ b/src/components/PageBody/PageBody.tsx @@ -0,0 +1,14 @@ +import { Revision, RevisionPageDocument, Space } from '@gitbook/api'; +import { PageHeader } from './PageHeader'; +import { PageDocument } from './PageDocument'; + +export function PageBody(props: { space: Space; revision: Revision; page: RevisionPageDocument }) { + const { space, revision, page } = props; + + return ( +
    + + +
    + ); +} diff --git a/src/components/PageBody/PageDocument.tsx b/src/components/PageBody/PageDocument.tsx new file mode 100644 index 000000000..ce681873c --- /dev/null +++ b/src/components/PageBody/PageDocument.tsx @@ -0,0 +1,20 @@ +import { api } from '@/lib/api'; +import { Revision, RevisionPageDocument, Space } from '@gitbook/api'; +import { DocumentView } from '../DocumentView'; + +/** + * Fetch the document for the page and render it. + */ +export async function PageDocument(props: { + space: Space; + revision: Revision; + page: RevisionPageDocument; +}) { + const { space, revision, page } = props; + + const { + data: { document }, + } = await api().spaces.getPageInRevisionById(space.id, revision.id, page.id); + + return ; +} diff --git a/src/components/PageBody/PageHeader.tsx b/src/components/PageBody/PageHeader.tsx new file mode 100644 index 000000000..6ede8ca03 --- /dev/null +++ b/src/components/PageBody/PageHeader.tsx @@ -0,0 +1,15 @@ +import { RevisionPageDocument } from '@gitbook/api'; +import clsx from 'clsx'; + +export function PageHeader(props: { page: RevisionPageDocument }) { + const { page } = props; + + return ( +
    +

    {page.title}

    + {page.description ? ( +

    {page.description}

    + ) : null} +
    + ); +} diff --git a/src/components/PageBody/index.ts b/src/components/PageBody/index.ts new file mode 100644 index 000000000..9cc5a3f24 --- /dev/null +++ b/src/components/PageBody/index.ts @@ -0,0 +1 @@ +export * from './PageBody'; diff --git a/src/components/SpaceContent/SpaceContent.tsx b/src/components/SpaceContent/SpaceContent.tsx new file mode 100644 index 000000000..4e420b9a3 --- /dev/null +++ b/src/components/SpaceContent/SpaceContent.tsx @@ -0,0 +1,95 @@ +import { Revision, RevisionPage, RevisionPageDocument, Space } from '@gitbook/api'; + +import { TableOfContents } from '@/components/TableOfContents'; +import clsx from 'clsx'; +import { Header } from '@/components/Header'; +import { PageBody } from '@/components/PageBody'; +import { notFound, redirect } from 'next/navigation'; +import { pageHref } from '@/lib/links'; + +/** + * Render the entire content of the space (header, table of contents, footer, and page content). + */ +export function SpaceContent(props: { space: Space; revision: Revision; pagePath: string }) { + const { space, revision, pagePath } = props; + const activePage = resolvePagePath(revision, pagePath); + + return ( +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + ); +} + +function resolvePagePath(revision: Revision, pagePath: string): RevisionPageDocument { + const resolveFirstDocument = (pages: RevisionPage[]): RevisionPageDocument | undefined => { + for (const page of pages) { + if (page.type === 'link') { + continue; + } + + return resolvePage(page); + } + + return; + }; + + const resolvePage = (page: RevisionPage): RevisionPageDocument => { + if (page.type === 'group') { + const firstDocument = resolveFirstDocument(page.pages); + if (firstDocument) { + redirect(pageHref(firstDocument.path)); + } + + notFound(); + } else if (page.type === 'link') { + notFound(); + } + + return page; + }; + + const iteratePages = (pages: RevisionPage[]): RevisionPageDocument | undefined => { + for (const page of pages) { + if (page.type === 'link') { + continue; + } + + if (page.path !== pagePath) { + // TODO: can be optimized to count the number of slashes and skip the entire subtree + const result = iteratePages(page.pages); + if (result) { + return result; + } + + continue; + } + + return resolvePage(page); + } + }; + + if (!pagePath) { + const firstPage = resolveFirstDocument(revision.pages); + if (!firstPage) { + notFound(); + } + + return firstPage; + } + + const result = iteratePages(revision.pages); + if (!result) { + notFound(); + } + + return result; +} diff --git a/src/components/SpaceContent/index.ts b/src/components/SpaceContent/index.ts new file mode 100644 index 000000000..6436c15b8 --- /dev/null +++ b/src/components/SpaceContent/index.ts @@ -0,0 +1 @@ +export * from './SpaceContent'; diff --git a/src/components/TableOfContents/PageDocumentItem.tsx b/src/components/TableOfContents/PageDocumentItem.tsx new file mode 100644 index 000000000..721d60736 --- /dev/null +++ b/src/components/TableOfContents/PageDocumentItem.tsx @@ -0,0 +1,36 @@ +import { RevisionPageDocument } from '@gitbook/api'; +import { clsx } from 'clsx'; +import Link from 'next/link'; +import { PagesList } from './PagesList'; +import { pageHref } from '@/lib/links'; + +export function PageDocumentItem(props: { + page: RevisionPageDocument; + activePage: RevisionPageDocument; +}) { + const { page, activePage } = props; + + return ( +
  • + + {page.title} + + {page.pages && page.pages.length ? ( + + ) : null} +
  • + ); +} diff --git a/src/components/TableOfContents/PageGroupItem.tsx b/src/components/TableOfContents/PageGroupItem.tsx new file mode 100644 index 000000000..32baa9a8d --- /dev/null +++ b/src/components/TableOfContents/PageGroupItem.tsx @@ -0,0 +1,21 @@ +import { RevisionPageDocument, RevisionPageGroup } from '@gitbook/api'; +import { clsx } from 'clsx'; +import { PagesList } from './PagesList'; + +export function PageGroupItem(props: { + page: RevisionPageGroup; + activePage: RevisionPageDocument; +}) { + const { page, activePage } = props; + + return ( +
  • +
    + {page.title} +
    + {page.pages && page.pages.length ? ( + + ) : null} +
  • + ); +} diff --git a/src/components/TableOfContents/PagesList.tsx b/src/components/TableOfContents/PagesList.tsx new file mode 100644 index 000000000..4cf7db72c --- /dev/null +++ b/src/components/TableOfContents/PagesList.tsx @@ -0,0 +1,24 @@ +import { RevisionPage, RevisionPageDocument } from '@gitbook/api'; +import { ClassValue, clsx } from 'clsx'; +import { PageDocumentItem } from './PageDocumentItem'; +import { PageGroupItem } from './PageGroupItem'; + +export function PagesList(props: { + pages: RevisionPage[]; + activePage: RevisionPageDocument; + style?: ClassValue; +}) { + const { pages, activePage, style } = props; + + return ( +
      + {pages.map((page) => { + if (page.type === 'group') { + return ; + } + + return ; + })} +
    + ); +} diff --git a/src/components/TableOfContents/TableOfContents.tsx b/src/components/TableOfContents/TableOfContents.tsx new file mode 100644 index 000000000..fbf0516fc --- /dev/null +++ b/src/components/TableOfContents/TableOfContents.tsx @@ -0,0 +1,22 @@ +import { Revision, RevisionPageDocument } from '@gitbook/api'; +import { clsx } from 'clsx'; +import { PagesList } from './PagesList'; +import { Trademark } from './Trademark'; + +export function TableOfContents(props: { revision: Revision; activePage: RevisionPageDocument }) { + const { revision, activePage } = props; + + return ( + + ); +} diff --git a/src/components/TableOfContents/Trademark.tsx b/src/components/TableOfContents/Trademark.tsx new file mode 100644 index 000000000..0a1a89587 --- /dev/null +++ b/src/components/TableOfContents/Trademark.tsx @@ -0,0 +1,28 @@ +import clsx from 'clsx'; + +/** + * Link to the GitBook platform. + */ +export function Trademark() { + return ( + + ); +} diff --git a/src/components/TableOfContents/index.ts b/src/components/TableOfContents/index.ts new file mode 100644 index 000000000..715a3a239 --- /dev/null +++ b/src/components/TableOfContents/index.ts @@ -0,0 +1 @@ +export * from './TableOfContents'; diff --git a/src/lib/api.ts b/src/lib/api.ts new file mode 100644 index 000000000..56c198887 --- /dev/null +++ b/src/lib/api.ts @@ -0,0 +1,19 @@ +import 'server-only'; + +import { headers } from 'next/headers'; +import { GitBookAPI } from '@gitbook/api'; + +/** + * Create an API client for the current request. + */ +export function api(): GitBookAPI { + const headersList = headers(); + const apiToken = headersList.get('x-gitbook-token'); + + const gitbook = new GitBookAPI({ + authToken: apiToken || process.env.GITBOOK_TOKEN, + endpoint: process.env.GITBOOK_API_URL, + }); + + return gitbook; +} diff --git a/src/lib/links.ts b/src/lib/links.ts new file mode 100644 index 000000000..889627d44 --- /dev/null +++ b/src/lib/links.ts @@ -0,0 +1,13 @@ +import 'server-only'; + +import { headers } from 'next/headers'; + +/** + * Create a link to a page path in the current space. + */ +export function pageHref(pagePath: string): string { + const headersList = headers(); + const basePath = headersList.get('x-gitbook-basepath') ?? ''; + + return `${basePath}/${pagePath.startsWith('/') ? pagePath.slice(1) : pagePath}`; +} diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 000000000..55fe554a3 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,25 @@ +import { NextResponse } from 'next/server'; +import { NextRequest } from 'next/server'; + +/** + * Rewrite the request to extract the spaceId from the URL + * and pass it as a header. + */ +export function middleware(request: NextRequest) { + const url = new URL(request.url); + const [space, ...pathRest] = url.pathname.slice(1).split('/'); + + const headers = new Headers(request.headers); + headers.set('x-gitbook-space', space); + headers.set('x-gitbook-basepath', `/${space}`); + + url.pathname = `/${pathRest.join('/')}`; + + return NextResponse.rewrite(url, { + headers, + }); +} + +export const config = { + matcher: '/((?!api|_next/static|_next/image|favicon.ico).*)', +}; diff --git a/tailwind.config.ts b/tailwind.config.ts index 1af3b8f01..e23395f3d 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,20 +1,19 @@ -import type { Config } from 'tailwindcss' +import type { Config } from 'tailwindcss'; +import colors from 'tailwindcss/colors'; const config: Config = { - content: [ - './src/pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './src/app/**/*.{js,ts,jsx,tsx,mdx}', - ], - theme: { - extend: { - backgroundImage: { - 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', - 'gradient-conic': - 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', - }, + content: [ + './src/pages/**/*.{js,ts,jsx,tsx,mdx}', + './src/components/**/*.{js,ts,jsx,tsx,mdx}', + './src/app/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: { + colors: { + primary: colors.blue, + }, + }, }, - }, - plugins: [], -} -export default config + plugins: [], +}; +export default config; diff --git a/tsconfig.json b/tsconfig.json index e59724b28..1445a451f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,27 @@ { - "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] }