Skip to content
Versão preliminar. Cores, componentes e layout ainda vão mudar: falta receber o padrão de interface do TJES (template-basico-vue) e o manual de identidade visual.

BaseAppShell, BasePage e BasePageAside ​

A moldura institucional de todo sistema do Tribunal: cabeçalho azul-marinho com o logo, o nome do sistema, a busca e a pessoa conectada; menu lateral com os módulos; e a área de conteúdo, de até 1280 px. Cada tela entra nela como um BasePage, com o título da tela e o conteúdo. Telas de detalhe e de formulário usam o BasePageAside para a coluna lateral de 360 px.

Pular para o conteúdo
Gestão de ObrasSecretaria de Engenharia

Contratos de obras

42 contratos ativos. Medição de outubro aberta até 10/11.

Último item do menu escolhido

Contratos

Nesta página o exemplo fica numa caixa de 560 px de altura; no sistema, a moldura ocupa a janela inteira. Abaixo de 992 px de largura de janela, o menu lateral vira uma faixa horizontal sob o cabeçalho.

Uso ​

  • Use um BaseAppShell por sistema, na raiz do app. Cada tela é um BasePage dentro dele: o title vira o único h1 da tela, o subtitle diz o estado da página e o slot actions recebe as ações da tela (no máximo um botão primário).
  • O menu lateral vem da propriedade nav: grupos com um título curto (Obras, Secretaria) e itens com label, href e icon. Dê ícone a todos os itens: com o menu recolhido, só os ícones aparecem.
  • Marque a tela aberta com current: true. Ela ganha fundo, peso e uma barra lateral, não só cor.
  • Use count para o que pede atenção, como medições abertas, e countLabel para dizer o que é contado: o leitor de tela ouve "7 medições abertas" junto com o nome do item.
  • Com roteador, ouça navigate, chame event.preventDefault() e navegue pelo item.href. O navigate só chega no clique simples: com Ctrl, Cmd, Shift, Alt ou o botão do meio, o navegador abre o link em outra aba ou janela, como no RouterLink. Sem roteador, os links funcionam sozinhos.
  • O botão de menu no começo do cabeçalho recolhe o menu lateral para uma faixa só de ícones. Ligue v-model:collapsed para guardar a preferência da pessoa.
  • O slot search recebe a busca geral do sistema: um BaseSearch com landmark e, se for a única busca com atalho da tela, shortcut. Ele ganha as cores do cabeçalho. Buscas de lista ficam na tela, não no cabeçalho.
  • O slot tools recebe botões de ícone, como avisos e ajuda: BaseButton com kind="ghost" e icon-only.
  • user-name e user-role mostram quem está conectado. Com o slot user-menu, o nome vira um botão que abre um painel com links e botões (perfil, sair).
  • O slot logo recebe o logo branco do Tribunal, sempre sobre o azul-marinho e nunca recolorido. Com home-href, logo e nome do sistema levam à tela inicial.
  • Sem nav, não há menu lateral nem botão de menu: serve para telas de entrada e de erro.

Conteúdo com coluna lateral ​

O BasePageAside põe a coluna lateral de 360 px à direita do conteúdo quando a área de conteúdo tem pelo menos 1080 px. Abaixo disso, a coluna vai para baixo do conteúdo. A medida é a da área de conteúdo, não a da janela: com o menu recolhido, as duas colunas aparecem em telas menores. Nesta página, estreita, elas aparecem empilhadas.

Itens da medição

Planilha da medição 29.

Resumo

Valor medido e saldo do contrato.

Histórico

Envios e devoluções.

Use para detalhe com decisão (resumo, histórico e barra de decisão na lateral) e formulário em etapas (o andamento na lateral). Na lateral, ponha o que apoia a decisão, nunca o único caminho para concluir a tarefa: no celular ela fica no fim da página. A barra de decisão vai no topo da lateral: a coluna rola com a página, então o que fica embaixo só aparece quando a pessoa chega ao fim do conteúdo.

Estilo ​

PropriedadeToken
Fundo do cabeçalho--tj-background-brand, igual nos dois temas
Texto do cabeçalho--tj-text-on-brand; secundário --tj-text-on-brand-secondary
Busca e botões no cabeçalhofundo --tj-layer-on-brand, borda --tj-border-on-brand
Altura do cabeçalho--tj-header (64 px; 56 px abaixo de 992 px)
Menu lateralfundo --tj-layer-01, borda --tj-border-subtle-02, largura --tj-sidebar (256 px; 64 px recolhido)
Item do menutexto --tj-text-secondary, hover --tj-layer-hover-01
Item atualfundo --tj-layer-selected-01, texto --tj-text-brand, barra --tj-border-interactive
Dica e ponto do menu recolhidodica com fundo --tj-background-inverse e texto --tj-text-inverse; ponto --tj-icon-interactive
Área de conteúdofundo --tj-background, largura máxima --tj-content-max (1280 px), margem --tj-space-8 (--tj-space-4 no celular)
Painel da pessoafundo --tj-layer-01, sombra --tj-shadow-2
Coluna lateral360 px, intervalo --tj-space-6
Foco no cabeçalhocontorno sólido de 2 px em --tj-text-on-brand, além do --tj-ring

Código ​

vue
<BaseAppShell
  v-model:collapsed="menuRecolhido"
  product="Gestão de Obras"
  unit="Secretaria de Engenharia"
  home-href="/"
  :nav="menu"
  user-name="Marta Coelho"
  user-role="Fiscal de contrato"
  @navigate="(item, event) => { event.preventDefault(); router.push(item.href) }"
