"use client"; import Link from "next/link"; import { useEffect, useState } from "react"; import { MenuIcon } from "@/components/icons"; import { SettingsDialog } from "@/components/SettingsDialog"; import { ThemeToggle } from "@/components/ThemeToggle"; import { useI18n } from "@/lib/i18n"; import { sidebarOpen } from "@/lib/nav"; import { OPEN_SETTINGS_EVENT } from "@/lib/ui-events"; import { cn } from "@/lib/utils"; /** * Minimal, sticky frosted top bar: brand on the left, quiet actions on the * right. The phone layout keeps the brand compact and relies on the tab bar * for navigation. */ export function AppHeader({ className, compact = false }: { className?: string; compact?: boolean }) { const { t } = useI18n(); const [settingsOpen, setSettingsOpen] = useState(false); useEffect(() => { const onOpen = () => setSettingsOpen(true); window.addEventListener(OPEN_SETTINGS_EVENT, onOpen); return () => window.removeEventListener(OPEN_SETTINGS_EVENT, onOpen); }, []); // Restore the desktop sidebar width preference once, on the client. useEffect(() => { void import("@/components/Sidebar").then((module) => module.sidebarCollapse.hydrate()); }, []); return ( <>
, // which has no horizontal padding — the -mx-4 made it 16px wider // than the viewport and caused a horizontal scroll on phones. "glass sticky top-0 z-40 mb-6 px-4 lg:hidden sm:px-6", className, )} >
{/* eslint-disable-next-line @next/next/no-img-element -- static app icon, no optimisation needed */} Freezmo {!compact ? ( {t("header.tagline")} ) : null}
{/* Settings lives in the tab bar and the drawer; the old header gear was the same control a third time. */}
setSettingsOpen(false)} /> ); }