Skip to content

design(site): collapsible sidebar navigation for deployment & AI settings#25450

Draft
tracyjohnsonux wants to merge 44 commits into
mainfrom
sidebar-nav-accordion
Draft

design(site): collapsible sidebar navigation for deployment & AI settings#25450
tracyjohnsonux wants to merge 44 commits into
mainfrom
sidebar-nav-accordion

Conversation

@tracyjohnsonux
Copy link
Copy Markdown
Contributor

Summary

Design/UX iteration — new collapsible sidebar navigation for deployment settings, plus a standalone AI admin section. Frontend only, no backend changes.

What changed

Collapsible sidebar system (site/src/components/Sidebar/)

  • Two-state model: 240px expanded / 64px collapsed
  • Direct DOM manipulation during drag for zero-stutter performance; CSS transitions for click-to-toggle
  • Nav always renders at 240px — outer container clips with overflow-hidden, preventing content reflow
  • Resize handle with hover/drag visual feedback
  • Context exposes collapsed, expand(), toggle()
  • Accordion sections with icon-only collapsed mode + tooltips

Deployment sidebar (/deployment)

  • 3 accordion sections: General, Infrastructure, Authentication
  • AI Settings and AI Governance removed (moved to /ai)
  • "Deployment" header row with PanelLeft icon — click to collapse/expand
  • Naming convention: capital first word, rest lowercase

AI section (/ai) — new top-level area

  • Own layout, sidebar, and route tree
  • Top-level icon links: AI Governance, Providers, Models, Spend
  • Agents accordion: General, Instructions, Templates, Experiments, MCP servers, Lifecycle
  • Routes point to real AgentSettings*Page components (not stubs)
  • AI Governance page is a stub pending backend

Admin dropdown

  • Simplified to: Deployment, Organizations, AI, Logs, Healthcheck

Mock pages

  • AI Settings: Usage stats, Providers list, Add/Edit provider forms, Models
  • AI Governance stubs: Access and spend, Governance settings, Analytics, Data controls
  • Secrets stub page under Deployment

Other

Generated with Coder Agents

…ttings

Replaces the flat-list deployment settings sidebar with a new grouped
accordion navigation system. Each section (General, Infrastructure,
Authentication, AI Settings, AI Governance) has an icon header with
expand/collapse behavior — only one section open at a time.

The sidebar right edge is draggable to resize. Dragging below a
threshold snaps it to an icon-only collapsed view (56px). Width is
persisted to localStorage.

A 3px hover-glow line on the resize handle uses a CSS gradient mask
that fades at both ends for a softer visual effect.

New components:
- CollapsibleSidebar: resizable nav wrapper with context
- SidebarAccordion: icon+label header with Radix Collapsible content
- SidebarResizeHandle: drag handle with gradient glow
- useSidebarResize: width state, drag logic, snap, localStorage

Also adds blank stub pages for AI Settings sub-routes (Usage Stats,
Models, Providers, Keys) and AI Governance sub-routes (Access & Speed,
Settings, Analytics, Data Controls).
- Remove breadcrumb bar from deployment settings layout
- Make layout full-width: sidebar flush-left with 24px padding
  matching main nav alignment
- Reset button styles on accordion triggers (bg-transparent
  border-none) since Tailwind preflight is disabled
- Center content area within its column via max-w + mx-auto
- Simplify to two-state model: expanded (240px) or collapsed (56px)
  with no in-between widths. Eliminates weird partial-width states.
- Move resize handle outside nav overflow area so it's never clipped
  and the hover glow line aligns exactly on the 1px border.
- Position handle with -right-1 to center on the border line.
- Match collapsed icon button padding (px-3 py-2) to expanded button
  so icons stay at the same vertical position in both states.
- Use same size-4 icons in both states for consistent alignment.
- Persist collapsed/expanded state (not raw width) to localStorage.
- Remove transition on outer wrapper for instant width changes during
  drag — no more clunky pause at snap boundaries.
- Content area top padding reduced to 24px (pt-6) from 40px.
- Resize glow line is now a 300px segment centered on the cursor
  (150px above, 150px below) using a dynamic CSS mask gradient
  that updates on mousemove. Creates a spotlight effect instead
  of a full-height line.
- Icons left-align with the Coder logo: nav pl-6 (24px) matches
  navbar px-6, buttons have zero left padding so icon left edges
  sit at exactly 24px from viewport edge in both states.
- Collapsed buttons use the same py-2 and size-4 icon as expanded
  buttons for consistent vertical rhythm.
- Replace mask:none with a fully transparent gradient on mouseleave
  so the opacity transition fades smoothly without the full-line
  flash (the previous approach unmasked the entire line for one
  frame before the opacity transition kicked in).
