AppShell
A casca completa de uma aplicação dashboard - sidebar, header, conteúdo e painel lateral opcional.
AppShell orquestra SidebarProvider, SidebarInset e os slots compostos. Monte a árvore com AppShell.Sidebar, AppShell.Inset, AppShell.Header, AppShell.Content e opcionalmente AppShell.RightPanel.
A área principal fica em AppShell.Content, com rolagem vertical (overflow-y-auto) para o header não competir com o scroll da página.
Em demos embutidas (docs, Storybook estreito), passe collapsible="none" no AppSidebar ou Sidebar para o painel ficar no fluxo do layout — o modo padrão do primitivo usa posição fixa na viewport, o que pode sair do quadro de preview.
'use client';
import { AppHeader, AppShell, AppSidebar } from '@uranus-workspace/blocks';
import {
Separator,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarTrigger,
} from '@uranus-workspace/design-system';
export default function AppShellDefault() {
return (
<div className="box-border flex h-[min(680px,78vh)] min-h-[520px] w-full flex-col overflow-hidden rounded-xl border border-fd-border bg-fd-background shadow-sm">
<AppShell defaultSidebarOpen className="flex h-full min-h-0 w-full flex-1 overflow-hidden">
<AppShell.Sidebar>
<AppSidebar
collapsible="none"
className="h-full min-h-0 w-[min(100%,16rem)] shrink-0 border-r border-sidebar-border"
>
<AppSidebar.Header>
<span className="px-2 font-semibold text-sidebar-foreground">Uranus</span>
</AppSidebar.Header>
<AppSidebar.Content>
<SidebarGroup>
<SidebarGroupLabel>Navegação</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<AppSidebar.NavLink href="#" active label="Início">
Início
</AppSidebar.NavLink>
<AppSidebar.NavLink href="#" label="Projetos">
Projetos
</AppSidebar.NavLink>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</AppSidebar.Content>
</AppSidebar>
</AppShell.Sidebar>
<AppShell.Inset className="min-h-0 min-w-0 flex-1">
<AppShell.Header>
<AppHeader>
<SidebarTrigger />
<Separator orientation="vertical" className="h-5" />
<AppHeader.Breadcrumbs>
<span className="truncate text-sm text-fd-muted-foreground">
Produtos / Visão geral
</span>
</AppHeader.Breadcrumbs>
</AppHeader>
</AppShell.Header>
<AppShell.Content className="bg-muted/15">
<div className="space-y-3 p-6">
<p className="text-sm font-medium text-fd-foreground">Área principal</p>
<p className="text-sm leading-relaxed text-fd-muted-foreground">
O header permanece fixo enquanto esta região rola (`AppShell.Content`).
</p>
<div className="grid gap-3 pt-2 sm:grid-cols-2">
<div className="h-24 rounded-lg border border-dashed border-fd-border/80 bg-fd-card/50" />
<div className="h-24 rounded-lg border border-dashed border-fd-border/80 bg-fd-card/50" />
</div>
</div>
</AppShell.Content>
</AppShell.Inset>
</AppShell>
</div>
);
}
O preview usa align="stretch" para o exemplo ocupar toda a largura útil (sem ficar como uma faixa estreita no centro).
Uso
import { AppHeader, AppShell, AppSidebar } from '@uranus-workspace/blocks';
import { Separator, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarTrigger } from '@uranus-workspace/design-system';
<AppShell defaultSidebarOpen>
<AppShell.Sidebar>
<AppSidebar>
<AppSidebar.Header>{/* marca */}</AppSidebar.Header>
<AppSidebar.Content>
<SidebarGroup>
<SidebarGroupLabel>Principal</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<AppSidebar.NavLink href="/dashboard" label="Início">
Início
</AppSidebar.NavLink>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</AppSidebar.Content>
</AppSidebar>
</AppShell.Sidebar>
<AppShell.Inset>
<AppShell.Header>
<AppHeader>
<SidebarTrigger />
<Separator orientation="vertical" className="h-5" />
<AppHeader.Breadcrumbs>{/* breadcrumbs */}</AppHeader.Breadcrumbs>
<AppHeader.Actions>{/* ações globais */}</AppHeader.Actions>
</AppHeader>
</AppShell.Header>
<AppShell.Content>{children}</AppShell.Content>
</AppShell.Inset>
<AppShell.RightPanel>{/* opcional: DetailDrawer */}</AppShell.RightPanel>
</AppShell>Anatomia
AppShell.Sidebar— navegação primária (fora do<main>).AppShell.Inset— região principal ao lado da sidebar (usaSidebarInset/<main>).AppShell.Header— opcional, dentro do inset (sticky quando o conteúdo éAppHeader).AppShell.Content— corpo rolável da página.AppShell.RightPanel— opcional, irmão do inset (painel direito).
Diretrizes
- Use um
AppShellpor aplicação. O bloco assume que a navegação é única no nível raiz. - O bloco não define um
<h1>. O<h1>da tela mora noPageHeader. - Para autenticação use
AuthLayout, nãoAppShell.
Estado controlado vs. não controlado
<AppShell defaultSidebarOpen={false}>
<AppShell.Sidebar>...</AppShell.Sidebar>
...
</AppShell>Por padrão o estado da sidebar é persistido em cookie pelo SidebarProvider do @uranus-workspace/design-system. Para controlar via app state passe sidebarOpen + onSidebarOpenChange.