sebs7n-ui0.1.0
Navegación

AppShell

El layout de un panel: sidebar sticky desde lg y, debajo, una barra de 56px con hamburguesa.

import { AppShell } from "sebs7n-ui/app-shell"

Ejemplos

El layout completo

Achicá la ventana por debajo de 1024px: el sidebar pasa a un Sheet detrás de la hamburguesa. El alto sale de `--app-shell-height`; acá está fijado en 560px para que entre en la página.

Ir al contenido

Facturas

Todo lo emitido en septiembre.

Facturado
$ 1.284.000
+12,4 %vs. agosto
Vencido
$ 142.900
6 facturas
import { AppShell } from "sebs7n-ui/app-shell"
import { AppShellContent } from "sebs7n-ui/app-shell-content"
import { Button } from "sebs7n-ui/button"
import { Card, CardContent } from "sebs7n-ui/card"
import { DropdownMenuItem } from "sebs7n-ui/dropdown-menu"
import { FileTextIcon, LogOutIcon, UsersIcon } from "lucide-react"
import { PageHeader, PageHeaderActions, PageHeaderDescription, PageHeaderTitle } from "sebs7n-ui/page-header"
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarItem } from "sebs7n-ui/sidebar"
import { Stat } from "sebs7n-ui/stat"
import { UserMenu } from "sebs7n-ui/user-menu"

function Completo() {
  const usuario = { name: "Ana Pérez", email: "ana@acme.com" }
  return (
    <div className="overflow-hidden rounded-xl border border-gray-400">
      <AppShell
        className="[--app-shell-height:560px]"
        mobileBar={
          <>
            <div className="size-6 rounded-md bg-gray-1000" />
            <span className="ml-auto" />
            <UserMenu collapsed user={usuario} />
          </>
        }
        sidebar={
          <Sidebar>
            <SidebarHeader>
              <div className="flex h-8 items-center gap-2 px-1">
                <div className="size-6 shrink-0 rounded-md bg-gray-1000" />
                <span className="text-label-14 font-medium">Acme</span>
              </div>
            </SidebarHeader>
            <SidebarContent>
              <SidebarGroup>
                <SidebarGroupLabel>Operación</SidebarGroupLabel>
                <SidebarItem active icon={<FileTextIcon />}>
                  Facturas
                </SidebarItem>
                <SidebarItem icon={<UsersIcon />}>Clientes</SidebarItem>
              </SidebarGroup>
            </SidebarContent>
            <SidebarFooter>
              <UserMenu
                signOut={
                  <DropdownMenuItem>
                    <LogOutIcon />
                    Cerrar sesión
                  </DropdownMenuItem>
                }
                user={usuario}
              />
            </SidebarFooter>
          </Sidebar>
        }
      >
        <AppShellContent>
          <PageHeader>
            <PageHeaderTitle>Facturas</PageHeaderTitle>
            <PageHeaderDescription>Todo lo emitido en septiembre.</PageHeaderDescription>
            <PageHeaderActions>
              <Button variant="accent">Nueva factura</Button>
            </PageHeaderActions>
          </PageHeader>
          <div className="grid gap-4 sm:grid-cols-2">
            <Card size="sm">
              <CardContent>
                <Stat delta="+12,4 %" hint="vs. agosto" label="Facturado" trend="up" value="$ 1.284.000" />
              </CardContent>
            </Card>
            <Card size="sm">
              <CardContent>
                <Stat delta="6 facturas" label="Vencido" trend="down" value="$ 142.900" />
              </CardContent>
            </Card>
          </div>
        </AppShellContent>
      </AppShell>
    </div>
  )
}

Props

Generadas del TypeScript del paquete. Solo las props propias: las heredadas del primitivo de Base UI o del elemento HTML están en la línea «hereda de».

AppShell

Hereda las props de <div>.

PropTipoPor defectoDescripción
sidebar*React.ReactNodeUn <Sidebar>. Se renderiza fijo en desktop y dentro de un Sheet en mobile.
labelsPartial<AppShellLabels>
mainIdstring"contenido"id del <main>; es a donde apunta el skip link.
mobileBarReact.ReactNodeContenido de la barra de 56px a la derecha de la hamburguesa.
pathnamestringLa ruta actual. Cuando cambia, el Sheet mobile se cierra.
classNamestring

Teclado

Tab (primera parada)
«Ir al contenido», el skip link que salta al <main>.
Escape
Cierra el Sheet mobile.

Accesibilidad

  • Trae el skip link «Ir al contenido» apuntando al <main>: es la primera parada de tabulación de toda la app.
  • El <main> tiene id (mainId, por defecto contenido) y es enfocable por programa.
  • Al elegir un ítem en el Sheet mobile, se cierra y el foco va al <main>.
  • Los textos son configurables por labels, para traducir la app entera.

Reglas de uso

  • Pasale `pathname={usePathname()}`: cualquier navegación —un link del contenido, un router.push— cierra el Sheet mobile.
  • Usá `AppShellContent` como hijo directo: es el contenedor de página, así todas las pantallas tienen el mismo ancho.
  • El alto sale de --app-shell-height (100dvh). Para embeberlo en una caja: className="[--app-shell-height:720px]".
  • Para cerrar el Sheet desde un caso propio: useAppShell().closeMobile({ focusMain: true }).

Relacionados