/**
* AppNav — top navigation bar (phone) / left sidebar (tablet/desktop).
*
* UI-SPEC §AppNav:
* - Phone: 48px top bar, app name "FamilySync" left, user color swatch right
* - Tablet/Desktop: 240px left sidebar, app name + ColorLegend
* - Accent colors NOT on chrome (60/30/10 split)
*
* Reviewer note (UI-SPEC §Post-Verification):
* - Phone-nav avatar/color swatch needs aria-label + title (icon-only affordance)
* - Grid is primary focal point; AppNav is secondary chrome
*/
import { NavLink } from 'react-router'
import { CalendarDays, List } from 'lucide-react'
import { ColorLegend, type LegendMember } from './ColorLegend.js'
interface AppNavProps {
members?: LegendMember[]
currentUserColor?: string
currentUserName?: string
/** Called when the user avatar is tapped — opens the Settings sheet. */
onOpenSettings?: () => void
}
export function AppNav({ members = [], currentUserColor, currentUserName, onOpenSettings }: AppNavProps) {
const isMobile = typeof window !== 'undefined' && window.matchMedia('(max-width: 767px)').matches
if (isMobile) {
return (
)
}
return (
)
}
/** Phone: 48px top bar — app name left, user avatar right */
function PhoneNav({
currentUserColor,
currentUserName,
onOpenSettings,
}: {
currentUserColor?: string
currentUserName?: string
onOpenSettings?: () => void
}) {
const displayName = currentUserName ?? 'User'
const color = currentUserColor ?? 'var(--color-member-0)'
return (
{/* App name */}
FamilySync
{/* User avatar — promoted to button to open Settings sheet (D-09) */}
)
}
/** Tablet/Desktop: 240px left sidebar — app name + nav links + color legend + avatar */
function DesktopNav({
members,
currentUserColor,
currentUserName,
onOpenSettings,
}: {
members: LegendMember[]
currentUserColor?: string
currentUserName?: string
onOpenSettings?: () => void
}) {
const navLinkStyle = ({ isActive }: { isActive: boolean }): React.CSSProperties => ({
display: 'flex',
alignItems: 'center',
gap: '10px',
padding: 'var(--space-2) var(--space-3, 12px)',
borderRadius: 'var(--space-1, 4px)',
textDecoration: 'none',
fontSize: 'var(--text-body-size, 15px)',
fontWeight: isActive ? 600 : 400,
color: isActive ? 'var(--color-member-0)' : 'var(--color-text-primary)',
background: isActive ? 'color-mix(in srgb, var(--color-member-0) 10%, transparent)' : 'transparent',
minHeight: '44px',
transition: 'color 0.1s ease, background 0.1s ease',
})
return (
)
}