Panel
Header bar · body · footer, plus a collapsible panel
Session settings
nockerl-cli · primary
A panel is a persistent, in-layout region: a header bar with a title and actions, a padded body, and an optional footer. Larger than a card; not an overlay.
The header chevron collapses and expands the body. The transition animates grid height (flash-free) and freezes under reduced-motion. Click the header to toggle.
Toolbar row · inspector (key / value) · nested sections
Output
A toolbar row hosts secondary controls (toggles, actions) on a slightly raised tier between the header and the body. Word wrap is on.
Inspector
Selected session
Advanced
Sampling
A panel can contain section panels: a nested surface a tier up, with its own header and body.
Permissions
Sections share the panel material at the control radius, divided by hairlines.
Split pane: two panels + a draggable, keyboard-operable splitter
Explorer
12 sessions
The left pane. Drag the splitter, or focus it and press Arrow Left / Right (Home / End to snap). Width is clamped between 25% and 75%.
Detail
nockerl-cli · gateway
The right pane fills the remaining space. A split-pane region stays in the layout; it is not an overlay like a drawer.
Saved 0 times · drag or arrow-key the splitter. The island is live.
// Web: React, consuming @dizyx/nockerl-tokens. (Web is the laggard platform. Spec + live demo,// not yet exported from @dizyx/nockerl-react; promotion is tracked.)
export function Inspector() { return ( <Panel title="Session settings" subtitle="nockerl-cli · primary" leadingIcon={<SettingsIcon />} actions={<NockerlIconButton label="More" icon={<MoreIcon />} />} footer={<><NockerlButton variant="ghost">Reset</NockerlButton><NockerlButton>Save</NockerlButton></>} > <p>A persistent, in-layout region: larger than a card, not an overlay.</p> </Panel> );}
// Collapsible: the header chevron toggles the body (aria-expanded).<Panel title="Context window" collapsible defaultOpen> <UsageMeter /></Panel>
// Split pane: two panels + a draggable, keyboard-operable resize handle.<PanelGroup direction="horizontal"> <Panel title="Explorer" minSize={25} defaultSize={46}><Tree /></Panel> <PanelResizeHandle /> <Panel title="Detail"><Detail /></Panel></PanelGroup>// Android: Jetpack Compose (canonical). There is no single NockerlPanel yet;// a panel is COMPOSED from NockerlCard + NockerlPanelShape, exactly as the// shipped ToolCallCard / AgentTranscriptPanel do. (See drift.)import com.nockerl.app.core.theme.NockerlCardimport com.nockerl.app.core.theme.NockerlElevationimport com.nockerl.app.core.theme.NockerlPanelShape
NockerlCard( shape = NockerlPanelShape, // 12dp, a step tighter than a card color = LocalNockerlColors.current.cardSurface1, elevation = NockerlElevation.Level1, border = LocalNockerlColors.current.cardHairline, modifier = Modifier.fillMaxWidth(),) { Column { // Header bar: icon tile + title/subtitle (start) · actions (end). Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(11.dp)) { ToolIconTile(icon = Icons.Filled.Tune, accent = colors.accentPrimary) Spacer(Modifier.width(8.dp)) Text("Session settings", fontWeight = FontWeight.SemiBold, modifier = Modifier.weight(1f)) // Collapse toggle. The header chevron drives AnimatedVisibility(expanded). Icon(if (expanded) Icons.Filled.KeyboardArrowUp else Icons.Filled.KeyboardArrowDown, null) } AnimatedVisibility(visible = expanded) { // flash-free collapse Column(Modifier.padding(11.dp)) { /* body */ } } }}// macOS: SwiftUI (canonical). The titled content panel is SettingsCard// (NockerlVoice/UI/SettingsComponents.swift): a header label row + body, on the// chrome surface with a hairline + the lit-from-above elevation.SettingsCard("Session settings", info: "nockerl-cli · primary") { Text("A persistent, in-layout region: larger than a card, not an overlay.") .foregroundStyle(NockerlTheme.onSurface)}
// Split pane: Voice builds it by hand (a fixed-width pane + content in an// HStack), deliberately NOT NavigationSplitView (its opaque sidebar fights the// facet background). See drift.HStack(spacing: 0) { leftPane.frame(width: 216) Rectangle().fill(NockerlTheme.hairline).frame(width: 1) // the divider detail.frame(maxWidth: .infinity, maxHeight: .infinity)}Parameters
Section titled “Parameters”| Prop | Type | Default | Description |
|---|---|---|---|
title * | string | Header bar title. Bound to the title.small type role. | |
subtitle | string | Optional second line under the title (muted). | |
leadingIcon | ReactNode | Optional glyph rendered in the accent header tile. | |
actions | ReactNode | Header-bar actions, right-aligned (icon buttons / overflow). | |
toolbar | ReactNode | Optional control strip on a raised tier between the header and body. | |
footer | ReactNode | Optional footer content; actions are right-aligned by convention. | |
collapsible | boolean | false | Renders the header as a toggle (aria-expanded); the body collapses flush. |
defaultOpen | boolean | true | Initial expanded state when collapsible. |
children | ReactNode | Body content. Padded by the panel; never bleeds to the edge. |
PanelGroup takes direction ('horizontal' | 'vertical'); each Panel in a
group accepts minSize / maxSize / defaultSize (percent), and
PanelResizeHandle is the draggable, keyboard-operable
(role="separator", Arrow keys) splitter.
A panel is composed from NockerlCard. These are its
panel-relevant parameters; the header / body / footer / collapse are built in the
content lambda (icon tile, title Row, AnimatedVisibility).
| Parameter | Type | Default | Description |
|---|---|---|---|
modifier | Modifier | Modifier | External modifier (size, alignment, .clickable { } for a collapse toggle). |
shape | Shape | NockerlPanelShape | Panel silhouette: the 12dp NockerlPanelShape (a step tighter than the 18dp card). |
color | Color | cardSurface1 | Surface fill. Nested section panels step up to cardSurface2. |
elevation | Dp | NockerlElevation.Level1 | Drop-shadow elevation. Panels sit low (Level1); the lift reads from the hairline + catch-light. |
border | Color? | cardHairline | Hairline border. Header / body / footer dividers are separate hairlines. |
content * | @Composable BoxScope.() -> Unit | Panel content: the header Row, body, and (in AnimatedVisibility) the collapsible region. |
The titled panel is SettingsCard (NockerlVoice/UI). The parameters below are its
real signature; the split-pane region is hand-built from layout primitives + the
theme tokens (no panel wrapper).
| Style | Type | Default | Description |
|---|---|---|---|
title * | String | Header label (rendered UPPERCASE, tracked, muted) in the header row. | |
info | String? | nil | Optional help text. Adds an InfoTip ⓘ beside the title. |
content * | @ViewBuilder -> Content | Panel body, laid out under the header. | |
NockerlTheme.chromeSurface | Color | Panel fill (#15171A dark / #FFFFFF light). | |
NockerlTheme.panelRadius | CGFloat | 12 | Panel corner radius, matching radius.panel (SettingsCard currently uses cardRadius = 14; see drift). |
NockerlTheme.hairline | Color | Hairline border + the split-pane divider rectangle. | |
.nockerlElevation() | modifier | The lit-from-above neutral shadow (soft black; near-invisible on dark, structure on light). |