feat: update navbar
This commit is contained in:
parent
f90fd8f65a
commit
da6887d41c
|
|
@ -4,20 +4,25 @@ import { ReactNode } from 'react';
|
|||
import { usePathname } from 'next/navigation';
|
||||
import { SubsectionNav } from '@/components/shared/SubsectionNav';
|
||||
import { DocsSidebar } from '@/components/docs/layout/DocsSidebar';
|
||||
import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout';
|
||||
|
||||
/**
|
||||
* Root Documentation Layout
|
||||
*
|
||||
* Provides shared layout elements for all documentation pages:
|
||||
* - SubsectionNav at the top
|
||||
* - Left Sidebar (DocsSidebar)
|
||||
* - Three-column layout (left sidebar + content + right TOC via DocPage)
|
||||
* - Background gradients
|
||||
* - Two-column flex wrapper (sidebar + main content)
|
||||
*
|
||||
* Uses ThreeColumnLayout for consistent column structure:
|
||||
* - Left: DocsSidebar (w-64, hidden lg:block)
|
||||
* - Center: Page content (flex-1)
|
||||
* - Right: Handled by DocPage component
|
||||
*
|
||||
* Pages handle their own:
|
||||
* - Breadcrumbs (manually specified)
|
||||
* - Article content
|
||||
* - TOC sidebar (on the right)
|
||||
* - TOC sidebar (on the right via DocPage)
|
||||
*
|
||||
* Features:
|
||||
* - Animated gradient background matching landing page
|
||||
|
|
@ -54,17 +59,16 @@ export default function DocsRootLayout({ children }: DocsRootLayoutProps) {
|
|||
ctaHref="/signup"
|
||||
/>
|
||||
|
||||
{/* Two-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 - Pages render here with their own article + TOC structure */}
|
||||
<main className="flex-1 min-w-0">
|
||||
{children}
|
||||
</main>
|
||||
{/* Three-column Documentation Layout */}
|
||||
<div className="relative z-10">
|
||||
<ThreeColumnLayout
|
||||
left={
|
||||
<div className="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} />
|
||||
</div>
|
||||
}
|
||||
center={children}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
* - Next Steps section at bottom
|
||||
* - Table of Contents sidebar on the right
|
||||
*
|
||||
* Uses ThreeColumnLayout for consistent column structure:
|
||||
* - Center: Article content (max-w-3xl)
|
||||
* - Right: Table of Contents (w-56, hidden xl:block)
|
||||
*
|
||||
* This component extracts common layout patterns from all doc pages,
|
||||
* reducing duplication and ensuring consistency.
|
||||
*
|
||||
|
|
@ -29,6 +33,7 @@ import { ReactNode } from 'react';
|
|||
import { Breadcrumb } from '@/components/docs/shared/Breadcrumb';
|
||||
import { DocsTOC } from '@/components/docs/layout/DocsTOC';
|
||||
import { SectionHeader, LinkCard, LinkCardGrid } from '@/components/docs/blocks';
|
||||
import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout';
|
||||
|
||||
/**
|
||||
* Next step link card configuration
|
||||
|
|
@ -92,45 +97,46 @@ export const DocPage = ({
|
|||
children,
|
||||
}: DocPageProps) => {
|
||||
return (
|
||||
<div className="flex">
|
||||
{/* Article Content */}
|
||||
<article className="flex-1 max-w-3xl mx-auto px-6 lg:px-12 py-12">
|
||||
{/* Breadcrumb Navigation */}
|
||||
<Breadcrumb items={breadcrumbItems} />
|
||||
<ThreeColumnLayout
|
||||
center={
|
||||
<article className="max-w-3xl mx-auto px-6 lg:px-12 py-12">
|
||||
{/* Breadcrumb Navigation */}
|
||||
<Breadcrumb items={breadcrumbItems} />
|
||||
|
||||
{/* Page Content (Hero + Sections) */}
|
||||
{children}
|
||||
{/* Page Content (Hero + Sections) */}
|
||||
{children}
|
||||
|
||||
{/* Next Steps Section */}
|
||||
<section id="next-steps" className="mb-12">
|
||||
<SectionHeader level={2} id="next-steps" className="mb-6">
|
||||
Next Steps
|
||||
</SectionHeader>
|
||||
{/* Next Steps Section */}
|
||||
<section id="next-steps" className="mb-12">
|
||||
<SectionHeader level={2} id="next-steps" className="mb-6">
|
||||
Next Steps
|
||||
</SectionHeader>
|
||||
|
||||
{nextSteps.description && (
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
{nextSteps.description}
|
||||
</p>
|
||||
)}
|
||||
{nextSteps.description && (
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
{nextSteps.description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<LinkCardGrid columns={2}>
|
||||
{nextSteps.links.map((link, index) => (
|
||||
<LinkCard
|
||||
key={index}
|
||||
href={link.href}
|
||||
title={link.title}
|
||||
description={link.description}
|
||||
accent={link.accent}
|
||||
/>
|
||||
))}
|
||||
</LinkCardGrid>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
{/* Right TOC Sidebar */}
|
||||
<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>
|
||||
<LinkCardGrid columns={2}>
|
||||
{nextSteps.links.map((link, index) => (
|
||||
<LinkCard
|
||||
key={index}
|
||||
href={link.href}
|
||||
title={link.title}
|
||||
description={link.description}
|
||||
accent={link.accent}
|
||||
/>
|
||||
))}
|
||||
</LinkCardGrid>
|
||||
</section>
|
||||
</article>
|
||||
}
|
||||
right={
|
||||
<div className="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} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* Three Column Layout - Core Wireframe Component
|
||||
*
|
||||
* Provides a consistent three-column layout structure used across the application.
|
||||
* This is the single source of truth for column widths, breakpoints, and responsive behavior.
|
||||
*
|
||||
* Column Structure:
|
||||
* - Left: w-64 (256px), hidden until lg breakpoint
|
||||
* - Center: flex-1 (flexible, takes remaining space)
|
||||
* - Right: w-56 (224px), hidden until xl breakpoint
|
||||
*
|
||||
* Usage Examples:
|
||||
*
|
||||
* 1. SubsectionNav (3 columns):
|
||||
* <ThreeColumnLayout
|
||||
* left={<Logo />}
|
||||
* center={<NavItems />}
|
||||
* right={<UserMenu />}
|
||||
* />
|
||||
*
|
||||
* 2. Docs Layout (2 columns - left + center):
|
||||
* <ThreeColumnLayout
|
||||
* left={<DocsSidebar />}
|
||||
* center={<DocPage />}
|
||||
* />
|
||||
*
|
||||
* 3. Doc Page (2 columns - center + right):
|
||||
* <ThreeColumnLayout
|
||||
* center={<Article />}
|
||||
* right={<DocsTOC />}
|
||||
* />
|
||||
*
|
||||
* Design Principles:
|
||||
* - Responsive breakpoints match Tailwind defaults (lg: 1024px, xl: 1280px)
|
||||
* - Column widths ensure visual alignment across all usage contexts
|
||||
* - Flexible center column adapts to available space
|
||||
* - Optional columns enable 1, 2, or 3 column layouts
|
||||
*/
|
||||
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
/**
|
||||
* Props for ThreeColumnLayout component
|
||||
*/
|
||||
export interface ThreeColumnLayoutProps {
|
||||
/** Left column content (w-64, hidden until lg breakpoint) */
|
||||
left?: ReactNode;
|
||||
|
||||
/** Center column content (flex-1, always visible) */
|
||||
center: ReactNode;
|
||||
|
||||
/** Right column content (w-56, hidden until xl breakpoint) */
|
||||
right?: ReactNode;
|
||||
|
||||
/** Additional classes for left column */
|
||||
leftClassName?: string;
|
||||
|
||||
/** Additional classes for center column */
|
||||
centerClassName?: string;
|
||||
|
||||
/** Additional classes for right column */
|
||||
rightClassName?: string;
|
||||
|
||||
/** Additional classes for container */
|
||||
containerClassName?: string;
|
||||
|
||||
/** Breakpoint for showing left column (default: 'lg') */
|
||||
leftBreakpoint?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
||||
|
||||
/** Breakpoint for showing right column (default: 'xl') */
|
||||
rightBreakpoint?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
||||
}
|
||||
|
||||
/**
|
||||
* Three Column Layout Component
|
||||
*
|
||||
* Core wireframe for consistent three-column layouts across the application.
|
||||
* Handles responsive behavior and provides customization via className props.
|
||||
*/
|
||||
export const ThreeColumnLayout = ({
|
||||
left,
|
||||
center,
|
||||
right,
|
||||
leftClassName = '',
|
||||
centerClassName = '',
|
||||
rightClassName = '',
|
||||
containerClassName = '',
|
||||
leftBreakpoint = 'lg',
|
||||
rightBreakpoint = 'xl',
|
||||
}: ThreeColumnLayoutProps) => {
|
||||
// Generate responsive visibility classes
|
||||
const leftHidden = `hidden ${leftBreakpoint}:block`;
|
||||
const rightHidden = `hidden ${rightBreakpoint}:block`;
|
||||
|
||||
return (
|
||||
<div className={`flex ${containerClassName}`}>
|
||||
{/* Left Column - w-64 (256px) */}
|
||||
{left && (
|
||||
<div className={`${leftHidden} w-64 shrink-0 ${leftClassName}`}>
|
||||
{left}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Center Column - flex-1 (flexible) */}
|
||||
<div className={`flex-1 min-w-0 ${centerClassName}`}>
|
||||
{center}
|
||||
</div>
|
||||
|
||||
{/* Right Column - w-56 (224px) */}
|
||||
{right && (
|
||||
<div className={`${rightHidden} w-56 shrink-0 ${rightClassName}`}>
|
||||
{right}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -9,17 +9,24 @@
|
|||
* - Active state indicator (purple color)
|
||||
* - Optional API Key input on the right
|
||||
* - Responsive (hamburger menu on mobile)
|
||||
* - Can be reused across landing app sections
|
||||
* - Three-column layout matching docs structure
|
||||
* - Customizable left/right slots
|
||||
*
|
||||
* Uses ThreeColumnLayout for consistent alignment with docs pages.
|
||||
* Columns align with docs layout at all screen widths.
|
||||
*
|
||||
* Usage:
|
||||
* <SubsectionNav
|
||||
* items={[...]}
|
||||
* currentPath="/docs/final"
|
||||
* showApiKeyInput={true}
|
||||
* leftSlot={<Logo />}
|
||||
* rightSlot={<UserMenu />}
|
||||
* />
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useState, useEffect, useRef, ReactNode } from 'react';
|
||||
import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout';
|
||||
|
||||
interface NavItem {
|
||||
label: string;
|
||||
|
|
@ -33,6 +40,10 @@ interface SubsectionNavProps {
|
|||
ctaHref?: string;
|
||||
onCtaClick?: () => void;
|
||||
showApiKeyInput?: boolean;
|
||||
/** Optional content for left column (w-64, hidden until lg) */
|
||||
leftSlot?: ReactNode;
|
||||
/** Optional content for right column (w-56, hidden until xl). If not provided and showApiKeyInput is true, API key input is used. */
|
||||
rightSlot?: ReactNode;
|
||||
}
|
||||
|
||||
const API_KEY_STORAGE = 'banatie_docs_api_key';
|
||||
|
|
@ -41,6 +52,8 @@ export const SubsectionNav = ({
|
|||
items,
|
||||
currentPath,
|
||||
showApiKeyInput = false,
|
||||
leftSlot,
|
||||
rightSlot,
|
||||
}: SubsectionNavProps) => {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
|
|
@ -110,32 +123,8 @@ export const SubsectionNav = ({
|
|||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<nav className="sticky top-0 z-40 bg-slate-950/80 backdrop-blur-sm border-b border-white/10">
|
||||
{/* Main Nav Container */}
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
<div className="flex items-center justify-between h-12">
|
||||
{/* Desktop Navigation */}
|
||||
<div className="hidden md:flex items-center gap-8">
|
||||
{items.map((item) => {
|
||||
const active = isActive(item.href);
|
||||
return (
|
||||
<a
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={`
|
||||
py-3 text-sm font-medium transition-colors
|
||||
${active ? 'text-purple-400' : 'text-gray-400 hover:text-white'}
|
||||
`}
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Right Side: API Key Input (Desktop) */}
|
||||
{showApiKeyInput && (
|
||||
// Desktop API Key Input Component
|
||||
const apiKeyComponent = showApiKeyInput && (
|
||||
<div className="hidden md:block relative" ref={dropdownRef}>
|
||||
<button
|
||||
onClick={() => setIsApiKeyExpanded(!isApiKeyExpanded)}
|
||||
|
|
@ -252,10 +241,37 @@ export const SubsectionNav = ({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
);
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<div className="md:hidden flex items-center ml-auto">
|
||||
return (
|
||||
<nav className="sticky top-0 z-40 bg-slate-950/80 backdrop-blur-sm border-b border-white/10">
|
||||
{/* Three-Column Layout */}
|
||||
<ThreeColumnLayout
|
||||
left={leftSlot}
|
||||
center={
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
<div className="flex items-center justify-between h-12">
|
||||
{/* Desktop Navigation Items */}
|
||||
<div className="hidden md:flex items-center gap-8">
|
||||
{items.map((item) => {
|
||||
const active = isActive(item.href);
|
||||
return (
|
||||
<a
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={`
|
||||
py-3 text-sm font-medium transition-colors
|
||||
${active ? 'text-purple-400' : 'text-gray-400 hover:text-white'}
|
||||
`}
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<div className="md:hidden flex items-center ml-auto">
|
||||
<button
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
className="p-2 text-gray-400 hover:text-white transition-colors"
|
||||
|
|
@ -284,9 +300,12 @@ export const SubsectionNav = ({
|
|||
)}
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
right={rightSlot || apiKeyComponent}
|
||||
/>
|
||||
|
||||
{/* Decorative Wave Line */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-px overflow-hidden">
|
||||
|
|
|
|||
Loading…
Reference in New Issue