feat: improve docs layout

This commit is contained in:
Oleg Proskurin 2025-10-21 20:56:35 +07:00
parent 813e0b186c
commit da33f96c35
5 changed files with 162 additions and 108 deletions

View File

@ -4,16 +4,12 @@
* API Reference: Text to Image * API Reference: Text to Image
* *
* Refactored to use block components from @/components/docs/blocks * 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 { TipBox } from '@/components/docs/shared/TipBox';
import { Table } from '@/components/docs/shared/Table'; import { Table } from '@/components/docs/shared/Table';
import { Breadcrumb } from '@/components/docs/shared/Breadcrumb';
import { CodeBlock } from '@/components/docs/shared/CodeBlock'; import { CodeBlock } from '@/components/docs/shared/CodeBlock';
import { InteractiveAPIWidget } from '@/components/docs/blocks/InteractiveAPIWidget'; import { InteractiveAPIWidget } from '@/components/docs/blocks/InteractiveAPIWidget';
import { import {
@ -24,6 +20,7 @@ import {
LinkCard, LinkCard,
LinkCardGrid, LinkCardGrid,
} from '@/components/docs/blocks'; } from '@/components/docs/blocks';
import { TocProvider } from '@/contexts/TocContext';
const tocItems = [ const tocItems = [
{ id: 'overview', text: 'Overview', level: 2 }, { id: 'overview', text: 'Overview', level: 2 },
@ -35,12 +32,6 @@ const tocItems = [
{ id: 'next-steps', text: 'Next Steps', level: 2 }, { 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 = [ const parameters = [
{ name: 'prompt', type: 'string', required: true, description: 'Text description of the image to generate' }, { 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)' }, { name: 'filename', type: 'string', required: false, description: 'Output filename (without extension)' },
@ -50,25 +41,7 @@ const parameters = [
export default function TextToImageAPIPage() { export default function TextToImageAPIPage() {
return ( return (
<> <TocProvider tocItems={tocItems}>
{/* Subsection Navigation with API Key Input */}
<SubsectionNav
items={navItems}
currentPath="/docs/api/text-to-image"
showApiKeyInput={true}
/>
<DocsLayout
sidebar={<DocsSidebar currentPath="/docs/api/text-to-image" />}
toc={<DocsTOC items={tocItems} />}
>
<Breadcrumb
items={[
{ label: 'Documentation', href: '/docs' },
{ label: 'API Reference', href: '/docs/api' },
{ label: 'Text to Image' },
]}
/>
{/* Hero Section */} {/* Hero Section */}
<Hero <Hero
@ -247,7 +220,6 @@ export default function TextToImageAPIPage() {
/> />
</LinkCardGrid> </LinkCardGrid>
</section> </section>
</DocsLayout> </TocProvider>
</>
); );
} }

View File

@ -1,23 +1,15 @@
'use client'; 'use client';
/** /**
* Authentication Guide - Final Variant * Authentication Guide
* *
* Features: * Refactored to use block components from @/components/docs/blocks
* - SubsectionNav at top * Layout (SubsectionNav, DocsSidebar, Breadcrumb, TOC) handled by parent layout.tsx
* - Prominent TipBox for security warnings * This page only provides TOC items and content.
* - Compact TipBox for general tips
* - Enhanced tables for rate limits and key types
* - Simplified Next Steps
*/ */
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 { TipBox } from '@/components/docs/shared/TipBox';
import { Table } from '@/components/docs/shared/Table'; import { Table } from '@/components/docs/shared/Table';
import { Breadcrumb } from '@/components/docs/shared/Breadcrumb';
import { CodeBlock } from '@/components/docs/shared/CodeBlock'; import { CodeBlock } from '@/components/docs/shared/CodeBlock';
import { import {
Hero, Hero,
@ -26,6 +18,7 @@ import {
LinkCard, LinkCard,
LinkCardGrid, LinkCardGrid,
} from '@/components/docs/blocks'; } from '@/components/docs/blocks';
import { TocProvider } from '@/contexts/TocContext';
const tocItems = [ const tocItems = [
{ id: 'overview', text: 'Overview', level: 2 }, { id: 'overview', text: 'Overview', level: 2 },
@ -38,34 +31,9 @@ const tocItems = [
{ id: 'next-steps', text: 'Next Steps', level: 2 }, { 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() { export default function AuthenticationGuidePage() {
return ( return (
<> <TocProvider tocItems={tocItems}>
{/* Subsection Navigation */}
<SubsectionNav
items={navItems}
currentPath="/docs/guides/authentication"
ctaText="Join Beta"
ctaHref="/signup"
/>
<DocsLayout
sidebar={<DocsSidebar currentPath="/docs/guides/authentication" />}
toc={<DocsTOC items={tocItems} />}
>
<Breadcrumb
items={[
{ label: 'Documentation', href: '/docs' },
{ label: 'Guides', href: '/docs/guides' },
{ label: 'Authentication' },
]}
/>
{/* Hero Section */} {/* Hero Section */}
<Hero <Hero
@ -339,7 +307,6 @@ curl -X DELETE https://api.banatie.com/api/admin/keys/OLD_KEY_ID \\
/> />
</LinkCardGrid> </LinkCardGrid>
</section> </section>
</DocsLayout> </TocProvider>
</>
); );
} }

View File

@ -1,22 +1,78 @@
'use client';
import { ReactNode } from 'react'; 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 * Root Documentation Layout
* *
* Simple wrapper for all documentation pages. * Centralized layout for all documentation pages providing:
* Each variant handles its own layout/navigation. * - 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 <TocProvider tocItems={...}>
* 2. Provide their content
* *
* Features: * Features:
* - Consistent background gradient matching landing page * - Animated gradient background matching landing page
* - No navigation/sidebars at this level * - Automatic active page detection via pathname
* - Children render their own layouts * - Auto-generated breadcrumbs from URL structure
* - Responsive layout (mobile tablet desktop)
*/ */
interface DocsRootLayoutProps { interface DocsRootLayoutProps {
children: ReactNode; 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) { export default function DocsRootLayout({ children }: DocsRootLayoutProps) {
const pathname = usePathname();
const { tocItems } = useToc();
const breadcrumbItems = getBreadcrumbItems(pathname);
return ( return (
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950"> <div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950">
{/* Animated gradient background (matching landing page) */} {/* Animated gradient background (matching landing page) */}
@ -25,8 +81,37 @@ export default function DocsRootLayout({ children }: DocsRootLayoutProps) {
<div className="absolute bottom-1/4 -right-1/4 w-96 h-96 bg-cyan-600/10 rounded-full blur-3xl animate-pulse delay-700"></div> <div className="absolute bottom-1/4 -right-1/4 w-96 h-96 bg-cyan-600/10 rounded-full blur-3xl animate-pulse delay-700"></div>
</div> </div>
{/* Content */} {/* Subsection Navigation */}
<div className="relative z-10">{children}</div> <SubsectionNav
items={navItems}
currentPath={pathname}
ctaText="Join Beta"
ctaHref="/signup"
/>
{/* Three-column Documentation Layout */}
<div className="relative z-10 flex">
{/* Left Sidebar - Thin, minimal design */}
<aside className="hidden lg:block w-64 border-r border-white/10 bg-slate-950/50 backdrop-blur-sm sticky top-12 h-[calc(100vh-3rem)] overflow-y-auto">
<DocsSidebar currentPath={pathname} />
</aside>
{/* Main Content Area - Wide margins for comfortable reading */}
<main className="flex-1 min-w-0">
<div className="max-w-3xl mx-auto px-6 lg:px-12 py-12">
{/* Breadcrumb */}
<Breadcrumb items={breadcrumbItems} />
{/* Page Content */}
{children}
</div>
</main>
{/* Right TOC - Subtle and unobtrusive */}
<aside className="hidden xl:block w-56 border-l border-white/10 bg-slate-950/30 backdrop-blur-sm sticky top-12 h-[calc(100vh-3rem)] overflow-y-auto">
<DocsTOC items={tocItems} />
</aside>
</div>
</div> </div>
); );
} }

View File

@ -4,16 +4,12 @@
* Getting Started Page - Production Documentation * Getting Started Page - Production Documentation
* *
* Refactored to use block components from @/components/docs/blocks * 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 { TipBox } from '@/components/docs/shared/TipBox';
import { CodeBlock } from '@/components/docs/shared/CodeBlock'; import { CodeBlock } from '@/components/docs/shared/CodeBlock';
import { Breadcrumb } from '@/components/docs/shared/Breadcrumb';
import { import {
Hero, Hero,
SectionHeader, SectionHeader,
@ -21,6 +17,7 @@ import {
LinkCard, LinkCard,
LinkCardGrid, LinkCardGrid,
} from '@/components/docs/blocks'; } from '@/components/docs/blocks';
import { TocProvider } from '@/contexts/TocContext';
const tocItems = [ const tocItems = [
{ id: 'introduction', text: 'Introduction', level: 2 }, { id: 'introduction', text: 'Introduction', level: 2 },
@ -31,28 +28,9 @@ const tocItems = [
{ id: 'next-steps', text: 'Next Steps', level: 2 }, { 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() { export default function GettingStartedPage() {
return ( return (
<> <TocProvider tocItems={tocItems}>
{/* Subsection Navigation */}
<SubsectionNav
items={navItems}
currentPath="/docs"
ctaText="Join Beta"
ctaHref="/signup"
/>
<DocsLayout
sidebar={<DocsSidebar currentPath="/docs" />}
toc={<DocsTOC items={tocItems} />}
>
<Breadcrumb items={[{ label: 'Documentation', href: '/docs' }, { label: 'Getting Started' }]} />
{/* Hero Section */} {/* Hero Section */}
<Hero <Hero
@ -214,7 +192,6 @@ export BANATIE_API_KEY="bnt_your_key_here"`}
/> />
</LinkCardGrid> </LinkCardGrid>
</section> </section>
</DocsLayout> </TocProvider>
</>
); );
} }

View File

@ -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
* <TocProvider tocItems={[...]}>
* <page content>
* </TocProvider>
* ```
*
* Usage in layout:
* ```tsx
* const { tocItems } = useToc();
* return <DocsTOC items={tocItems} />;
* ```
*/
import { createContext, useContext, ReactNode } from 'react';
export interface TocItem {
id: string;
text: string;
level: number;
}
interface TocContextValue {
tocItems: TocItem[];
}
const TocContext = createContext<TocContextValue | undefined>(undefined);
interface TocProviderProps {
tocItems: TocItem[];
children: ReactNode;
}
export const TocProvider = ({ tocItems, children }: TocProviderProps) => {
return <TocContext.Provider value={{ tocItems }}>{children}</TocContext.Provider>;
};
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;
};