The product frame: sidebar, the work, an optional rail.
The lockup goes through Mark rather than a bare img, so it follows the theme. A bare img here is how the first screen lost its wordmark in dark.
product is validated against the seven real products and dropped otherwise. The component knows only the attribute; the colours are the product-<p>-wash tokens. An unrecognised name would set an attribute that matches no token and silently render no wash, so it is rejected instead.
main holds the page heading, not just the body, so the skip link lands on the one h1 rather than above it. tabIndex={-1} is what lets focus actually arrive.
The folded state is remembered per browser when uncontrolled, and every localStorage call is wrapped because a private window throws.
import { AppShell } from '@redrob-labs/ui';
| Prop | Type | Notes |
|---|---|---|
product |
string |
Product name, e.g. Desk. Sets the product wash at the top of the sidebar. |
mark |
string |
|
markDark |
string |
|
symbol |
string |
The symbol alone, shown when the sidebar is folded. |
nav |
AppShellNavItem[] |
|
navLabel |
string |
|
aside |
React.ReactNode |
Extra content at the bottom of the sidebar. |
theme |
React.ReactNode |
|
title |
React.ReactNode |
|
meta |
React.ReactNode |
A line under the title: what this screen is showing. |
actions |
React.ReactNode |
|
foot |
React.ReactNode |
|
rail |
React.ReactNode |
A right-hand panel about the current run. |
railLabel |
string |
|
measure |
boolean |
false lets the work area run full width instead of holding a reading measure. |
collapsible |
boolean |
|
collapsed |
boolean |
|
defaultCollapsed |
boolean |
|
collapseLabel |
string |
|
expandLabel |
string |
|
skipLabel |
React.ReactNode |
|
className |
string |
|
children |
React.ReactNode |
|
onCollapsedChange |
(collapsed: boolean) => void |