'use client' import { useAuth } from '@thedaviddias/auth' import { Menu, Search, UserPlus } from 'lucide-react' import Link from 'next/link' import { useEffect, useState } from 'react' import { useAnalyticsEvents } from '@/components/analytics-tracker' import { GithubStars } from '@/components/stats/github-stars' import { useSearch } from '@/hooks/use-search' import { getRoute } from '@/lib/routes' import { NavLink } from './header-nav-link' import { DesktopSearchForm, MobileSearchOverlay } from './header-search' import { UserDropdownMenu } from './header-user-menu' import { MobileDrawer } from './mobile-drawer' /** * Generates a user slug from user data * * @param user - User object from auth * @returns string - Generated user slug */ function generateSlugFromUser(user: any): string { if (!user) return '' // Try to get username from user_metadata const username = user.user_metadata?.user_name if (username) { return username } // Fallback to user ID if no username available return user.id } /** * Main header component with navigation, search, and user actions * * @returns JSX.Element - Header component */ export function Header() { const [showMobileSearch, setShowMobileSearch] = useState(false) const [showMobileDrawer, setShowMobileDrawer] = useState(false) const [showAutocomplete, setShowAutocomplete] = useState(false) const [showMobileAutocomplete, setShowMobileAutocomplete] = useState(false) const { searchQuery, setSearchQuery, handleSearch } = useSearch() const { user, isLoaded, signOut } = useAuth() const { trackSearch } = useAnalyticsEvents() const userSlug = user ? generateSlugFromUser(user) : '' const isProfilePrivate = Boolean(user?.publicMetadata?.isProfilePrivate) // Check if profile is incomplete (needs name or username to be visible) const needsNameOrUsername = Boolean( user && !user.user_metadata?.full_name && !user.user_metadata?.user_name && !user.publicMetadata?.github_username ) // Auto-focus mobile search input when it appears and handle escape key useEffect(() => { if (showMobileSearch) { // Prevent body scroll when search is open document.body.style.overflow = 'hidden' } else { document.body.style.overflow = '' } return () => { document.body.style.overflow = '' } }, [showMobileSearch]) /** * Handles form submission for search * * @param e - Form event */ const onSubmit = (e: React.FormEvent) => { e.preventDefault() if (searchQuery.trim()) { // Track search submission trackSearch( searchQuery, 0, showMobileSearch ? 'header-mobile-search' : 'header-desktop-search' ) handleSearch(searchQuery) setSearchQuery('') setShowAutocomplete(false) setShowMobileAutocomplete(false) if (showMobileSearch) { setShowMobileSearch(false) setShowMobileAutocomplete(false) } } } /** * Handles desktop search input focus */ const handleInputFocus = () => { setShowAutocomplete(true) } /** * Handles mobile search input focus */ const handleMobileInputFocus = () => { setShowMobileAutocomplete(true) } /** * Handles desktop search input change * * @param e - Input change event */ const handleSearchChange = (e: React.ChangeEvent) => { setSearchQuery(e.target.value) if (!showAutocomplete) setShowAutocomplete(true) } /** * Handles mobile search input change * * @param e - Input change event */ const handleMobileSearchChange = (e: React.ChangeEvent) => { setSearchQuery(e.target.value) if (!showMobileAutocomplete) setShowMobileAutocomplete(true) } return ( <>
{/* Logo + Menu - Left */}
{/* Mobile menu toggle */} llms.txt hub
{/* Search - Center (prominent on desktop) */} setShowAutocomplete(false)} onAutocompleteSelect={() => { setShowAutocomplete(false) setSearchQuery('') }} /> {/* Navigation + Actions - Right */}
{/* Desktop navigation */} {/* Mobile search icon */}
{!isLoaded ? (
) : user ? ( ) : ( Sign Up )}
{/* Mobile search overlay */} { setShowMobileSearch(false) setShowMobileAutocomplete(false) }} onAutocompleteSelect={() => { setShowMobileAutocomplete(false) setShowMobileSearch(false) setSearchQuery('') }} />
{/* Mobile Drawer */} setShowMobileDrawer(false)} featuredCount={6} /> ) }