diff --git a/components/Header.tsx b/components/Header.tsx index 1fc87e1..308ee4d 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,12 +1,12 @@ 'use client' -import { useEffect, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import Link from 'next/link' import { usePathname } from 'next/navigation' -import { useTheme } from './ThemeProvider' +import { useTheme, type Theme } from './ThemeProvider' import { useXangaLayoutOptional } from '@/components/xanga/XangaLayoutContext' -function ThemeIcon({ theme }: { theme: 'light' | 'dark' | 'xanga' }) { +function ThemeIcon({ theme }: { theme: Theme }) { if (theme === 'light') { return ( void -}) { - const label = value === 'xanga' ? 'Xanga' : value === 'dark' ? 'Dark' : 'Light' +const THEME_OPTIONS: { value: Theme; label: string }[] = [ + { value: 'light', label: 'Light' }, + { value: 'dark', label: 'Dark' }, + { value: 'xanga', label: 'Xanga' }, +] + +function themeLabel(theme: Theme) { + return theme === 'xanga' ? 'Xanga' : theme === 'dark' ? 'Dark' : 'Light' +} + +// Shows only the active theme's icon. Clicking it opens a small tray/menu +// with all 3 theme options; picking one applies the theme, closes the tray, +// and swaps the trigger icon to match. +function ThemeMenu({ theme, setTheme }: { theme: Theme; setTheme: (t: Theme) => void }) { + const [open, setOpen] = useState(false) + const containerRef = useRef(null) + const triggerRef = useRef(null) + + useEffect(() => { + if (!open) return + + function handlePointerDown(event: MouseEvent) { + if (containerRef.current && !containerRef.current.contains(event.target as Node)) { + setOpen(false) + } + } + function handleKeyDown(event: KeyboardEvent) { + if (event.key === 'Escape') { + setOpen(false) + triggerRef.current?.focus() + } + } + + document.addEventListener('mousedown', handlePointerDown) + document.addEventListener('keydown', handleKeyDown) + return () => { + document.removeEventListener('mousedown', handlePointerDown) + document.removeEventListener('keydown', handleKeyDown) + } + }, [open]) + return ( - {label} - - {label} - - +
+ + + {open && ( +
+ {THEME_OPTIONS.map((option) => { + const isActive = theme === option.value + return ( + + ) + })} +
+ )} +
) } @@ -162,6 +223,29 @@ function DesktopNavLink({ ) } +// Distinct from the hamburger icon on purpose: this represents "bring the +// sidebar panel back", not "open a menu". The highlighted panel + chevron +// point toward whichever side (left/right) the sidebar will reappear on. +function RestoreSidebarIcon({ side }: { side: 'left' | 'right' }) { + const panelX = side === 'left' ? 3 : 15 + const chevronPath = side === 'left' ? 'M8.5 9l-2.5 3 2.5 3' : 'M15.5 9l2.5 3-2.5 3' + return ( + + ) +} + function HamburgerIcon({ open }: { open: boolean }) { return ( -
-
- {(['light', 'dark'] as const).map((t) => ( - setTheme(t)} - /> - ))} - {showCollapsedIcon && layout ? ( - - ) : ( - setTheme('xanga')} - /> - )} -
+
+ {showCollapsedIcon && layout && ( + + )} + {/* Hamburger toggle for mobile navigation */}