>
  <template #logo><img src="/logo-tjes-branco.png" alt="Poder Judiciário · Tribunal de Justiça do Estado do Espírito Santo"></template>
  <template #search><BaseSearch v-model="busca" label="Buscar em todo o sistema" landmark shortcut /></template>
  <template #user-menu>
    <a href="/perfil">Meu perfil</a>
    <button type="button" @click="sair">Sair</button>
  </template>
  <BasePage title="Contrato 012/2026" subtitle="Reforma do Fórum de Alegre">
    <template #actions><BaseButton kind="secondary">Editar contrato</BaseButton></template>
    <BasePageAside>
      <BaseCard title="Medições">…</BaseCard>
      <template #aside><BaseCard title="Resumo">…</BaseCard></template>
    </BasePageAside>
  </BasePage>
</BaseAppShell>

BaseAppShell

PropriedadeTipoPadrãoDescrição
productstring—Nome do sistema ao lado do logo (obrigatório)
unitstring—Segunda linha, como a secretaria; some abaixo de 992 px
homeHrefstring—Faz do logo e do nome um link para a tela inicial
navNavGroup[][]Grupos do menu lateral; sem ele não há menu
navLabelstring'Menu principal'Nome acessível do menu lateral
v-model:collapsedbooleanfalseMenu recolhido em faixa de ícones (computador)
userNamestring—Pessoa conectada, com avatar
userRolestring—Papel da pessoa, como "Fiscal de contrato"

NavGroup: { label?: string, items: NavItem[] }. NavItem: { label: string, href: string, icon?: string, count?: number, countLabel?: string, current?: boolean }.

Slots: default (as telas), logo, search, tools, user-menu (links e botões do painel da pessoa; um <hr> separa grupos) e nav-footer (nota no pé do menu lateral, escondida quando recolhido e no celular). Eventos: navigate, com o item e o evento do clique, e update:collapsed.

BasePage

PropriedadeTipoPadrãoDescrição
titlestring—Título da tela, o único h1 (obrigatório)
subtitlestring—Linha abaixo do título com o estado da página

Slots: default (conteúdo) e actions (botões da tela, à direita do título; ocupam a largura toda no celular). Fora de um BaseAppShell, o BasePage desenha o próprio <main> num contêiner do Bootstrap, para apps que ainda não usam a moldura.

BasePageAside

Slots: default (conteúdo principal) e aside (coluna lateral de 360 px). Sem o slot aside, só o conteúdo aparece.

Acessibilidade ​

  • Segue o padrão Landmarks do WAI-ARIA APG: o cabeçalho é <header> (banner), o menu lateral é <nav> com o nome de navLabel e o conteúdo é o único <main>. Dentro da moldura, o BasePage não cria outro <main>.
  • O primeiro Tab da tela mostra o link "Pular para o conteúdo". Ele leva o foco ao <main> sem mudar o endereço, para não confundir roteadores com #.
  • No computador, o cabeçalho fica fixo no topo. A página reserva a altura dele (scroll-padding-top), então o item focado, o destino de uma âncora e o começo do conteúdo depois do link de pular nunca ficam escondidos sob o cabeçalho.
  • Cada grupo do menu é uma lista com o nome do seu título. A tela aberta tem aria-current="page", e o leitor de tela anuncia "página atual".
  • O botão de menu tem nome fixo, "Menu lateral", e diz o estado por aria-expanded; aria-controls aponta para o menu. "Recolhido" quer dizer só ícones: os links continuam todos na ordem de leitura e de Tab.
  • Recolhido, cada item mantém o nome e a quantidade para o leitor de tela. O nome aparece numa dica ao lado do ícone, tanto com o mouse quanto com o foco do teclado, e Esc esconde a dica sem mover o foco. Um ponto sobre o ícone avisa que o item tem quantidade acima de zero.
  • O painel da pessoa segue o padrão Disclosure: o botão diz aria-expanded, os itens são links e botões comuns, alcançados com Tab. Esc fecha e devolve o foco ao botão; clicar fora, escolher um item ou sair do painel com Tab também fecha. Ao escolher um item, o foco volta ao botão, a não ser que o próprio item o tenha levado a outro lugar, como um modal. Ele não é um role="menu", então as setas não são prometidas.
  • No celular, o nome da pessoa e o nome do sistema saem da tela, mas continuam para o leitor de tela no botão da pessoa e no bloco do logo (um link, com home-href).
  • O foco no cabeçalho ganha contorno branco sólido, porque o anel translúcido não chega a 3:1 sobre o azul-marinho.
  • As transições do menu recolhido, do link de pular e da seta do painel somem com prefers-reduced-motion. Em alto contraste do Windows, o item atual ganha contorno e o cabeçalho, borda.
  • Os testes passam o axe em jsdom com o menu aberto, sem menu, com o painel da pessoa aberto e com página e coluna lateral, e rodam as regras de página inteira (region, bypass, marcos únicos) com a moldura completa. O jsdom não aplica CSS, então o menu recolhido, o contraste e as quebras de layout são conferidos nas páginas desta documentação.
  • Nesta documentação, os exemplos ficam dentro do <main> da própria página, então aparecem com um <main> aninhado e um cabeçalho que não é o banner. Os marcos foram conferidos nos testes, não aqui.