Files
GearBox/.planning/phases/36-admin-role-panel-foundation/36-UI-SPEC.md
Jean-Luc Makiola 94e2a8c019 plan(36): admin role & panel foundation — 2 plans ready
- 36-RESEARCH.md: schema migration, requireAdmin middleware, /api/auth/me
  surface, client routing patterns, grant script, wave breakdown
- 36-UI-SPEC.md: admin shell layout, sidebar disabled nav items, UserMenu
  admin link, palette and responsive notes
- 36-01-PLAN.md (wave 1): isAdmin schema column + Drizzle migration,
  requireAdmin middleware, /api/auth/me isAdmin field, /api/admin placeholder
  route, scripts/grant-admin.ts
- 36-02-PLAN.md (wave 2): AuthState isAdmin type, /admin client route with
  sidebar shell, admin/index.tsx placeholder, UserMenu admin link
- STATE.md: updated to Phase 36, ready to execute, 2 plans

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 20:43:12 +02:00

4.4 KiB

Phase 36: Admin Role & Panel Foundation — UI Design Contract

Phase: 36 — Admin Role & Panel Foundation Created: 2026-04-19 Status: Ready for planning


Design Intent

The admin panel is a protected, minimal shell consistent with the app's existing light/airy aesthetic. It is not a distinct visual world — it reuses the same white background, gray borders, and sans-serif type as the rest of GearBox. The only indicator of admin context is the sidebar and a subtle "Admin" badge or heading.


Layout

┌─────────────────────────────────────────────────────────┐
│ TopNav (existing — unchanged)                           │
├──────────────┬──────────────────────────────────────────┤
│ Sidebar      │ Main content area                        │
│ w-56         │ flex-1, min-h                            │
│ border-r     │                                          │
│              │ <Outlet /> (placeholder for now)         │
│ Admin        │                                          │
│ ──────────   │                                          │
│ □ Items      │                                          │
│ □ Tags       │                                          │
│              │                                          │
└──────────────┴──────────────────────────────────────────┘

Component Specs

Admin Shell (src/client/routes/admin.tsx)

Outer wrapper: flex min-h-[calc(100vh-3.5rem)] (full height minus TopNav 3.5rem/14)

Sidebar:

  • w-56 border-r border-gray-100 bg-white p-4 flex flex-col gap-1
  • Header: text-xs font-semibold text-gray-400 uppercase tracking-wide mb-3 — "Admin"
  • Nav items: flex items-center gap-2 px-3 py-2 rounded-lg text-sm (disabled state below)

Main content:

  • flex-1 p-6 bg-gray-50
  • Contains <Outlet />

Sidebar Nav Items (Disabled / Coming Soon)

Both "Items" and "Tags" are disabled in this phase.

Disabled item style:

flex items-center gap-2 px-3 py-2 rounded-lg text-sm
text-gray-300 cursor-not-allowed

Icon + label + badge:

<div className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm text-gray-300 cursor-not-allowed">
  <LucideIcon name="package" size={16} />
  <span>Items</span>
  <span className="ml-auto text-xs bg-gray-100 text-gray-400 px-1.5 py-0.5 rounded">Soon</span>
</div>

Icons to use:

  • Items → "package" (matches existing collection icon)
  • Tags → "tag"

Admin Index Placeholder (src/client/routes/admin/index.tsx)

Simple centered placeholder:

<div className="flex flex-col items-center justify-center h-64 text-center">
  <LucideIcon name="shield" size={32} className="text-gray-300 mb-3" />
  <p className="text-sm text-gray-500">Admin Panel</p>
  <p className="text-xs text-gray-400 mt-1">Select a section from the sidebar</p>
</div>

Position: before Profile link (top of menu). Only rendered when auth?.user?.isAdmin === true.

{auth?.user?.isAdmin && (
  <>
    <Link
      to="/admin"
      onClick={() => setOpen(false)}
      className="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
    >
      <LucideIcon name="shield" size={16} className="text-gray-400" />
      Admin
    </Link>
    <div className="border-t border-gray-100 my-1" />
  </>
)}

Palette (existing conventions)

Token Value Usage
bg-white #ffffff Sidebar, TopNav
bg-gray-50 #f9fafb Page background, main content
border-gray-100 #f3f4f6 Sidebar border, dividers
text-gray-900 #111827 Active/primary text
text-gray-500 #6b7280 Secondary text
text-gray-300 #d1d5db Disabled items
text-gray-400 #9ca3af Icons, muted labels

Responsive

  • Sidebar is always visible (no mobile collapse in this phase — admin is desktop-only usage)
  • hidden md:flex wrapper if needed to keep mobile layout clean, but admin route is inherently desktop

UI-SPEC COMPLETE