- Control opacity via explicit state (hovered) instead of CSS
  group-hover to keep mask and opacity in sync.
- Add -ml-px to sidebar icons to compensate for lucide SVG viewBox
  inset (~1.3px stroke padding) so the visible icon edges align
  with the Coder logo's left edge.
…g area

- Restore px-3 py-2 on both collapsed and expanded accordion buttons
  so vertical spacing is identical in both states.
- Adjust nav pl from pl-6 to pl-3: nav-pl(12) + button-px(12) = 24px
  matching the navbar px-6 so icons align with the Coder logo.
- Remove the -ml-px hack — no longer needed with correct padding math.
- Widen resize handle hit area from w-2 (8px) to w-4 (16px) giving
  8px of buffer on each side of the border line.
Increase collapsed width from 56px to 64px so the icon has equal
space on both sides. Icon center is at 32px (nav-pl 12 + btn-px 12
+ half icon 8), so width = 64 centers it exactly.
In collapsed mode, clicking a section icon now navigates to the
first page in that section (e.g. clicking the gear icon goes to
/deployment/overview). This triggers a route change which expands
the sidebar and opens the correct accordion section.

Adds an optional href prop to SidebarAccordion. When provided and
the sidebar is collapsed, the icon renders as a Link instead of a
toggle button.
…ment

The collapsed Link/button elements lacked w-full, so they shrank
to content width and the px-3 padding didn't align icons to the
same 24px left edge as the expanded state. Adding w-full ensures
the elements stretch to fill the nav width, keeping the icon at
nav-pl(12) + px-3(12) = 24px from sidebar left in both states.
- Clicking a collapsed sidebar icon now expands the sidebar AND
  navigates to the section's first page. Added expand() to the
  sidebar context, called from the accordion's collapsed Link/button.
- Remove requestAnimationFrame from drag handler — binary snap
  doesn't need throttling. Direct pointermove → setState is instant.
- Use data-sidebar-container attribute to find the outer wrapper
  for drag offset calculation (handle is outside nav element).
- Add mt-0 to all stub page h1 elements to reset browser-default
  top margin (preflight is off).
- Moved transition-[width] to the outer wrapper div so the width
  change animates on the container, not the inner nav.
The expanded button was 40px tall (py-2 + text-sm line-height 24px)
while the collapsed button was only 32px (py-2 + icon 16px). Adding
an explicit h-10 (40px) to all three button/link variants ensures
icons stay at the same vertical position when toggling between
expanded and collapsed states.
Replace w-full + px-3 on collapsed buttons with w-10 h-10
justify-center so the hover background wraps tightly around
the icon as a 40x40 rounded square. The icon center stays at
32px from sidebar left (matching the expanded state).
Track a dragging state that keeps the glow line visible even when
the cursor leaves the handle area. During drag, a global pointermove
listener updates the glow position and opacity is bumped to 0.7
(vs 0.4 on hover). On pointerup everything resets cleanly.
Remove the ::before/::after stripe bars on .navbar-stripe-devel
and .navbar-stripe-rc. The CSS variable definitions are kept
in case they're referenced elsewhere.
Apply text-content-primary to the section icon when its accordion
is open, matching the label text treatment. Applies to all three
states: expanded button, collapsed link, and collapsed button.
Add an 'active' prop to SidebarAccordion that reflects whether
the section owns the current route (via activeSection). The icon
and label use this for text-content-primary highlighting instead
of the 'open' prop which only tracks accordion expansion.

This fixes collapsed mode where no accordion is visually open
but the active section's icon should still be highlighted.
Restore right padding on the nav (pl-3 → px-3) so the expanded
button has equal 12px space on both sides before the border line.
The first 15px of drag movement tracks the cursor 1:1 so the
grab feels immediate. After that, the width snaps to expanded
(240px) or collapsed (64px) based on the snap threshold.

- Track live pixel width during drag via dragWidth state.
- Disable CSS transition while dragging so the 1:1 tracking
  doesn't fight the animation. Re-enable on pointerup so the
  final snap animates smoothly.
- Expose 'dragging' boolean from the hook for the container to
  conditionally apply the transition class.
Replace React state updates on every pointermove with direct
container.style.width writes. This eliminates the stutter caused
by React reconciliation on each mouse event.

During drag:
- CSS transition is disabled (container.style.transition = 'none')
- Width tracks the cursor 1:1, clamped between 64px and 240px
- Zero React re-renders happen

