Skip to content

feat(ui): adopt the Nebari Design registry header and theme hook - #4

Merged
jbouder merged 1 commit into
mainfrom
feat/adopt-nebari-design-header
Aug 13, 2026
Merged

feat(ui): adopt the Nebari Design registry header and theme hook#4
jbouder merged 1 commit into
mainfrom
feat/adopt-nebari-design-header

Conversation

@jbouder

@jbouder jbouder commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Adopts the shared header and theme hook from the nebari-design shadcn registry, mirroring nebari-landing's canonical Header.

  • Added ui/components.json with the @nebari registry and installed @nebari/navigation-menu, @nebari/dropdown-menu, @nebari/button, and @nebari/use-theme-preference via npx shadcn@latest add. The local button.tsx/spinner.tsx were already identical to the registry versions; the local dropdown-menu.tsx was upgraded to the registry version (its only consumer was the old header). The local avatar.tsx is kept — the registry has no avatar item.
  • Extracted the header out of layout.tsx into src/components/header.tsx, built on MenuBarBrand / MenuBarNav / MenuBarActions. The app's Dashboard/Apps/Metrics nav links are preserved as registry NavLinks (react-router Link via the render prop, active state from useLocation). The profile menu keeps the app's real auth wiring: getUser() for name/email, Keycloak logout() for sign-out, and the existing "Authentication disabled" fallback when auth is off (no sign-out item in that case).
  • Defined the shared semantic tokens (--header-border, --header-foreground, --header-action-hover, --notification-badge, --sign-out-foreground--header-background already existed) for light and dark in src/index.css, with their @theme --color-* mappings, values copied from nebari-landing.
  • Replaced the local useThemePreference hook with the registry hook + ThemeProvider (installed theme-provider.tsx), keeping the existing nebari-apps:themeMode storage key, and inlined the themeBootstrapScript-generated pre-paint script in index.html.
  • Added a vitest + testing-library unit suite (ui/tests/) — the repo previously had no JS test infra — and wired npm test into the CI ui job.

Acceptance criteria (nebari-dev/nebari-design#131)

  • @nebari registry added to components.json; header rebuilt on MenuBarBrand/MenuBarActions from @nebari/navigation-menu
  • h-14 bar, pl-4, logo h-8 w-auto, MenuBarBrand href="/" with aria-label="Go to homepage"
  • Header styled only with --header-* semantic tokens in light and dark; --notification-badge and --sign-out-foreground defined with --color-* mappings
  • Local theme hook deleted and replaced with @nebari/use-theme-preference; app wrapped in the registry ThemeProvider; bootstrap script inlined in index.html head; existing nebari-apps:themeMode storage key preserved
  • Notifications bell: skipped — this app has no notifications feature (toasts only), per the issue's "only if the app already has notifications"
  • Profile menu: avatar + name + chevron trigger, name/email section, w-[248px] p-2, red sign-out with LogOut icon using text-sign-out-foreground
  • Theme toggle inside the profile menu as a menuitemradio segmented control (Light/Dark/System) wired to the registry hook
  • Unit tests: menuitemradio + aria-checked assertions, theme-change callbacks, sign-out, no-auth fallback (there were no pre-existing JS tests to migrate)
  • Attach light/dark header screenshots

Test plan

  • npm run build (tsc -b + vite build, now also type-checks tests/) — passes
  • npm test (vitest, 7 tests) — passes

Pre-existing note: vite build warns about a >500 kB chunk; unrelated to this change.

Part of nebari-dev/nebari-design#131

🤖 Generated with Claude Code

https://claude.ai/code/session_012Xb4VPMBJ4ksnCiChJpVzu

Adopt the shared header and theme hook from the nebari-design shadcn
registry (nebari-dev/nebari-design#131), mirroring nebari-landing's
canonical Header:

- Add components.json with the @Nebari registry and install
  @nebari/navigation-menu, @nebari/dropdown-menu, @nebari/button, and
  @nebari/use-theme-preference (button was already identical; the local
  dropdown-menu is upgraded to the registry version).
- Extract the header out of layout.tsx into components/header.tsx built
  on MenuBarBrand/MenuBarNav/MenuBarActions: h-14 bar, h-8 logo linking
  home, the app's Dashboard/Apps/Metrics nav links preserved as registry
  NavLinks, and a 248px profile menu with name/email, a Light/Dark/System
  menuitemradio segmented theme control, and a red sign-out item wired to
  the existing Keycloak logout.
- Style the header only with the shared semantic tokens (--header-*,
  --notification-badge, --sign-out-foreground) copied from
  nebari-landing, plus their @theme --color-* mappings.
- Replace the local useThemePreference hook with the registry hook +
  ThemeProvider (keeping the existing nebari-apps:themeMode storage key)
  and inline the generated pre-paint bootstrap script in index.html.
- Add a vitest + testing-library unit suite for the header (menuitemradio
  aria-checked assertions included) and run it in CI.

The app has no notifications feature, so the notifications bell is
intentionally omitted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Xb4VPMBJ4ksnCiChJpVzu
@jbouder
jbouder merged commit d1b5015 into main Aug 13, 2026
6 checks passed
@jbouder
jbouder deleted the feat/adopt-nebari-design-header branch August 13, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant