Blocos
AppSidebar
Navegação lateral opinada para dashboards — marca, busca, grupos e footer no padrão sidebar-01 (shadcn).
AppSidebar compõe o primitivo Sidebar do @uranus-workspace/design-system com componentes nomeados:
AppSidebar.Header— topo do trilho (marca, workspace switcher).AppSidebar.Brand— linha de produto:Brand.Icon,Brand.Body(Brand.Title,Brand.Subtitle),Brand.Action(densidade sidebar-01).AppSidebar.Search— campo com ícone (SidebarInput+ token).AppSidebar.Content— área rolável; dentro dela useSidebarGroup,SidebarGroupLabel,SidebarMenueAppSidebar.NavLink(do@uranus-workspace/design-system).AppSidebar.Footer— rodapé (usuário, versão).AppSidebar.NavLink— links comBlockLink,aria-currente tooltip no modo ícone.
Monte a árvore com children — não há menu serializado por props.
Em docs ou iframe estreito, o Sidebar padrão é fixo na viewport — use collapsible="none" no preview para o trilho ficar no fluxo (como no exemplo abaixo). Em apps reais deixe o collapsible padrão.
O preview usa align="stretch" e altura mínima maior para o exemplo ocupar toda a largura útil (sidebar + área principal lado a lado), sem ficar comprimido ao centro.
'use client';
import { AppHeader, AppSidebar } from '@uranus-workspace/blocks';
import {
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
Button,
Separator,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarInset,
SidebarMenu,
SidebarProvider,
SidebarTrigger,
} from '@uranus-workspace/design-system';
import {
BookOpen,
ChevronsUpDown,
Code,
FileCode,
FileText,
FolderTree,
Layers,
Rocket,
} from 'lucide-react';
export default function AppSidebarDefault() {
return (
<div className="box-border flex h-[min(680px,78vh)] min-h-[520px] w-full min-w-0 flex-col overflow-hidden rounded-xl border border-fd-border bg-fd-background shadow-sm">
<SidebarProvider className="flex min-h-0 w-full flex-1 flex-col">
<div className="flex min-h-0 min-w-0 w-full flex-1 flex-row">
<AppSidebar
collapsible="none"
className="w-[min(100%,19rem)] shrink-0 border-r border-sidebar-border"
>
<AppSidebar.Header>
<AppSidebar.Brand>
<AppSidebar.Brand.Icon>
<BookOpen aria-hidden />
</AppSidebar.Brand.Icon>
<AppSidebar.Brand.Body>
<AppSidebar.Brand.Title>Documentation</AppSidebar.Brand.Title>
<AppSidebar.Brand.Subtitle>v1.0.1</AppSidebar.Brand.Subtitle>
</AppSidebar.Brand.Body>
<AppSidebar.Brand.Action>
<Button
type="button"
variant="ghost"
size="icon"
className="size-8 shrink-0"
aria-label="Switch workspace"
>
<ChevronsUpDown aria-hidden className="size-4 opacity-70" />
</Button>
</AppSidebar.Brand.Action>
</AppSidebar.Brand>
</AppSidebar.Header>
<AppSidebar.Content>
<AppSidebar.Search placeholder="Search the docs…" />
<SidebarGroup>
<SidebarGroupLabel>Getting started</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<AppSidebar.NavLink
href="#installation"
icon={<Rocket aria-hidden className="size-4" />}
label="Installation"
>
Installation
</AppSidebar.NavLink>
<AppSidebar.NavLink
href="#structure"
icon={<FolderTree aria-hidden className="size-4" />}
label="Project structure"
>
Project structure
</AppSidebar.NavLink>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Build your application</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<AppSidebar.NavLink
href="#routing"
icon={<Layers aria-hidden className="size-4" />}
label="Routing"
>
Routing
</AppSidebar.NavLink>
<AppSidebar.NavLink
href="#data"
icon={<Code aria-hidden className="size-4" />}
active
label="Data fetching"
>
Data fetching
</AppSidebar.NavLink>
<AppSidebar.NavLink
href="#rendering"
icon={<FileCode aria-hidden className="size-4" />}
label="Rendering"
>
Rendering
</AppSidebar.NavLink>
<AppSidebar.NavLink
href="#middleware"
icon={<FileText aria-hidden className="size-4" />}
label="Middleware"
>
Middleware
</AppSidebar.NavLink>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</AppSidebar.Content>
<AppSidebar.Footer>
<div className="flex items-center gap-2 border-t border-sidebar-border px-2 py-3">
<div
className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-accent text-xs font-medium text-sidebar-accent-foreground"
aria-hidden
>
UT
</div>
<div className="grid min-w-0 flex-1 gap-0.5 text-left text-xs leading-tight">
<span className="truncate font-medium text-sidebar-foreground">User</span>
<span className="truncate text-sidebar-foreground/70">you@uranus.com.br</span>
</div>
<ChevronsUpDown aria-hidden className="size-4 shrink-0 opacity-50" />
</div>
</AppSidebar.Footer>
</AppSidebar>
<SidebarInset className="min-h-0 flex min-w-0 flex-1 flex-col overflow-hidden bg-background">
<AppHeader>
<SidebarTrigger className="-ml-1" />
<Separator orientation="vertical" className="mr-1 data-[orientation=vertical]:h-4" />
<AppHeader.Breadcrumbs>
<BreadcrumbList className="text-sm">
<BreadcrumbItem className="hidden sm:inline-flex">
<BreadcrumbLink href="#">Build your application</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator className="hidden sm:inline-flex" />
<BreadcrumbItem>
<BreadcrumbPage>Data fetching</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</AppHeader.Breadcrumbs>
</AppHeader>
<div className="flex flex-1 flex-col gap-4 overflow-auto p-4">
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
<div className="aspect-video rounded-xl bg-muted/60" />
<div className="aspect-video rounded-xl bg-muted/60" />
<div className="aspect-video rounded-xl bg-muted/60" />
</div>
<div className="min-h-40 flex-1 rounded-xl bg-muted/60 md:min-h-min" />
</div>
</SidebarInset>
</div>
</SidebarProvider>
</div>
);
}
Uso
import { AppSidebar } from '@uranus-workspace/blocks';
import {
Button,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
} from '@uranus-workspace/design-system';
import { BookOpen, ChevronsUpDown, Home } from 'lucide-react';
<AppSidebar collapsible="none">
<AppSidebar.Header>
<AppSidebar.Brand>
<AppSidebar.Brand.Icon>
<BookOpen aria-hidden />
</AppSidebar.Brand.Icon>
<AppSidebar.Brand.Body>
<AppSidebar.Brand.Title>Documentation</AppSidebar.Brand.Title>
<AppSidebar.Brand.Subtitle>v1.0.1</AppSidebar.Brand.Subtitle>
</AppSidebar.Brand.Body>
<AppSidebar.Brand.Action>
<Button type="button" variant="ghost" size="icon" aria-label="Workspace">
<ChevronsUpDown aria-hidden className="size-4" />
</Button>
</AppSidebar.Brand.Action>
</AppSidebar.Brand>
</AppSidebar.Header>
<AppSidebar.Content>
<AppSidebar.Search placeholder="Search the docs…" />
<SidebarGroup>
<SidebarGroupLabel>Getting started</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<AppSidebar.NavLink href="/docs/install" icon={<Home aria-hidden className="size-4" />} label="Installation">
Installation
</AppSidebar.NavLink>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</AppSidebar.Content>
</AppSidebar>Roteamento
Os links resolvem o componente de âncora via BlockLink na seguinte ordem:
- Prop
linkComponentnoAppSidebar. LinkProviderno topo da árvore.- Elemento nativo
<a>.
import Link from 'next/link';
import { AppSidebar, LinkProvider } from '@uranus-workspace/blocks';
import { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu } from '@uranus-workspace/design-system';
<LinkProvider linkComponent={Link}>
<AppSidebar>
<AppSidebar.Content>
<SidebarGroup>
<SidebarGroupLabel>Conta</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<AppSidebar.NavLink href="/settings">Configurações</AppSidebar.NavLink>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</AppSidebar.Content>
</AppSidebar>
</LinkProvider>Diretrizes
- Use ícones decorativos (
aria-hidden) — o label carrega o peso semântico. activeemAppSidebar.NavLinké responsabilidade do consumidor (geralmente derivado deusePathname()).- Para densidade próxima ao bloco oficial: grupo com label em sentence case, ícones
size-4, busca logo abaixo do header.