Uranus® Design System
Blocos

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.

Uranus
Navegação

Área principal

O header permanece fixo enquanto esta região rola (`AppShell.Content`).

'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 (usa SidebarInset / <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 AppShell por 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 no PageHeader.
  • Para autenticação use AuthLayout, não AppShell.

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.