> ## Documentation Index
> Fetch the complete documentation index at: https://docs.switchbord.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Navegação e layout de páginas

> Como a estrutura do app do Switchbord é organizada — os grupos da barra lateral, sub-rotas, breadcrumbs, abas de filtro e quando usar um Card em vez de uma seção simples.

A estrutura do app do Switchbord é construída em torno de uma barra lateral recolhível, um breadcrumb auto-derivado na barra superior e um pequeno conjunto de primitivos de página composáveis (`PageHeader`, `FilterTabs`, `Tabs`, `Card`, seções simples). Esta página documenta o que está onde e — para colaboradores — quando usar cada primitivo, para que novas telas tenham a mesma aparência e comportamento do restante do produto.

## Estrutura da barra lateral

A barra lateral esquerda usa **grupos recolhíveis**. Cada grupo é uma rota pai; seus filhos são uma lista simples de destinos de primeira classe abaixo dela.

<CardGroup cols={2}>
  <Card title="Inbox" icon="inbox">
    Simples — sem subgrupo. Leva direto ao inbox do operador.
  </Card>

  <Card title="Contacts" icon="address-book">
    Simples. Filtros e segmentos vivem dentro da página, não na barra lateral.
  </Card>

  <Card title="Agents" icon="robot">
    Grupo recolhível. Filhos: `Overview`, `Templates` e rotas de detalhe por agente.
  </Card>

  <Card title="Campaigns" icon="bullhorn">
    Grupo recolhível. Filhos: `All campaigns`, `Audiences`, `Schedules`.
  </Card>

  <Card title="Journeys" icon="diagram-project">
    Grupo recolhível. Filhos: `All journeys`, `Templates`, `Runs`.
  </Card>

  <Card title="Settings" icon="gear">
    Simples; abas internas cuidam das várias sub-páginas.
  </Card>
</CardGroup>

Os grupos persistem seu estado aberto/fechado por usuário em `localStorage`, para que a estrutura não se recolha novamente a cada navegação.

<Tip>
  Se você está adicionando um novo destino de nível superior, prefira primeiro uma entrada **simples**. Só promova para um grupo recolhível quando houver três ou mais rotas irmãs que se beneficiem de ficar visíveis ao mesmo tempo.
</Tip>

## Sub-rotas sob um registro pai

Páginas de detalhe para Agents, Campaigns e Journeys usam um formato de URL consistente:

```
/agents/[id]/config
/agents/[id]/tools
/agents/[id]/mcp
/agents/[id]/runs

/campaigns/[id]/overview
/campaigns/[id]/audience
/campaigns/[id]/schedule
/campaigns/[id]/runs

/journeys/[id]/graph
/journeys/[id]/triggers
/journeys/[id]/runs
```

Essas sub-rotas são renderizadas como **FilterTabs** no topo da página do registro, imediatamente abaixo do `PageHeader`. Cada aba é uma rota real — pode ser acessada por link direto, compartilhada e é preservada entre recarregamentos. As trocas de aba usam navegação shallow do Next.js, então a posição de scroll e o estado transitório não se perdem.

