layout-shells
Installation
SKILL.md
Layout shells
Every page imports the shell it needs; there is no runtime chooser. Variant / collapsible / direction / max-width are hardcoded inside the shell file — not props, not user-facing settings. If a project spun from this template doesn't need one of the shells (e.g. no marketing area), the shell file is deleted, not "disabled by config". The philosophy is starting clean over configuring at runtime — configurability adds branches that need to be tested, translated, permissioned; deletion doesn't.
Rules
- Every page imports its shell explicitly at the top of the page file. No wrapper picks the shell based on route, role, or props.
import AppLayout from '#common/ui/components/app_layout' export default function Page() { return <AppLayout>...</AppLayout> } - Shell decisions are hardcoded: variant, collapsible, direction, max-width live inside the shell file. Do not accept them as props.
- Header widgets are shared across shells that need them (
<NotificationBell />,<ToggleTheme />,<LanguageSwitcher />,<NavUser />) — same visual identity, imported directly by each shell that mounts them. - Nav configs live in a single file and are exposed as functions (
getMainNav(t),getFooterNav(t),getNavUser(t),getMobileFab(t)). Nav items support acan: 'permissionKey'field for RBAC gating — see [[authorization]]. Nav items are never hardcoded inside the shell file. - Providers stay at the root client entry, not inside shells. Theme, i18n, Tuyau, modal stack are mounted once so every shell renders inside them.
- Adding a shell is only worth it when the shape is genuinely new (installer wizard chrome, kiosk, checkout). Otherwise reuse an existing shell — the same page can render inside two different shells if two contexts need it.