Ir para o conteúdo
Secções
Idioma, atualmente Português
Sistema de design Rastrillo

Apresentação

As peças pequenas de vocabulário com que se monta um ecrã: estado, identidade, progresso e a única forma de aviso.

Cada exemplo funciona de verdade, mas as suas ligações não levam a lado nenhum. HTML mostra a marcação para copiar.

status-pill

O estado de um registo como uma etiqueta colorida, com cor e texto.

Pré-visualização

neutral

<span rst-status rst-tone="neutral">Rascunho</span>

positive

<span rst-status rst-tone="positive">Publicado</span>

warning

<span rst-status rst-tone="warning">Agendado</span>

negative

<span rst-status rst-tone="negative">Falhou</span>

neutral

{{template "status-pill" dict "Label" "Rascunho"}}

positive

{{template "status-pill" dict "Label" "Publicado" "Tone" "positive"}}

warning

{{template "status-pill" dict "Label" "Agendado" "Tone" "warning"}}

negative

{{template "status-pill" dict "Label" "Falhou" "Tone" "negative"}}

neutral Tone é neutral por omissão, por isso esta chamada omite-o.

badge

Uma etiqueta com contorno em maiúsculas, para marcas pequenas e fixas. Diferente do status-pill, que é o estado de um registo.

Pré-visualização

Sem tom (o valor predefinido discreto)

<span rst-badge>Rascunho</span>

neutral

<span rst-badge="neutral">Interno</span>

positive

<span rst-badge="positive">Ativo</span>

warning

<span rst-badge="warning">Beta</span>

negative

<span rst-badge="negative">Esgotado</span>

Sem tom (o valor predefinido discreto)

{{template "badge" dict "Label" "Rascunho"}}

neutral

{{template "badge" dict "Label" "Interno" "Tone" "neutral"}}

positive

{{template "badge" dict "Label" "Ativo" "Tone" "positive"}}

warning

{{template "badge" dict "Label" "Beta" "Tone" "warning"}}

negative

{{template "badge" dict "Label" "Esgotado" "Tone" "negative"}}

meter

Uma barra de capacidade com o seu número.

Pré-visualização

Vazio

<span rst-meter>
  <meter rst-meter-bar value="0" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>0/500</span>
</span>

A meio

<span rst-meter>
  <meter rst-meter-bar value="42" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>210/500</span>
</span>

Quase cheio

<span rst-meter>
  <meter rst-meter-bar value="82" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>412/500</span>
</span>

Cheio

<span rst-meter>
  <meter rst-meter-bar value="100" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>500/500</span>
</span>

Acima do limite

<span rst-meter>
  <meter rst-meter-bar value="100" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>700/500</span>
</span>

Vazio

{{template "meter" dict "Percent" 0 "Text" "0/500"}}

A meio

{{template "meter" dict "Percent" 42 "Text" "210/500"}}

Quase cheio

{{template "meter" dict "Percent" 82 "Text" "412/500"}}

Cheio

{{template "meter" dict "Percent" 100 "Text" "500/500"}}

Acima do limite

{{template "meter" dict "Percent" 140 "Text" "700/500"}}

Acima do limite O preenchimento é limitado a 100% no parcial.

stat

Um número num painel, com uma etiqueta e quanto mudou.

O número grande

Pré-visualização

Coloque isto dentro de <div rst-stats>.

<div rst-stat="lead">
  <span rst-stat-label>Receita deste mês</span>
  <span rst-stat-num>€48,210</span>
  <span rst-stat-delta rst-tone="positive">&#43;12%</span>
  <span rst-stat-note>face ao mês passado</span>
</div>

Coloque isto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Receita deste mês"
    "Value" "€48,210"
    "Delta" "+12%"
    "Tone" "positive"
    "Note" "face ao mês passado"
    "Lead" true}}

Acrescente Lead a um número da linha para o tornar grande. É o mesmo componente, apenas maior.

Um número mais pequeno

Pré-visualização

Coloque isto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Faturas por pagar</span>
  <span rst-stat-num>24</span>
</div>

Coloque isto dentro de <div rst-stats>.

{{template "stat" dict "Label" "Faturas por pagar" "Value" "24"}}

Só precisa de uma etiqueta e um número. Tudo o resto é opcional.

Quando descer é bom

Pré-visualização

Coloque isto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Tempo até à primeira resposta</span>
  <span rst-stat-num>1 h 12 min</span>
  <span rst-stat-delta rst-tone="positive">−38%</span>
  <span rst-stat-note>face à semana passada</span>
</div>

Coloque isto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Tempo até à primeira resposta"
    "Value" "1 h 12 min"
    "Delta" "−38%"
    "Tone" "positive"
    "Note" "face à semana passada"}}

