Tema
Modelo de página
Toda tela do sistema tem o mesmo esqueleto: a trilha, o título com a situação, a linha de apoio, as ações e os blocos de conteúdo, um embaixo do outro. Quem monta o esqueleto é o BasePage, dentro do BaseAppShell. A tela só escolhe os blocos; espaço, margem e alinhamento vêm prontos. Assim o título fica na mesma altura em todas as telas e nada pula quando a pessoa troca de página.
As duas telas acima têm o título na mesma altura: a de cima tem trilha, a de baixo não tem, e a linha da trilha fica reservada nas duas.
Role a tela acima até o fim: o cabeçalho fica no alto, o menu lateral desce até o rodapé, o rodapé ocupa a largura toda, os blocos ficam à mesma distância um do outro e a tabela larga rola para o lado, com a barra à mostra.
Numa tela curta, como a de cima, o rodapé fica no fim da janela, e não no meio dela. Os links do menu que não cabem rolam dentro do menu, sem deixar a página mais alta.
Quando usar
- Em toda tela dentro do
BaseAppShell: lista, painel, detalhe, formulário e relatório. A tela de login e as de erro fora da moldura são as únicas exceções. - Sempre que a tela tiver título. Se a tela não cabe no modelo, o modelo é que muda, aqui no design system, e não a tela.
Componentes
BaseAppShell: a moldura. Recebe embreadcrumba trilha da tela aberta, vinda do roteador; nas telas sem trilha, uma lista vazia, que mantém a linha reservada.BasePage: o esqueleto da tela, de cima para baixo:- a linha da trilha, com altura reservada mesmo vazia;
- o
title, o únicoh1, com o slotstatusao lado (o selo da situação do registro); - o
subtitle, a linha de apoio; - o slot
actions, à direita, com no máximo um botão primário; - o corpo, onde cada bloco fica a 24 px (
--tj-page-gap) do anterior.
BasePageState: vai dentro doBasePage, para o título e as ações ficarem na tela enquanto os dados carregam. Pronto, ele empilha os blocos com o mesmo intervalo do corpo.BasePageAside: a coluna lateral de 360 px, nos detalhes e formulários com resumo.BaseTabs: cada painel também empilha os blocos e começa a 24 px da linha das abas. O painel não tem borda; o bloco de dentro é que é o cartão.BaseCardGrid: cartões e indicadores lado a lado, todos da mesma altura e com os links alinhados no fim.BaseStack: dentro de um bloco, as partes uma embaixo da outra, a 8, 16 ou 24 px. O corpo doBaseCardjá é uma pilha de 16 px.BaseCardcomflush: o título e a tabela num cartão só, com a tabela de borda a borda.BaseFileItemcomflush: a linha de arquivo sem borda, dentro de um cartão ou de uma célula de tabela.BaseDataTable: a tabela já é um cartão. Larga demais, ela rola para o lado com a barra sempre à mostra, e as colunas de texto guardam a largura mínima.
Texto
- O título diz o que a tela mostra, sem verbo: "Contratos ativos", "Medições do contrato CF901/2026".
- A linha de apoio diz o recorte ou o estado: "Contratos em execução e paralisados. Só consulta."
- A trilha usa os mesmos nomes do menu e termina na tela aberta, sem link.
Faça e não faça
| Faça | Não faça |
|---|---|
Passar a trilha ao BaseAppShell e deixar o BasePage desenhar a linha. | Pôr um BaseBreadcrumb antes do BasePage: o título desce e a tela pula. |
Deixar os blocos direto no corpo do BasePage, do BasePageState ou do painel da aba. | Escrever margin, padding ou mt-3 na tela para afastar um bloco do outro. |
Uma borda por bloco: a BaseDataTable solta no painel da aba, ou num BaseCard flush quando precisa de título. | BaseCard em volta de BaseDataTable, de BaseKpiCard ou de outro cartão: caixa dentro de caixa. |
BaseCardGrid para indicadores e atalhos. | Uma grade própria com display: grid e gap em pixels. |
BasePageState dentro do BasePage. | BasePageState em volta do BasePage, que some com o título enquanto carrega. |
O selo da situação no slot status. | O selo no slot actions, longe do título. |
As medidas de cada parte estão nas páginas dos componentes. Os testes da documentação abrem estas telas num navegador de verdade e conferem que o título fica na mesma altura com e sem trilha, que os blocos ficam a 24 px, que não há cartão dentro de cartão, que a tabela rola em vez de cortar e que o menu lateral vai até o fim.
Código
vue
<script setup lang="ts">
import { BaseAlertBanner, BaseBadge, BaseButton, BaseCard, BaseCardGrid, BaseDataTable, BaseKpiCard, BasePage, BasePageState } from '@lab-inovacao-tjes/design-system'
</script>
<template>
<!-- No AppLayout, o BaseAppShell recebe :breadcrumb="breadcrumbOf(route)" e mostra a tela pelo RouterView. -->
<BasePage title="Contratos ativos" subtitle="Contratos em execução e paralisados. Só consulta.">
<template #status><BaseBadge tone="info">Só consulta</BaseBadge></template>
<template #actions>
<BaseButton kind="secondary" icon="file-earmark-pdf" @click="exportPdf">Exportar PDF</BaseButton>
</template>
<BasePageState :status="status" loading-label="Carregando os contratos ativos" @retry="load">
<BaseCardGrid size="sm">
<BaseKpiCard label="Contratos ativos" :value="String(rows.length)" helper-text="em execução e paralisados" />
<BaseKpiCard label="Com alerta" :value="String(withAlerts)" href="/alerts" link-label="Ver alertas" />
</BaseCardGrid>
<BaseAlertBanner tone="info" title="Fórmulas em validação">O % executado ainda será confirmado.</BaseAlertBanner>
<BaseCard title="Contratos em execução e paralisados" flush>
<BaseDataTable :columns="columns" :rows="rows" row-key="id" label="Contratos ativos" />
</BaseCard>
</BasePageState>
</BasePage>
</template>Na tela de referência
- P19, moldura com a trilha e o rodapé:
AppLayout.vue. - P19, painel com indicadores, aviso e tabela larga:
ActiveContractsFeature.vue. - P20: em construção.