diff --git a/apps/web/src/components/AppHeader.tsx b/apps/web/src/components/AppHeader.tsx index da11edb..2e5990c 100644 --- a/apps/web/src/components/AppHeader.tsx +++ b/apps/web/src/components/AppHeader.tsx @@ -5,10 +5,107 @@ import { Button } from '@tpmjs/ui/Button/Button'; import { Header } from '@tpmjs/ui/Header/Header'; import { Icon } from '@tpmjs/ui/Icon/Icon'; import Link from 'next/link'; -import { useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { MobileMenu } from './MobileMenu'; import { ThemeToggle } from './ThemeToggle'; +interface DropdownItem { + href: string; + label: string; + description?: string; + external?: boolean; +} + +interface NavDropdownProps { + label: string; + items: DropdownItem[]; +} + +function NavDropdown({ label, items }: NavDropdownProps): React.ReactElement { + const [isOpen, setIsOpen] = useState(false); + const dropdownRef = useRef(null); + + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + } + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + return ( +
+ + {isOpen && ( +
+ {items.map((item) => + item.external ? ( + setIsOpen(false)} + > +
+
{item.label}
+ {item.description && ( +
{item.description}
+ )} +
+ +
+ ) : ( + setIsOpen(false)} + > +
{item.label}
+ {item.description && ( +
{item.description}
+ )} + + ) + )} +
+ )} +
+ ); +} + +const developerItems: DropdownItem[] = [ + { href: '/docs', label: 'Documentation', description: 'Guides and tutorials' }, + { href: '/sdk', label: 'SDK', description: 'Build with our SDK' }, + { href: '/spec', label: 'Specification', description: 'TPMJS tool format' }, + { href: '/integrations', label: 'Integrations', description: 'Connect your tools' }, +]; + +const resourceItems: DropdownItem[] = [ + { href: '/how-it-works', label: 'How It Works', description: 'Learn the basics' }, + { href: '/faq', label: 'FAQ', description: 'Common questions' }, + { href: '/changelog', label: 'Changelog', description: 'Latest updates' }, + { href: '/stats', label: 'Stats', description: 'Platform metrics' }, +]; + /** * Shared application header used across all pages */ @@ -32,8 +129,8 @@ export function AppHeader(): React.ReactElement { actions={ <> {/* Desktop Navigation - hidden on mobile */} -
- {/* Core Product Links */} +
+ {/* Primary Links */} - - - - - - - + + {/* Dropdown Menus */} + + {/* Separator */} - | + | - {/* Developer Section */} - - - - - - - - - - - - - - - - - - + {/* Social & Utilities */} @@ -114,21 +167,36 @@ export function AppHeader(): React.ReactElement { href="https://github.com/tpmjs/tpmjs" target="_blank" rel="noopener noreferrer" - className="text-foreground hover:text-foreground transition-colors" + className="p-2 text-foreground hover:text-foreground-secondary transition-colors" + aria-label="View on GitHub" > + + {/* Auth Section - Segmented */} + | {session ? ( - - - + <> + + + + + + + ) : (
- {/* Mobile Hamburger Button - shown on mobile only */} + {/* Mobile Hamburger Button - shown on mobile/tablet */}
- {/* Navigation links */} -