A cor decide-a você, não o componente. Aqui o número desceu e isso é boa notícia, por isso a variação está a verde.

Quando subir é mau

Pré-visualização

Coloque isto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Pagamentos falhados</span>
  <span rst-stat-num>9</span>
  <span rst-stat-delta rst-tone="negative">&#43;3</span>
  <span rst-stat-note>face à semana passada</span>
</div>

Coloque isto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Pagamentos falhados"
    "Value" "9"
    "Delta" "+3"
    "Tone" "negative"
    "Note" "face à semana passada"}}

Aqui o número subiu e isso é má notícia, por isso a variação está a vermelho.

Quando não se pode dizer

Pré-visualização

Coloque isto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Duração média da sessão</span>
  <span rst-stat-num>4 min 12 s</span>
  <span rst-stat-delta rst-tone="neutral">&#43;18 s</span>
  <span rst-stat-note>desde sexta-feira</span>
</div>

Coloque isto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Duração média da sessão"
    "Value" "4 min 12 s"
    "Delta" "+18 s"
    "Note" "desde sexta-feira"}}

Deixe a cor de fora e a variação fica cinzenta. Faça isso quando não puder dizer se é boa ou má.

Um número encurtado

Pré-visualização

Coloque isto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Mensagens enviadas</span>
  <span rst-stat-num><data value="4120">4.1k</data></span>
</div>

Coloque isto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Mensagens enviadas"
    "Value" "4.1k"
    "Exact" "4120"}}

Está a mostrar 4.1k em vez de 4120? Ponha o número completo em Exact. Os leitores de ecrã só leem o que está no ecrã, por isso mantenha no próprio número tudo o que uma pessoa precise.

person

Avatar com iniciais, nome e email. Serve para identificar depressa os registos de pessoas.

Nome e e-mail

Pré-visualização
<a rst-person href="/people/1">
  <span rst-person-av aria-hidden="true">G</span>
  <span rst-person-meta>
    <span rst-person-name>Grace Hopper</span>
    <span rst-person-email>grace@example.com</span>
  </span>
</a>
{{template "person" dict
    "Href" "/people/1"
    "Name" "Grace Hopper"
    "Email" "grace@example.com"
    "Initial" "G"}}

Grande, o tamanho do cabeçalho de detalhe

Pré-visualização
<a rst-person="lg" href="/people/2">
  <span rst-person-av aria-hidden="true">A</span>
  <span rst-person-meta>
    <span rst-person-name>Ada Lovelace</span>
    <span rst-person-email>ada@example.com</span>
  </span>
</a>
{{template "person" dict
    "Href" "/people/2"
    "Name" "Ada Lovelace"
    "Email" "ada@example.com"
    "Initial" "A"
    "Large" true}}

Sem inicial

Pré-visualização
<a rst-person href="/people/3">
  <span rst-person-av="empty" aria-hidden="true"></span>
  <span rst-person-meta>
    <span rst-person-name>Convite por aceitar</span>
    <span rst-person-email>invited@example.com</span>
  </span>
</a>
{{template "person" dict
    "Href" "/people/3"
    "Name" "Convite por aceitar"
    "Email" "invited@example.com"}}

actor

Quem fez algo, em palavras: o nome de uma pessoa, ou o agente e a pessoa por quem agiu. Sem distintivo nem ícone.

Um agente a agir por uma pessoa

Pré-visualização
<span rst-actor>Claude para Grace Hopper</span>
{{template "actor" dict "Actor" .Actor}}

Defina ui.ActorName uma vez no arranque para transformar um sujeito num nome. A própria aplicação, o Actor zero, não renderiza nada.

Uma pessoa

Pré-visualização
<span rst-actor>Grace Hopper</span>
{{template "actor" dict "Actor" .Actor}}

callout

O único vocabulário de avisos: faixa com cor, ícone de tom, título a negrito opcional e um parágrafo de corpo.

info

Pré-visualização
<div rst-callout rst-tone="info">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
  </span>
  <div rst-callout-body>
    <p>As publicações só são visíveis para membros até o site ser publicado.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "As publicações só são visíveis para membros até o site ser publicado."
    "Tone" "info"}}

positive

Pré-visualização
<div rst-callout rst-tone="positive">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
  </span>
  <div rst-callout-body>
    <strong>Os pagamentos estão ligados</strong>
    <p>Já pode receber pagamentos pelos bilhetes.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "Já pode receber pagamentos pelos bilhetes."
    "Title" "Os pagamentos estão ligados"
    "Tone" "positive"}}

warning