<Info>
  As abas de sub-rota não são o mesmo primitivo que os `Tabs` de página. Veja [Abas de filtro vs. abas de conteúdo](#abas-de-filtro-vs-abas-de-conteúdo) abaixo.
</Info>

## Breadcrumbs

A barra superior renderiza uma trilha de breadcrumb que é, por padrão, **auto-derivada da rota atual**. O sistema percorre os segmentos do pathname, consulta cada um em um pequeno registro (`/apps/app/lib/breadcrumbs.ts`) para obter um rótulo legível e renderiza migalhas clicáveis para cada segmento, exceto o último.

### Modo automático (o padrão)

Toda página recebe breadcrumbs auto-derivados sem fazer nada:

```tsx theme={null}
// Nenhuma prop necessária — automático é o padrão.
<PageHeader title="Runs" />
```

Para `/agents/abc123/runs`, isso renderiza: **Agents › Acme support bot › Runs**. O rótulo do meio é resolvido pelo loader `[id]` do registro (ele busca o nome de exibição do agente no cache).

Use o modo automático quando:

* Os segmentos de rota mapeiam de forma clara para rótulos legíveis (o caso comum).
* Você já está dentro de uma hierarquia de registro pai/filho já cadastrada no registro.

### Modo explícito

Passe `breadcrumbs` como um array quando a trilha auto-derivada estaria errada ou sem contexto suficiente:

```tsx theme={null}
<PageHeader
  title="Reply drafting"
  breadcrumbs={[
    { label: "Inbox", href: "/inbox" },
    { label: contact.displayName, href: `/inbox/${conv.id}` },
    { label: "Draft" },
  ]}
/>
```

Use o modo explícito quando:

* A URL não reflete o local mental do usuário (por exemplo, rotas modais, wizards).
* Você precisa exibir um rótulo que ainda não está no registro e não quer adicioná-lo.
* Você está renderizando uma página pontual (migrações, ferramentas administrativas) em que manter o registro atualizado não vale o esforço.

<Warning>
  Não misture os dois modos. Se você passar `breadcrumbs`, o resolvedor automático é ignorado completamente — overrides parciais não são suportados de propósito, para manter a trilha previsível.
</Warning>

## Abas de filtro vs. abas de conteúdo

O Switchbord fornece dois primitivos de abas que parecem semelhantes, mas cumprem papéis diferentes.

### `FilterTabs` — controle segmentado

Uma linha compacta de botões segmentados. Escolhe **qual recorte da mesma lista** você está visualizando. Não tem painéis de conteúdo próprios — apenas controla o estado de query/filtro abaixo.

Use `FilterTabs` quando:

* Estiver alternando entre visualizações do mesmo conjunto de dados subjacente (por exemplo, `All / Draft / Pending / Approved` em templates).
* Você quiser um visual de controle segmentado que não sugira "páginas" separadas.
* For navegação de sub-rota para um registro de detalhe (`config | tools | mcp | runs`).

```tsx theme={null}
<FilterTabs
  value={status}
  onValueChange={setStatus}
  options={[
    { value: "all", label: "All" },
    { value: "draft", label: "Draft" },
    { value: "approved", label: "Approved" },
  ]}
/>
```

### `Tabs` — regiões de conteúdo

O primitivo `Tabs` completo, baseado em Radix, com `TabsList`, `TabsTrigger` e `TabsContent`. Cada aba possui uma **região de conteúdo distinta**, com seu próprio cabeçalho, seus próprios dados e, potencialmente, suas próprias mutações.

Use `Tabs` quando:

* As abas renderizam interfaces estruturalmente diferentes (por exemplo, **Overview** vs. **JSON** vs. **Logs**).
* Cada aba tem conteúdo substancial — tabelas, formulários, gráficos.
* De outra forma, seria necessário dividir em rotas irmãs, mas as telas estão fortemente acopladas demais para justificar navegação em nível de URL.

<Tip>
  Regra prática: se alternar a aba deveria mudar a **URL**, use `FilterTabs` com sub-rotas. Se alternar a aba só muda **o que está dentro deste card/seção**, use `Tabs`.
</Tip>

## Cards vs. seções — composição de página

O erro mais comum em telas novas é envolver tudo em um `Card`. Nossa gramática de página é:

1. **`PageHeader`** no topo — título, descrição, breadcrumbs, ação principal.
2. **Seções simples** abaixo — um `<h2>` (ou um pequeno componente de cabeçalho de seção) seguido de conteúdo diretamente sobre o fundo da página.
3. **`Card`** apenas para painéis laterais, seletores modulares, ou coisas que genuinamente precisam de um contêiner com borda.

### Prefira seções simples

```tsx theme={null}
<PageHeader title="Agent configuration" />

<section className="space-y-4">
  <h2 className="text-lg font-semibold">Prompt</h2>
  <PromptEditor ... />
</section>

<section className="space-y-4">
  <h2 className="text-lg font-semibold">Tools</h2>
  <ToolList ... />
</section>
```

Isso se lê como uma única página com duas preocupações, que geralmente é o que você quer dizer. Empilhar dois `Card`s completos produz páginas pesadas e "encaixotadas" que não escalam bem além de três seções.

### Use `Card` quando

* **Painéis laterais** — um resumo na coluna direita ao lado do conteúdo principal.
* **Seletores modulares** — seletor de modelo, seletor de template, caixa de filtro de audiência. Widgets autocontidos que podem viver em qualquer lugar da página.
* **Estados vazios e prompts de onboarding** — um único elemento centralizado em uma página, do contrário, vazia.
* **Blocos de dashboard** — cards de métrica em páginas de visão geral.

```tsx theme={null}
// Bom: painel lateral
<div className="grid grid-cols-[1fr_320px] gap-6">
  <AgentRunsTable ... />
  <Card>
    <CardHeader>
      <CardTitle>Recent alerts</CardTitle>
    </CardHeader>
    <CardContent>...</CardContent>
  </Card>
</div>
```

<Warning>
  Se você se pegar aninhando um `Card` dentro de outro `Card`, pare. Esse é o sinal de que o contêiner externo deveria ser uma seção simples, ou o interno deveria ser um `<div>` simples.
</Warning>

## Checklist rápido para novas páginas

Antes de abrir um PR para uma nova tela, confirme:

* [ ] `PageHeader` é o primeiro elemento; `breadcrumbs` está ou omitido (automático) ou é um array explícito — nunca os dois.
* [ ] As sub-rotas sob um registro usam `FilterTabs` conectadas a URLs reais, e não `Tabs` de página.
* [ ] A entrada na barra lateral é simples, a menos que existam 3 ou mais rotas irmãs, caso em que se torna um grupo recolhível com um ícone apropriado.
* [ ] A estrutura de nível superior é `PageHeader` + seções. `Card` aparece apenas para painéis laterais, seletores, estados vazios ou blocos de dashboard.
* [ ] Todo novo segmento `[id]` tem um loader de rótulo registrado em `/apps/app/lib/breadcrumbs.ts` (ou breadcrumbs explícitos são passados em cada ponto de uso).

## Entregue neste projeto

O projeto de navegação e polimento de interface (BORD-329 → BORD-333) entregou:

* **BORD-329** — grupos recolhíveis na barra lateral para Agents / Campaigns / Journeys ✅
* **BORD-330** — abas de sub-rota por registro (`config | tools | mcp | runs` e afins) ✅
* **BORD-331** — breadcrumbs auto-derivados com um pequeno registro + escape hatch de override explícito ✅
* **BORD-332** — refatoração da gramática de página: `PageHeader` + seções, `Card` rebaixado para função de painel lateral ✅
* **BORD-333** — este documento + uma limpeza de design tokens no CTA da landing page `/web` ✅
