Início
Boas práticas
Tema
Idiomas e RTL
App e cabeçalho
Layout
Tipografia
Abas
Menu e âncora
Dropdown e popover
Command e toggles
Botão
Campos
Seleção e valores
Combobox e menções
Datas e calendário
Árvore e cascata
Transfer
Upload
Filtros
Tabela
Planilha
KPI e estatística
Badge e tag
Listas e detalhes
Gráficos
Imagem e carrossel
Ícones
Diagramas
Alertas e estados
Progresso e passos
Diálogo e toast
Drawer e notificação
Utilitários
Overview
Work queue
Report
Report com htmx
Form / request
Tabela administrativa
Página de detalhe
Formulário em diálogo
Gráfico com dados do servidor
Buscar…
llms.txt
Tema
Tema
Restaurar
Copiar prompt
Copiar snippet
Prompt: para as instruções de um agente. Snippet: direto no templates/base.html.
v0.11.0
Abrir em tela cheia
<ab-app brand-name="Acme Finanças" user-email="ana.souza@acme.com">
<a slot="nav" href="#" aria-current="page">Visão geral</a>
<a slot="nav" href="#">Contas a receber</a>
<a slot="nav" href="#">Conciliação</a>
<ab-page-header heading="Bom dia, Ana" description="Situação do caixa hoje">
<ab-button slot="actions" icon="arrows-clockwise" id="refresh">Atualizar</ab-button>
</ab-page-header>
<ab-stack gap="5">
<ab-grid cols="4" min="12rem">
<ab-kpi id="k1" label="Saldo em conta" icon="bank" type="currency" loading></ab-kpi>
<ab-kpi id="k2" label="A receber (7 dias)" icon="arrow-down-left" type="currency" loading></ab-kpi>
<ab-kpi id="k3" label="A pagar (7 dias)" icon="arrow-up-right" type="currency" loading></ab-kpi>
<ab-kpi id="k4" label="Inadimplência" type="percent" invert-delta loading></ab-kpi>
</ab-grid>
<ab-split side="end" side-width="22rem">
<ab-table id="due" heading="Vencendo esta semana" clickable></ab-table>
<ab-card slot="side" heading="Atenção">
<ab-stack gap="3">
<ab-alert tone="warn">3 boletos sem conciliação há mais de 5 dias.</ab-alert>
<ab-alert tone="info">Última sincronização com o ERP há 12 min.</ab-alert>
</ab-stack>
</ab-card>
</ab-split>
</ab-stack>
</ab-app>
<script type="module">
// Simula a função Python get_overview() (na Page real ela é gerada pelo @register_function).
const get_overview = () => new Promise((r) => setTimeout(() => r({
saldo: 1284300.12, receber: 214500, pagar: 98210.5, inadimplencia: 0.031, delta_inad: -0.004,
due: [
{ cliente: "Padaria Pão Dourado", vencimento: "2026-11-07", valor: 1890.4, status: "A vencer" },
{ cliente: "Clínica Bem Viver", vencimento: "2026-11-05", valor: 12500, status: "Atrasado" },
{ cliente: "Oficina Rota 66", vencimento: "2026-11-09", valor: 420, status: "A vencer" },
],
}), 700));
const t = document.getElementById("due");
t.columns = [
{ key: "cliente", label: "Cliente" },
{ key: "vencimento", label: "Vencimento", type: "date" },
{ key: "valor", label: "Valor", type: "currency" },
{ key: "status", label: "Status", type: "badge", tones: { Atrasado: "danger", "A vencer": "neutral" } },
];
// Uma chamada alimenta vários componentes: abLoad liga o loading de todos e o apply distribui os dados.
const kpis = ["k1", "k2", "k3", "k4"].map((id) => document.getElementById(id));
const load = () => abLoad([...kpis, t], get_overview, {
apply: (data, el) => {
if (el === t) t.rows = data.due;
else Object.assign(el, { k1: { value: data.saldo }, k2: { value: data.receber }, k3: { value: data.pagar }, k4: { value: data.inadimplencia, delta: data.delta_inad } }[el.id]);
},
});
document.getElementById("refresh").addEventListener("click", load);
load();
</script>
# page_overview.py — __render__ only renders the shell; data comes after first paint.
from abstra.pages import register_function
from abstra.tables import select
from lib_jinja import render_template
@register_function
def __render__():
return render_template("overview.html", title="Visão geral", active="overview")
@register_function
def get_overview():
due = select("receivables", where={"status": "open"}, order_by="due_date", limit=10)
return {
"saldo": 1284300.12,
"receber": sum(r["amount"] for r in due),
"due": [
{"cliente": r["customer"], "vencimento": r["due_date"], "valor": r["amount"], "status": r["status_label"]}
for r in due
],
}