Pré-visualização
<div rst-callout rst-tone="warning">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
  </span>
  <div rst-callout-body>
    <strong>Ligue os pagamentos para começar a vender</strong>
    <p>O seu evento está ativo, mas ainda não pode receber pagamentos.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "O seu evento está ativo, mas ainda não pode receber pagamentos."
    "Title" "Ligue os pagamentos para começar a vender"
    "Tone" "warning"}}

negative

Pré-visualização
<div rst-callout rst-tone="negative">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>
  </span>
  <div rst-callout-body>
    <strong>A última importação falhou</strong>
    <p>Nada foi alterado. Corrija a linha 91 e tente de novo.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "Nada foi alterado. Corrija a linha 91 e tente de novo."
    "Title" "A última importação falhou"
    "Tone" "negative"}}

negative, anunciado como alerta

Pré-visualização
<div rst-callout rst-tone="negative" role="alert">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>
  </span>
  <div rst-callout-body>
    <strong>A importação parou</strong>
    <p>Nada foi alterado. Corrija a linha 91 e tente de novo.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "Nada foi alterado. Corrija a linha 91 e tente de novo."
    "Title" "A importação parou"
    "Tone" "negative"
    "Alert" true}}

alert acrescenta role="alert" para mostrar mensagens importantes.

detail-list

Lista de definições sobre um registo num ecrã de detalhe. A marca mono é para valores de aspeto técnico.

Quatro dados, um de aspeto técnico

Pré-visualização

Coloque isto dentro de <section rst-box>.

<dl rst-detail>
  <dt>Público</dt>
  <dd>Membros</dd>
  <dt>Página principal</dt>
  <dd>Não</dd>
  <dt>Publicado</dt>
  <dd>
    <time datetime="2026-08-02">2 de agosto de 2026</time>
  </dd>
  <dt>Referência</dt>
  <dd class="rst-mono">post_01H9ZQ</dd>
</dl>

Coloque isto dentro de <section rst-box>.

{{template "detail-list" dict
    "Items" (list
        (dict "Label" "Público" "Value" "Membros")
        (dict "Label" "Página principal" "Value" "Não")
        (dict "DateTime" "2026-08-02" "Label" "Publicado" "Value" "2 de agosto de 2026")
        (dict "Label" "Referência" "Mono" true "Value" "post_01H9ZQ"))}}

notice

Uma confirmação de uma linha depois de um redirecionamento. Recebe uma cadeia simples, não um dict, e não desenha nada se estiver vazia.

Uma mensagem de guardado

Pré-visualização
<p rst-notice role="status">Publicação guardada.</p>
{{template "notice" "Publicação guardada."}}

region:notice

O aviso que cada moldura mantém na página, com o Notice dos dados da página, para que um leitor de ecrã ouça a mensagem e o live.js a possa preencher no lugar.

Uma mensagem de guardado

Pré-visualização
<div id="notice" role="status">
  <p rst-notice>Publicação guardada.</p>
</div>
{{template "region:notice" dict "Notice" "Publicação guardada."}}

form-error

A linha de resumo de erros de um formulário, role="alert". Recebe uma cadeia simples; não desenha nada quando não há erro.

Um envio recusado

Pré-visualização
<p rst-form-error role="alert">Esse título já está a ser usado.</p>
{{template "form-error" "Esse título já está a ser usado."}}

job-status

O fragmento consultado de uma tarefa em segundo plano. O atributo data-poll só é emitido enquanto a tarefa corre: omiti-lo é a forma de parar a consulta.

A decorrer

Pré-visualização

<div rst-job data-poll="/jobs/1/fragment" data-poll-every="2">
  <span rst-spin aria-hidden="true"></span> <bdi><strong>Importação</strong></bdi> em curso: <bdi>128 de 400</bdi>…
  <progress rst-job-bar value="32" min="0" max="100" aria-hidden="true"></progress>
</div>
{{template "job-status" dict
    "Name" "Importação"
    "Percent" 32
    "PollSeconds" 2
    "PollURL" "/jobs/1/fragment"
    "Progress" "128 de 400"
    "Status" "running"}}

Este faz consultas: é a única amostra da página que pede alguma coisa à rede e, num site estático, nunca chega a resolver-se.

Terminado

Pré-visualização

<div rst-job>
  <bdi><strong>Importação</strong></bdi> terminou.
</div>
{{template "job-status" dict "Name" "Importação" "Status" "done"}}

Falhou

Pré-visualização

<div rst-job>
  <bdi><strong>Importação</strong></bdi> falhou: <bdi>row 91: no such column &#34;published&#34;</bdi>
</div>
{{template "job-status" dict
    "Err" "row 91: no such column \"published\""
    "Name" "Importação"
    "Status" "failed"}}