diff --git a/docs/superpowers/specs/2026-03-18-admin-pages-design.md b/docs/superpowers/specs/2026-03-18-admin-pages-design.md
index 0796b37..8883577 100644
--- a/docs/superpowers/specs/2026-03-18-admin-pages-design.md
+++ b/docs/superpowers/specs/2026-03-18-admin-pages-design.md
@@ -9,9 +9,9 @@ Transfer the admin section from cameleer3-server UI to the design system project
## New Design System Components
-### 1. MultiSelect (primitive)
+### 1. MultiSelect (composite)
-Dropdown trigger that opens a popover with searchable checkbox list and "Apply" action.
+Dropdown trigger that opens a positioned panel with searchable checkbox list and "Apply" action.
**Props:**
```typescript
@@ -32,18 +32,25 @@ interface MultiSelectProps {
```
**Behavior:**
-- Click trigger → popover opens below with search input + checkbox list + "Apply (N)" footer
+- Click trigger → panel opens below with search input + checkbox list + "Apply (N)" footer
- Search filters options by label (case-insensitive)
- Checkboxes toggle selection; changes are local until "Apply" is clicked
-- Apply calls `onChange` with selected values and closes popover
-- Click outside or Escape closes without applying
+- Apply calls `onChange` with selected values and closes panel
+- Click outside or Escape closes without applying (discards pending changes)
- Trigger shows count: "2 selected" or placeholder when empty
+- Arrow keys navigate checkbox list, Space toggles focused item, Tab moves between search/list/apply
+- Panel has max-height with scroll for long option lists
+
+**Accessibility:**
+- Trigger: `role="combobox"`, `aria-expanded`, `aria-haspopup="listbox"`
+- Option list: `role="listbox"`, options have `role="option"` with `aria-selected`
+- Search input: `aria-label="Filter options"`
**Implementation:**
-- New directory: `src/design-system/primitives/MultiSelect/`
-- Uses Popover composite for positioning
+- New directory: `src/design-system/composites/MultiSelect/`
+- Manages its own open/close state and positioning (does NOT wrap Popover — needs controlled close behavior to distinguish apply vs. discard)
+- Uses portal for the dropdown panel to avoid overflow clipping
- CSS Modules with design tokens
-- No forwardRef needed (not a native form control)
### 2. ConfirmDialog (composite)
@@ -57,10 +64,11 @@ interface ConfirmDialogProps {
onConfirm: () => void
title?: string // default: "Confirm Deletion"
message: string // e.g., "Delete user 'alice'? This cannot be undone."
- confirmText: string // text the user must type to enable confirm button
+ confirmText: string // text the user must type to enable confirm button (must be non-empty)
confirmLabel?: string // default: "Delete"
cancelLabel?: string // default: "Cancel"
- variant?: 'danger' | 'warning' // default: 'danger'
+ variant?: 'danger' | 'warning' | 'info' // default: 'danger'
+ loading?: boolean // default: false — disables buttons, shows pending state
className?: string
}
```
@@ -71,7 +79,8 @@ interface ConfirmDialogProps {
- Confirm button disabled until input matches `confirmText` exactly
- Input clears on open
- Enter submits when enabled; Escape closes
-- Confirm button uses danger/warning variant styling
+- Confirm button uses danger/warning/info variant styling (matches AlertDialog pattern)
+- When `loading` is true, both buttons are disabled
**Implementation:**
- New directory: `src/design-system/composites/ConfirmDialog/`
@@ -95,14 +104,14 @@ interface InlineEditProps {
**Behavior:**
- **Display mode:** Shows value as text with subtle edit icon (pencil). Clicking text or icon enters edit mode.
-- **Edit mode:** Input field with current value. Enter or blur saves. Escape cancels (reverts to original value).
+- **Edit mode:** Input field with current value. Enter saves. Escape cancels (reverts to original value). Blur cancels (same as Escape — prevents accidental saves when clicking away).
- If saved value is empty and placeholder exists, display mode shows placeholder in muted style.
-- No save/cancel buttons — Enter saves, Escape cancels (lightweight inline pattern).
+- No save/cancel buttons — Enter saves, Escape/blur cancels (lightweight inline pattern).
**Implementation:**
- New directory: `src/design-system/primitives/InlineEdit/`
-- Uses `forwardRef` (wraps an input)
-- Manages internal editing state
+- No forwardRef — the component manages its own input internally (the input only exists in edit mode, so a forwarded ref would be null in display mode)
+- Manages internal editing state with useState
## Admin Pages
@@ -117,11 +126,25 @@ interface InlineEditProps {
All pages use the standard AppShell + Sidebar + TopBar layout with breadcrumbs.
+### Router Integration
+
+Update `App.tsx` to replace the single `/admin` route with nested routes:
+```tsx
+} />
+} />
+} />
+} />
+```
+
### Sidebar Integration
-Add admin links to the Sidebar bottom links. The existing Sidebar component already supports `bottomLinks` — add entries for Audit Log, OIDC, and User Management.
+Keep the existing single "Admin" bottom link in the Sidebar. The admin pages handle their own sub-navigation internally via a secondary nav bar at the top of each admin page (links to Audit Log, OIDC, User Management). This avoids cluttering the main sidebar with admin sub-entries.
-Update the mock sidebar data in `src/mocks/sidebar.ts` to include admin navigation, and update the Sidebar usage across all example pages.
+### Barrel Export Updates
+
+- Add `MultiSelect` and `MultiSelectOption` type to `src/design-system/composites/index.ts`
+- Add `ConfirmDialog` and `ConfirmDialogProps` type to `src/design-system/composites/index.ts`
+- Add `InlineEdit` and `InlineEditProps` type to `src/design-system/primitives/index.ts`
### Page: Audit Log (`src/pages/Admin/AuditLog/`)
@@ -178,14 +201,14 @@ Update the mock sidebar data in `src/mocks/sidebar.ts` to include admin navigati
Add demos for all three new components:
-- **MultiSelect** → PrimitivesSection: Demo showing multi-select with sample options, displaying selected count
+- **MultiSelect** → CompositesSection: Demo showing multi-select with sample options, displaying selected count
- **InlineEdit** → PrimitivesSection: Demo showing display/edit toggle with a sample name
- **ConfirmDialog** → CompositesSection: Demo with a "Delete item" button that opens the dialog
## File Structure
```
-src/design-system/primitives/MultiSelect/
+src/design-system/composites/MultiSelect/
MultiSelect.tsx
MultiSelect.module.css
MultiSelect.test.tsx