/**
* 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, ShieldCheck } 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;
/** When true, renders the Admin nav entry (ShieldCheck). UX gating only (D-03). */
isAdmin?: boolean;
}
export function AppNav({
members = [],
currentUserColor,
currentUserName,
onOpenSettings,
isAdmin = false,
}: 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,
isAdmin = false,
}: {
members: LegendMember[];
currentUserColor?: string;
currentUserName?: string;
onOpenSettings?: () => void;
isAdmin?: boolean;
}) {
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 (
);
}