Layout
How a whole screen is assembled, and the parts it is assembled from — every surface plugs into one three-panel shell, and each part below carries its spec and a live demo in the same place. Single source: content/layoutTemplates.tsx.
App Shell — Three-Panel Structure
App.tsxEvery WorkPal view composes into a single three-panel shell: NavPanel (global navigation), ConversationPanel (primary working surface), and InspectorPanel (contextual detail). Foundations tokens flow through all three; edit a color once and every panel updates.
Global navigation, view switching, recents, profile
SidebarMiniSidebarSidebar · 260px (drag 220–400) · sidebar-bg MiniSidebar · 64px · collapsed
The user’s primary working surface — chat, page content, forms
ChatPanelPageLayout (+ any page)flex-1 · centered content max-w-[863px]
Contextual detail to the right: document, task context, side cards
DetailPanelTaskContextPanelSplitView sideDetailPanel · 504px TaskContextPanel · 280px Overlays on narrow viewports
Rule: a new feature is a slot in one of these three panels — never a new top-level chrome element. If you need a new panel primitive, build it in shared.tsx and register it under the relevant panel here.
Page shell — pinned single-row header (toggle + title + rightSlot/actions) that the filters + body scroll beneath (frosted, like the header on this site) + optional pinned footer. Wraps HeaderBar internally.
Spec
shared.tsxCanonical page shell. A pinned single-row header (sidebar toggle · title · flexible gap · rightSlot search/actions · onNewChat · headerRight · onBack) stays pinned at the top as a frosted layer while the body scrolls beneath it, and an optional footer stays pinned to the bottom. The title lives on the pinned row and is truncated to one line — pass a short label, not prose. Edit the spec in shared.tsx once — every page updates.
px-4 sm:px-8 · pt-6 pb-3 · title inline (truncated) · .frosted-headerpx-4 sm:px-8header pb-3 + body pt-3mb-8Canonical top toolbar. Sidebar toggle (when closed) + optional left/right slots. Used by every top-level shell.
Spec
shared.tsxThe pinned top row. Bare — as ChatPanel and the Wingman chat/quiz shells use it — it's just the sidebar-toggle button (only when the sidebar is closed) + optional left/right slots. DS-029: the toggle glyph is not fixed; each product supplies it through NavToggleIconProvider (WorkPal shows a panel-left icon, Wingman a hamburger). DS-080: PageLayout renders through HeaderBar, passing title / rightSlot / widthClass / padX so the page title sits inline on the pinned row; bare consumers pass none of these and render exactly the toolbar they always did.
sidebarOpen, onToggleSidebar, headerRight, title, titleAs, rightSlot, widthClass, padXTwo-column shell that flips inline ↔ overlay based on container width (ResizeObserver, not viewport). Used by ProjectPage, ChatPanel + DetailPanel, TaskContextPanel.
Main column
Resize this card horizontally to see the panel collapse to overlay.
Side panel
Spec
shared.tsxMain column + collapsible side column. Auto-switches to overlay mode when the CONTAINER is too narrow to fit both inline — DS-029: this used to say "viewport". It is measured with a ResizeObserver on SplitView's own element, which is deliberately agnostic of viewport size, sidebar width and collapsed state.
side, sideOpen, onCloseSide, sideWidth, mainMinWidthCanonical header row for a side panel. Title + optional children + close button (X or panel-right collapse icon).
Inspector
Collapsible
Spec
shared.tsxShared header row for any side panel. Unifies close-button size (40px rounded-xl), hover, and typography across every panel.
title, onClose, closeIcon ('x' | 'panel-right'), closeLabelScrollable conversation inspector body with spacing and an automatic scrollbar.
Requires React 19, ReactDOM 19, TypeScript and lucide-react 1.14.0. Import frame.css once and use a frame-root wrapper; set its background to var(--color-bg-page) and color to var(--color-text-primary), or supply a matching host surface; add dark to an ancestor for dark mode.
Tested with shadcn 4.21.0, React 19.2.5, Vite 8.0.10 and Tailwind 3.4.19 / 4.3.3. Start with a configured React/Vite shadcn app. Files install into src/components/frame; import its frame.css. For manual copy, save the complete component and stylesheet below. Examples leave optional voice features off; retain the MIT license and third-party notices.
Required stylesheet: frame.cssnpx shadcn@4.21.0 add https://raw.githubusercontent.com/BeibeiZhang/frame-design-system/main/registry/side-panel-body.json
Scrollable body container — pairs with SidePanelHeader. Holds a vertical stack of SideCards.
Side panel
Spec
shared.tsxScrollable body that pairs with SidePanelHeader and holds a vertical stack of SideCards. Single source of truth for right-panel L/R padding (px-3) and inter-card gap (gap-4) — switching between project view and task view no longer shifts content horizontally.
children. Padding / gap are intentionally not configurable — that's the point.Collapsible section inside a right-column side panel — no panel fill, border or radius; sections are separated by a fading 1px rule. Pairs with SidePanelHeader / SidePanelBody.
Pre-fetch the user's calendar and reference last week's meeting notes.
Spec
shared.tsxCollapsible section inside a right-column side panel. DS-029: this used to say "card" — it has no panel fill, no border and no radius; sections are separated by a 1px rule along the bottom edge that fades out at both ends (side-card-divider, with last:bg-none on the final one). Header with title + optional icon + optional add affordance + chevron.
title, icon, hasAdd, defaultOpenDark-mode background glow: one rotating field carrying all three color gradients, turning together around the screen center — never changing brightness, color or size. Mount once per app root — never per `.app-shell-bg` surface — so every dark-mode shell shares one animation clock instead of a second instance rotating out of phase.
--shell-glow-purple--shell-glow-orange--shell-glow-blue% is today's brightness — a ceiling that never changes. The three glows keep their positions relative to each other and rotate together as one field around the screen center, 60 seconds per full turn, clockwise, at a constant speed. prefers-reduced-motion freezes the field at today's rest position (0° = 360°, so the freeze frame is never mid-turn).
User-draggable column width (useResizableWidth + ResizeHandle). The products' NavPanel defaults to 260px, drags 220–400px and is remembered per product; this demo uses a smaller range. Drag the right edge, or focus it and use ←/→, Home/End; Enter or double-click resets.
Navigation
160px
Main content