On pointerup:
- CSS transition is restored
- Width snaps to 64px or 240px based on the snap threshold
- React state syncs once for collapsed/expanded
The inner nav now always renders at w-[240px] (full expanded
width) so its text and icons never reflow during drag. The outer
container has overflow-hidden and its width is what changes —
content simply gets cropped as the container shrinks, then snaps
to the collapsed icon-only view on release.
…llapsed

The 1px right border was on the inner nav (always 240px wide),
so it got clipped by overflow-hidden when the container shrank
to 64px. Moving the border to the outer container keeps it at
the visible right edge in both states.
Any drag movement now completes the transition: drag left from
expanded → collapse, drag right from collapsed → expand. No
minimum distance threshold — just direction. A click without
movement toggles the state.

Removed the SNAP_THRESHOLD constant since it's no longer needed.
Movement under 3px is treated as a click (toggles collapsed
state). Movement >= 3px starts the drag — the container width
tracks the cursor 1:1 and snaps on release based on direction.
This prevents accidental state toggles from tiny mouse jitters
during a click.
Resize handle now extends 8px left of the border line but only
3px right into the content area. Clicking in the content area
no longer accidentally toggles the sidebar.
Revert handle to w-4 -right-2 (8px each side of border) so it's
grabbable from both sides. The glow line is now absolutely
positioned at left:7px within the 16px handle, placing the 2px
line exactly on the 1px border instead of centered in the hit
area.
The handle was inside the overflow-hidden div, clipping its right
half so it wasn't grabbable from the content side. Now the outer
wrapper (no overflow clipping) holds both the clipping container
and the handle as siblings. The handle extends 8px on each side
of the border without being clipped.
…rsor

Remove the gradient mask approach. The glow is now a plain 150px
tall, 2px wide rounded bar absolutely positioned at the cursor's
Y coordinate. No gradient, no mask — just a simple bar that
follows the mouse.
Shows a small uppercase 'Deployment' label above the accordion
buttons in expanded mode. Hidden when collapsed to icon-only.
Uses text-content-disabled as the tertiary content color.
Only kill the CSS transition when actual dragging starts (past
the 3px dead zone). For clicks, never touch container.style —
just toggle React state and let the existing CSS transition on
the container animate the width change smoothly. This eliminates
the weird line artifacts on click.
Keep the bar's last Y position on mouseleave instead of clearing
it to null. The opacity transition fades it out in place, avoiding
the flash caused by the bar jumping to top:-50 for one frame.
Replace the 100px cursor-following bar with a simple full-height
line that appears on hover and stays during drag. Removed all
mouseY tracking and gradient logic.
Replaces the stub AISettingsUsageStatsPage with a full mock
matching the design comp:
- 'AI usage' header with subtitle
- Groups/Users tabs
- Search input with date range
- Table with Name, Costs, Input/output, Cache read/write columns
- 4 mock group rows with avatars and token badges
- Pagination controls with page numbers
- Rename sidebar label from 'Usage Stats' to 'Usage'
Providers page with mock data:
- Table with Name, Base URL, User keys columns
- 4 providers (Anthropic, OpenAI, AWS Bedrock, Vercel AI Gateway)
- Check/X icons for user key status, chevron-right for drill-in
- + Add provider button, pagination

Sidebar icon updates:
- Infrastructure: Container → HardDrive
- Authentication: KeyRound → UserLock
- AI Settings: Sparkles → Settings2
- AI Governance: Scale → ShieldCheck

Sidebar label: 'Usage Stats' → 'Usage'
New page at /deployment/ai-settings/providers/add matching the
design comp:
- Back to providers link
- 'Add a provider' header with subtitle
- Form card with API key, Base URL, Icon picker fields
- Key policy section with 3 toggle switches (Central API key,
  Allow user API keys, Use central key as fallback)
- Cancel and Add Provider action buttons
- Route registered under ai-settings/providers/add
Models page at /deployment/ai-settings/models matching the design:
- Table with Name, Model cost, Session share, Context limit, Status
- 4 mock models: Opus 4.6 Max (active/default), claude-sonnet-4-6
  (active), anthropic.claude-opus-4-6-v1 (stale), GPT 5.4 (disabled)
- Status column with colored dot + label + detail text
- Provider icon avatars, chevron-right for drill-in
- Pagination controls
- Admin dropdown: Deployment, Organizations, AI, Logs, Healthcheck
- New /ai route with CollapsibleSidebar layout
- AI sidebar: AI Governance, Providers, Models, Spend (top-level) + Agents accordion
- Routes point to real AgentSettings*Page components from main
- Removed AI Settings/Governance from Deployment sidebar
- Fixed lucide-react icon names for v1 (Icon suffix)
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