AppShell
The frame every product screen sits in: the bar across the top, the rail under it down the side, the page in the middle, and the assistant beside it.
Master
Open the menu button to widen the rail, walk the side nav, and press Ask the assistant to bring the assistant in beside the page. Scroll the page: the page header stays at the top and shrinks to one compact line whose trail ends in the page name. Stage narrows the box the frame lives in, so watch the rail go on a phone. Width caps the page to a reading column; it does not resize the frame.
Usage
Use AppShell as the outer frame of a screen. It is a blueprint: it composes kit pieces and keeps no state of its own, so the screen decides what is open. Pass the kit AppHeader as header: it runs the full width across the top, and the rail starts under it. Pass the kit AppNav as nav, always with the app's full navigation: items={APP_NAV} and endItems={APP_NAV_END} from @/patterns/AppShell/appNav, every section and every link, with current set to the screen's own page (appNavPlace(id) gives its section and page name for the trail). Never pass a shorter list or make up links. Its column hugs whatever width the nav is, so collapsed, expanded and pinned all work. On a phone-width frame there is no room for a column, so the nav slides in over the page from the start edge: pass navOpen, the same boolean the AppHeader's menu button flips, and onNavClose, so tapping the page behind it closes it. It is a drawer there, at the nav's open width with its labels shown, and it is away and out of the keyboard's reach while it is closed. pageHeader takes a kit PageHeader and stays at the top of the page while the page scrolls under it, flush to the top edge; onPageHeaderStick says when the top of the page has scrolled away, so keep that boolean in the screen and pass it to the PageHeader as sticky to shrink it to the kit's compact 52px bar. stickyPageHeader false lets it scroll away instead. children are the page itself, already inside the scrolling content area with its edge padding and the gap between Sections, so screens do not add their own. assistant takes a kit ChatWindow and shows beside the page while assistantOpen is true. assistantSize full lets it take the page's place edge to edge, keeping the bar and the rail: the page and its page header are hidden, not removed, and the assistant stays the same element, so neither loses its state and focus stays where it was. Give the ChatWindow size full at the same time. width caps the page to a reading column; it does not resize the frame. The frame answers to its own width rather than the window's, so under about 640 the rail goes and an open assistant takes the page's place, whether it is docked in a panel or filling a screen. See contracts/appshell.json for the full contract. The frame marks itself, so panels that float out of the bar or the rail — menus, tooltips, the search dropdown — keep inside it rather than over whatever is beside it.
Do's
- Any product screen: a list, a record, a dashboard.
- A screen the assistant can be opened beside.
- The assistant's full-screen view, keeping the bar and the side nav.
Don'ts
- Do not add state to it; it is a blueprint. Keep which nav section, which page, whether the assistant is open and whether the page header is compact in the screen.
- Do not build the bar, the rail or the page header inside it. Pass the kit pieces.
- Do not trim, reorder or invent side nav links. Every screen passes the full APP_NAV and APP_NAV_END from @/patterns/AppShell/appNav and marks its own page with current.
- Do not add page padding or a gap between Sections in the screen; the content area already has both.
- Do not swap a full-size ChatWindow into the page area or hide the page header by hand. Set assistantSize full.
- Do not invent a second frame or a per-page grid beside it. Read contracts/layout.json.
- Do not use raw hex.
<AppShell assistantSize="panel" width="full" />