From dd0e6db1715e45aab6de69fa8ea4664ee02f2e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Tue, 24 Oct 2023 22:07:19 +0200 Subject: [PATCH] Start tabs --- README.md | 13 ++-- src/components/DocumentView/Block.tsx | 3 + .../DocumentView/Tabs/DynamicTabs.tsx | 62 +++++++++++++++++++ src/components/DocumentView/Tabs/Tabs.tsx | 19 ++++++ src/components/DocumentView/Tabs/index.ts | 1 + src/components/PageAside/PageAside.tsx | 35 +++++------ .../PageAside/ScrollSectionsList.tsx | 40 ++++++------ src/lib/document.ts | 13 ++-- 8 files changed, 137 insertions(+), 49 deletions(-) create mode 100644 src/components/DocumentView/Tabs/DynamicTabs.tsx create mode 100644 src/components/DocumentView/Tabs/Tabs.tsx create mode 100644 src/components/DocumentView/Tabs/index.ts diff --git a/README.md b/README.md index ae2fcad23..6b7d51ee7 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,15 @@ - [ ] Code block syntax highlighting - Theme - [ ] Toggler -- Page feedback -- Edit on GitHub -- Header links +- Page feedback +- Edit on GitHub +- Header links ## Differences -- Changed: Full-width mode: +- Changed: Full-width mode: - When off, layout is centered - It now detects based on the page -- New: Scroll to top button in page aside -- New: Proper RTL support \ No newline at end of file +- New: Scroll to top button in page aside +- New: Proper RTL support +- New: Per page OpenGraph cover image diff --git a/src/components/DocumentView/Block.tsx b/src/components/DocumentView/Block.tsx index 9285c4fb9..ccb2654c5 100644 --- a/src/components/DocumentView/Block.tsx +++ b/src/components/DocumentView/Block.tsx @@ -9,6 +9,7 @@ import { tcls } from '@/lib/tailwind'; import { Hint } from './Hint'; import { DocumentContextProps } from './DocumentView'; import { Images } from './Images'; +import { Tabs } from './Tabs'; export interface BlockProps extends DocumentContextProps { block: T; @@ -37,6 +38,8 @@ export function Block(props: BlockProps) { return ; case 'images': return ; + case 'tabs': + return ; default: return
Unsupported block {block.type}
; } diff --git a/src/components/DocumentView/Tabs/DynamicTabs.tsx b/src/components/DocumentView/Tabs/DynamicTabs.tsx new file mode 100644 index 000000000..f35026656 --- /dev/null +++ b/src/components/DocumentView/Tabs/DynamicTabs.tsx @@ -0,0 +1,62 @@ +'use client'; + +import { ClassValue, tcls } from '@/lib/tailwind'; +import React from 'react'; + +/** + * Client side component for the tabs, taking care of interactions. + */ +export function DynamicTabs(props: { + tabs: Array<{ + id: string; + title: string; + children: React.ReactNode; + }>; + style: ClassValue; +}) { + const { tabs, style } = props; + + const [active, setActive] = React.useState(null); + + return ( +
+
+ {tabs.map((tab) => ( + + ))} +
+ {tabs.map((tab) => ( +
+ {tab.children} +
+ ))} +
+ ); +} diff --git a/src/components/DocumentView/Tabs/Tabs.tsx b/src/components/DocumentView/Tabs/Tabs.tsx new file mode 100644 index 000000000..7636ace81 --- /dev/null +++ b/src/components/DocumentView/Tabs/Tabs.tsx @@ -0,0 +1,19 @@ +import { tcls } from '@/lib/tailwind'; +import { BlockProps } from '../Block'; +import { Blocks } from '../Blocks'; +import { DynamicTabs } from './DynamicTabs'; + +export function Tabs(props: BlockProps) { + const { block, style, context } = props; + + return ( + ({ + id: tab.key ?? index, // TODO: fix in API + title: tab.data.title, + children: , + }))} + style={style} + /> + ); +} diff --git a/src/components/DocumentView/Tabs/index.ts b/src/components/DocumentView/Tabs/index.ts new file mode 100644 index 000000000..856dbbb34 --- /dev/null +++ b/src/components/DocumentView/Tabs/index.ts @@ -0,0 +1 @@ +export * from './Tabs'; diff --git a/src/components/PageAside/PageAside.tsx b/src/components/PageAside/PageAside.tsx index 8bec0459c..3677dfb1a 100644 --- a/src/components/PageAside/PageAside.tsx +++ b/src/components/PageAside/PageAside.tsx @@ -1,21 +1,19 @@ -import { getDocumentSections } from "@/lib/document"; -import { tcls } from "@/lib/tailwind"; -import { RevisionPageDocument } from "@gitbook/api"; -import React from "react"; -import { ScrollSectionsList } from "./ScrollSectionsList"; +import { getDocumentSections } from '@/lib/document'; +import { tcls } from '@/lib/tailwind'; +import { RevisionPageDocument } from '@gitbook/api'; +import React from 'react'; +import { ScrollSectionsList } from './ScrollSectionsList'; /** * Aside listing the headings in the document. */ -export function PageAside(props: { - page: RevisionPageDocument; - document: any; -}) { +export function PageAside(props: { page: RevisionPageDocument; document: any }) { const { document } = props; const sections = getDocumentSections(document); return ( - - ) -} \ No newline at end of file + ); +} diff --git a/src/components/PageAside/ScrollSectionsList.tsx b/src/components/PageAside/ScrollSectionsList.tsx index fa216bb36..82822fc4a 100644 --- a/src/components/PageAside/ScrollSectionsList.tsx +++ b/src/components/PageAside/ScrollSectionsList.tsx @@ -1,14 +1,12 @@ 'use client'; -import { DocumentSection } from "@/lib/document"; -import { tcls } from "@/lib/tailwind"; -import Link from "next/link"; -import React from "react"; -import { IconChevronRight } from "@/components/icons/IconChevronRight"; +import { DocumentSection } from '@/lib/document'; +import { tcls } from '@/lib/tailwind'; +import Link from 'next/link'; +import React from 'react'; +import { IconChevronRight } from '@/components/icons/IconChevronRight'; -export function ScrollSectionsList(props: { - sections: DocumentSection[]; -}) { +export function ScrollSectionsList(props: { sections: DocumentSection[] }) { const { sections } = props; const [activeId, setActiveId] = React.useState(null); @@ -18,15 +16,21 @@ export function ScrollSectionsList(props: { return (
    - {sections.map(section => ( + {sections.map((section) => (
  • - 1 ? ['font-light', 'ps-3', 'py-1', 'text-slate-500', ] : ['py-2', 'text-slate-700', ], - - activeId === section.id ? 'text-primary-500' : 'hover:text-slate-900', - )}> + 1 + ? ['font-light', 'ps-3', 'py-1', 'text-slate-500'] + : ['py-2', 'text-slate-700'], + + activeId === section.id ? 'text-primary-500' : 'hover:text-slate-900', + )} + > {section.depth > 1 ? ( ) : null} @@ -35,5 +39,5 @@ export function ScrollSectionsList(props: {
  • ))}
- ) -} \ No newline at end of file + ); +} diff --git a/src/lib/document.ts b/src/lib/document.ts index e39aec470..be44e83da 100644 --- a/src/lib/document.ts +++ b/src/lib/document.ts @@ -1,4 +1,3 @@ - export interface DocumentSection { id: string; title: string; @@ -21,8 +20,12 @@ export function getDocumentSections(document: any): DocumentSection[] { const sections: DocumentSection[] = []; let depth = 0; - document.nodes.forEach(block => { - if (block.type === 'heading-1' || block.type === 'heading-2' || block.type === 'heading-3') { + document.nodes.forEach((block) => { + if ( + block.type === 'heading-1' || + block.type === 'heading-2' || + block.type === 'heading-3' + ) { if (block.type === 'heading-1') { depth = 1; } @@ -32,7 +35,7 @@ export function getDocumentSections(document: any): DocumentSection[] { sections.push({ id: block.data.id ?? title, // TODO: use slugify title, - depth: block.type === 'heading-1' ? 1 : (depth > 0 ? 2 : 1), + depth: block.type === 'heading-1' ? 1 : depth > 0 ? 2 : 1, }); } }); @@ -49,7 +52,7 @@ export function getNodeText(node: any): string { return node.leaves.map((leaf) => leaf.text).join(''); case 'block': case 'inline': - return node.nodes.map(child => getNodeText(child)).join(''); + return node.nodes.map((child) => getNodeText(child)).join(''); default: throw new Error('Invalid node'); }