theme and navigation components
Header and Navbar stay on authenticated screens. Theme widgets live in the header.
Related: UI Components, Theme System, Base UI Components.
Navigation component architecture#
Component hierarchy#
flowchart TD AA["AuthenticatedApp"] --> Header AA --> Navbar Header --> Theme["ThemeSelectorDialog"] Header --> Stats["Link /stats"] Header --> Logout["handleLogout"]
Header component#
Component structure#
flowchart LR Title["h1 JPortal"] --> Actions["stats ThemeSelectorDialog logout"]
Props: setIsAuthenticated, setIsDemoMode.
Logout removes username, password, attendanceData, clears auth and demo, navigate("/login").
FairyLights exists in the file but is commented out in the render.
Navbar component#
Navigation configuration#
flowchart LR N["Navbar"] --> A["/attendance"] N --> G["/grades"] N --> E["/exams"] N --> S["/subjects"] N --> P["/profile"]
navItems in Navbar.jsx. Icons via ?react from public/icons/. Active: opacity-100, bg-primary, fill-primary-foreground. Fixed bottom-0 left-0.
Theme selector dialog#
Component architecture#
flowchart TD Btn["header button"] --> Gestures["click hold swipe"] Gestures --> Store["useThemeStore"] Dialog["Dialog"] --> Toggle["ThemeToggle"] Dialog --> Grid["ThemeSelector"]
| Gesture | Action |
|---|---|
| Click under 500ms | Open dialog |
| Hold 500ms | Toggle light/dark |
| Swipe X or Y past 50px | Next or previous preset |
Refs: holdTimeoutRef, isHoldingRef, touchStartRef, hasSwipedRef.
Event handler implementation#
flowchart TD Down["pointer down"] --> Timer["500ms hold"] Timer --> Mode["toggleTheme"] Move["pointer move"] --> Swipe["changeToTheme"] Up["pointer up"] --> Open["open dialog unless hold or swipe"]
Theme toggle component#
Component flow#
flowchart TD Click["Button click"] --> XY["clientX clientY"] XY --> Toggle["toggleTheme"] Toggle --> Icon["Sun or Moon"]
CSS variables and theme tokens#
Variable mapping architecture#
flowchart TD Root["--background"] --> Map["@theme inline --color-background"] Map --> Util["bg-background"]
Radius: --radius-sm = calc(var(--radius) - 4px) and siblings. Fonts: --font-sans, --font-mono, --font-serif.
Grade and marks tokens in index.css (--color-grade-aa, --color-marks-outstanding, …). Marks bands in MarksCard are 80/60/40, not 90/70/50.
View transition animations#
Animation implementation#
sequenceDiagram participant Btn as ThemeToggle participant CSS as --x --y participant VT as startViewTransition Btn->>CSS: set click coords Btn->>VT: apply .dark VT-->>Btn: expand / shrink clip-path 1s
@supports (view-transition-name: none). Without it, the class flips with no animation.
Global styling utilities#
Body bg-background text-foreground. Scrollbars hidden. Snap utilities .snap-y, .snap-mandatory, .snap-start for the attendance sheet.
Component integration summary#
flowchart TD Header --> Theme Theme --> Store["theme-store"] Store --> CSS["CSS variables"] Navbar --> Routes["HashRouter NavLink"]