From da33f96c35fac9985d15c28f1f2d1d25e7cf1c81 Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Tue, 21 Oct 2025 20:56:35 +0700 Subject: [PATCH] feat: improve docs layout --- .../src/app/docs/api/text-to-image/page.tsx | 38 +------ .../app/docs/guides/authentication/page.tsx | 47 ++------- apps/landing/src/app/docs/layout.tsx | 99 +++++++++++++++++-- apps/landing/src/app/docs/page.tsx | 33 +------ apps/landing/src/contexts/TocContext.tsx | 53 ++++++++++ 5 files changed, 162 insertions(+), 108 deletions(-) create mode 100644 apps/landing/src/contexts/TocContext.tsx diff --git a/apps/landing/src/app/docs/api/text-to-image/page.tsx b/apps/landing/src/app/docs/api/text-to-image/page.tsx index 6c4d3c7..93065e7 100644 --- a/apps/landing/src/app/docs/api/text-to-image/page.tsx +++ b/apps/landing/src/app/docs/api/text-to-image/page.tsx @@ -4,16 +4,12 @@ * API Reference: Text to Image * * Refactored to use block components from @/components/docs/blocks - * Demonstrates API documentation patterns with semantic components + * Layout (SubsectionNav, DocsSidebar, Breadcrumb, TOC) handled by parent layout.tsx + * This page only provides TOC items and content. */ -import { DocsLayout } from '@/components/docs/layout/DocsLayout'; -import { DocsSidebar } from '@/components/docs/layout/DocsSidebar'; -import { DocsTOC } from '@/components/docs/layout/DocsTOC'; -import { SubsectionNav } from '@/components/shared/SubsectionNav'; import { TipBox } from '@/components/docs/shared/TipBox'; import { Table } from '@/components/docs/shared/Table'; -import { Breadcrumb } from '@/components/docs/shared/Breadcrumb'; import { CodeBlock } from '@/components/docs/shared/CodeBlock'; import { InteractiveAPIWidget } from '@/components/docs/blocks/InteractiveAPIWidget'; import { @@ -24,6 +20,7 @@ import { LinkCard, LinkCardGrid, } from '@/components/docs/blocks'; +import { TocProvider } from '@/contexts/TocContext'; const tocItems = [ { id: 'overview', text: 'Overview', level: 2 }, @@ -35,12 +32,6 @@ const tocItems = [ { id: 'next-steps', text: 'Next Steps', level: 2 }, ]; -const navItems = [ - { label: 'Documentation', href: '/docs' }, - { label: 'Demo', href: '/demo' }, - { label: 'Examples', href: '/docs/examples' }, -]; - const parameters = [ { name: 'prompt', type: 'string', required: true, description: 'Text description of the image to generate' }, { name: 'filename', type: 'string', required: false, description: 'Output filename (without extension)' }, @@ -50,25 +41,7 @@ const parameters = [ export default function TextToImageAPIPage() { return ( - <> - {/* Subsection Navigation with API Key Input */} - - - } - toc={} - > - + {/* Hero Section */} - - + ); } diff --git a/apps/landing/src/app/docs/guides/authentication/page.tsx b/apps/landing/src/app/docs/guides/authentication/page.tsx index 6b3d159..a8d1a73 100644 --- a/apps/landing/src/app/docs/guides/authentication/page.tsx +++ b/apps/landing/src/app/docs/guides/authentication/page.tsx @@ -1,23 +1,15 @@ 'use client'; /** - * Authentication Guide - Final Variant + * Authentication Guide * - * Features: - * - SubsectionNav at top - * - Prominent TipBox for security warnings - * - Compact TipBox for general tips - * - Enhanced tables for rate limits and key types - * - Simplified Next Steps + * Refactored to use block components from @/components/docs/blocks + * Layout (SubsectionNav, DocsSidebar, Breadcrumb, TOC) handled by parent layout.tsx + * This page only provides TOC items and content. */ -import { DocsLayout } from '@/components/docs/layout/DocsLayout'; -import { DocsSidebar } from '@/components/docs/layout/DocsSidebar'; -import { DocsTOC } from '@/components/docs/layout/DocsTOC'; -import { SubsectionNav } from '@/components/shared/SubsectionNav'; import { TipBox } from '@/components/docs/shared/TipBox'; import { Table } from '@/components/docs/shared/Table'; -import { Breadcrumb } from '@/components/docs/shared/Breadcrumb'; import { CodeBlock } from '@/components/docs/shared/CodeBlock'; import { Hero, @@ -26,6 +18,7 @@ import { LinkCard, LinkCardGrid, } from '@/components/docs/blocks'; +import { TocProvider } from '@/contexts/TocContext'; const tocItems = [ { id: 'overview', text: 'Overview', level: 2 }, @@ -38,34 +31,9 @@ const tocItems = [ { id: 'next-steps', text: 'Next Steps', level: 2 }, ]; -const navItems = [ - { label: 'Documentation', href: '/docs' }, - { label: 'Demo', href: '/demo' }, - { label: 'Examples', href: '/docs/examples' }, -]; - export default function AuthenticationGuidePage() { return ( - <> - {/* Subsection Navigation */} - - - } - toc={} - > - + {/* Hero Section */} - - + ); } diff --git a/apps/landing/src/app/docs/layout.tsx b/apps/landing/src/app/docs/layout.tsx index 7c810cb..0f01a99 100644 --- a/apps/landing/src/app/docs/layout.tsx +++ b/apps/landing/src/app/docs/layout.tsx @@ -1,22 +1,78 @@ +'use client'; + import { ReactNode } from 'react'; +import { usePathname } from 'next/navigation'; +import { SubsectionNav } from '@/components/shared/SubsectionNav'; +import { DocsSidebar } from '@/components/docs/layout/DocsSidebar'; +import { DocsTOC } from '@/components/docs/layout/DocsTOC'; +import { Breadcrumb } from '@/components/docs/shared/Breadcrumb'; +import { useToc } from '@/contexts/TocContext'; /** * Root Documentation Layout * - * Simple wrapper for all documentation pages. - * Each variant handles its own layout/navigation. + * Centralized layout for all documentation pages providing: + * - SubsectionNav at the top + * - Three-column layout (sidebar, content, TOC) + * - Automatic breadcrumb generation + * - Consistent background and styling + * + * Pages only need to: + * 1. Wrap content with + * 2. Provide their content * * Features: - * - Consistent background gradient matching landing page - * - No navigation/sidebars at this level - * - Children render their own layouts + * - Animated gradient background matching landing page + * - Automatic active page detection via pathname + * - Auto-generated breadcrumbs from URL structure + * - Responsive layout (mobile → tablet → desktop) */ interface DocsRootLayoutProps { children: ReactNode; } +const navItems = [ + { label: 'Documentation', href: '/docs' }, + { label: 'Demo', href: '/demo' }, + { label: 'Examples', href: '/docs/examples' }, +]; + +// Generate breadcrumb items from pathname +const getBreadcrumbItems = (pathname: string): { label: string; href?: string }[] => { + const segments = pathname.split('/').filter(Boolean); + + if (segments.length === 1 && segments[0] === 'docs') { + return [ + { label: 'Documentation', href: '/docs' }, + { label: 'Getting Started' }, + ]; + } + + const items: { label: string; href?: string }[] = [ + { label: 'Documentation', href: '/docs' }, + ]; + + if (segments.includes('guides')) { + items.push({ label: 'Guides', href: '/docs/guides' }); + if (segments.includes('authentication')) { + items.push({ label: 'Authentication' }); + } + } else if (segments.includes('api')) { + items.push({ label: 'API Reference', href: '/docs/api' }); + if (segments.includes('text-to-image')) { + items.push({ label: 'Text to Image' }); + } + } + + return items; +}; + export default function DocsRootLayout({ children }: DocsRootLayoutProps) { + const pathname = usePathname(); + const { tocItems } = useToc(); + const breadcrumbItems = getBreadcrumbItems(pathname); + return (
{/* Animated gradient background (matching landing page) */} @@ -25,8 +81,37 @@ export default function DocsRootLayout({ children }: DocsRootLayoutProps) {
- {/* Content */} -
{children}
+ {/* Subsection Navigation */} + + + {/* Three-column Documentation Layout */} +
+ {/* Left Sidebar - Thin, minimal design */} + + + {/* Main Content Area - Wide margins for comfortable reading */} +
+
+ {/* Breadcrumb */} + + + {/* Page Content */} + {children} +
+
+ + {/* Right TOC - Subtle and unobtrusive */} + +
); } diff --git a/apps/landing/src/app/docs/page.tsx b/apps/landing/src/app/docs/page.tsx index 8a05d26..969db2f 100644 --- a/apps/landing/src/app/docs/page.tsx +++ b/apps/landing/src/app/docs/page.tsx @@ -4,16 +4,12 @@ * Getting Started Page - Production Documentation * * Refactored to use block components from @/components/docs/blocks - * Demonstrates composition of reusable semantic components + * Layout (SubsectionNav, DocsSidebar, Breadcrumb, TOC) handled by parent layout.tsx + * This page only provides TOC items and content. */ -import { DocsLayout } from '@/components/docs/layout/DocsLayout'; -import { DocsSidebar } from '@/components/docs/layout/DocsSidebar'; -import { DocsTOC } from '@/components/docs/layout/DocsTOC'; -import { SubsectionNav } from '@/components/shared/SubsectionNav'; import { TipBox } from '@/components/docs/shared/TipBox'; import { CodeBlock } from '@/components/docs/shared/CodeBlock'; -import { Breadcrumb } from '@/components/docs/shared/Breadcrumb'; import { Hero, SectionHeader, @@ -21,6 +17,7 @@ import { LinkCard, LinkCardGrid, } from '@/components/docs/blocks'; +import { TocProvider } from '@/contexts/TocContext'; const tocItems = [ { id: 'introduction', text: 'Introduction', level: 2 }, @@ -31,28 +28,9 @@ const tocItems = [ { id: 'next-steps', text: 'Next Steps', level: 2 }, ]; -const navItems = [ - { label: 'Documentation', href: '/docs' }, - { label: 'Demo', href: '/demo' }, - { label: 'Examples', href: '/docs/examples' }, -]; - export default function GettingStartedPage() { return ( - <> - {/* Subsection Navigation */} - - - } - toc={} - > - + {/* Hero Section */} - - +
); } diff --git a/apps/landing/src/contexts/TocContext.tsx b/apps/landing/src/contexts/TocContext.tsx new file mode 100644 index 0000000..7460375 --- /dev/null +++ b/apps/landing/src/contexts/TocContext.tsx @@ -0,0 +1,53 @@ +'use client'; + +/** + * Table of Contents Context + * + * Allows documentation pages to pass their TOC items up to the layout + * so the layout can render the TOC in the right sidebar. + * + * Usage in pages: + * ```tsx + * + * + * + * ``` + * + * Usage in layout: + * ```tsx + * const { tocItems } = useToc(); + * return ; + * ``` + */ + +import { createContext, useContext, ReactNode } from 'react'; + +export interface TocItem { + id: string; + text: string; + level: number; +} + +interface TocContextValue { + tocItems: TocItem[]; +} + +const TocContext = createContext(undefined); + +interface TocProviderProps { + tocItems: TocItem[]; + children: ReactNode; +} + +export const TocProvider = ({ tocItems, children }: TocProviderProps) => { + return {children}; +}; + +export const useToc = (): TocContextValue => { + const context = useContext(TocContext); + if (!context) { + // Return empty array if no provider (allows layout to work without TOC) + return { tocItems: [] }; + } + return context; +};