banatie-service/apps/landing/src/components/shared/SubsectionNav.tsx

181 lines
5.9 KiB
TypeScript

'use client';
/**
* Subsection Navigation Component
*
* Reusable navigation bar for documentation and other subsections
* Features:
* - Dark nav bar with decorative wave line
* - Active state indicator (purple color)
* - Responsive (hamburger menu on mobile)
* - 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"
* leftSlot={<Logo />}
* rightSlot={<UserMenu />}
* />
*/
import { useState, ReactNode } from 'react';
import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout';
interface NavItem {
label: string;
href: string;
}
interface SubsectionNavProps {
items: NavItem[];
currentPath: string;
ctaText?: string;
ctaHref?: string;
onCtaClick?: () => void;
/** Optional content for left column (w-64, hidden until lg) */
leftSlot?: ReactNode;
/** Optional content for right column (w-56, hidden until xl) */
rightSlot?: ReactNode;
}
export const SubsectionNav = ({ items, currentPath, leftSlot, rightSlot }: SubsectionNavProps) => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const isActive = (href: string) => currentPath.startsWith(href);
return (
<nav className="sticky top-0 z-40 bg-slate-950/80 backdrop-blur-sm border-b border-white/10 relative">
{/* 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"
aria-label="Toggle menu"
>
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
{mobileMenuOpen ? (
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
) : (
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 6h16M4 12h16M4 18h16"
/>
)}
</svg>
</button>
</div>
</div>
</div>
}
/>
{/* Right Slot - Absolutely Positioned */}
{rightSlot && (
<div className="absolute top-0 right-0 h-12 flex items-center pr-0 hidden xl:flex overflow-visible">
{rightSlot}
</div>
)}
{/* Decorative Wave Line */}
<div className="absolute bottom-0 left-0 right-0 h-px overflow-hidden">
<svg
className="absolute inset-0 w-full h-full"
viewBox="0 0 1200 2"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient id="wave-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="rgb(147, 51, 234)" stopOpacity="0.3" />
<stop offset="50%" stopColor="rgb(8, 145, 178)" stopOpacity="0.5" />
<stop offset="100%" stopColor="rgb(147, 51, 234)" stopOpacity="0.3" />
</linearGradient>
</defs>
<path
d="M0,1 Q300,0 600,1 T1200,1"
stroke="url(#wave-gradient)"
strokeWidth="1"
fill="none"
className="animate-pulse"
/>
</svg>
</div>
{/* Mobile Menu Overlay */}
{mobileMenuOpen && (
<div className="md:hidden border-t border-white/10 bg-slate-900/95 backdrop-blur-sm">
<div className="px-6 py-4">
{/* ApiKeyWidget - Mobile */}
{rightSlot && (
<>
<div className="flex justify-end mb-3">
{rightSlot}
</div>
{/* Visual separator */}
<div className="border-t border-white/10 mb-3" />
</>
)}
{/* Navigation items */}
<div className="space-y-2">
{items.map((item) => {
const active = isActive(item.href);
return (
<a
key={item.href}
href={item.href}
onClick={() => setMobileMenuOpen(false)}
className={`
block px-4 py-3 rounded-lg text-sm font-medium transition-colors
${active ? 'bg-purple-500/10 text-purple-400' : 'text-gray-400 hover:text-white hover:bg-white/5'}
`}
>
{item.label}
</a>
);
})}
</div>
</div>
</div>
)}
</nav>
);
};