{#
table.html
==========
"Recent Orders / Recent Comments" style table widget — modeled
on the user-supplied reference. The widget card itself (card
bg, border, rounded corners) is already provided by the
dashboard grid's per-widget wrapper. This macro fills that
card with:
• Compact title row + optional "View all →" link
• Distinct header band (one notch darker than the card bg)
• Row body in `bg-surface-container` (the card bg) — no
zebra; visual rhythm comes from hairline dividers on
`surface-container-highest`
• First column heavier (`text-on-surface`, `font-medium`,
`whitespace-nowrap`) — that's the row's "anchor" cell,
matches the `<th scope="row">` pattern in the reference
• Other columns softer (`text-on-surface-variant`)
• Last row drops its bottom border
Expects payload:
{
columns: [{key, label}],
rows: [{key: value, ...}],
view_all_url: Option<String>,
}
#}
{% macro table_widget(title, payload) %}
<div class="table-widget h-full flex flex-col">
{# Header: title (left) + View all link (right) ============== #}
<div class="px-md pt-md pb-sm flex-shrink-0 flex items-center justify-between gap-sm">
<p class="text-label-sm text-outline uppercase tracking-wider truncate">{{ title }}</p>
{% if payload.view_all_url %}
<a
href="{{ payload.view_all_url }}"
class="text-label-sm text-on-surface-variant hover:text-primary transition-colors inline-flex items-center gap-1 flex-shrink-0 no-underline"
>
View all
<i data-lucide="arrow-up-right" class="w-3.5 h-3.5"></i>
</a>
{% endif %}
</div>
{% if payload.columns and payload.rows and payload.rows | length > 0 %}
<div class="flex-1 min-h-0 px-md pb-md overflow-hidden">
<div class="h-full overflow-auto rounded-xl border border-outline-variant bg-surface-container-low shadow-sm">
<table class="w-full text-left border-collapse text-[15px] leading-snug text-on-surface-variant">
{# Header — sticky, denser, and visually joined to the rounded
table shell so the widget reads as an actual data table. #}
<thead class="sticky top-0 z-10 bg-surface-container-high border-b border-outline-variant">
<tr>
{% for col in payload.columns %}
<th
scope="col"
class="px-md py-sm font-label-md text-label-md text-on-surface-variant uppercase tracking-wider whitespace-nowrap"
>{{ col.label }}</th>
{% endfor %}
</tr>
</thead>
<tbody class="divide-y divide-divider-soft dark:divide-gray-800/70">
{% for row in payload.rows %}
{# Alternating surface tokens give row rhythm without making the
compact dashboard table feel grid-heavy. #}
<tr class="{% if loop.index0 % 2 == 0 %}bg-surface-container{% else %}bg-surface-container-low{% endif %} hover:bg-surface-container-high transition-colors">
{% for col in payload.columns %}
{%- set v = row[col.key] -%}
{%- set vstr = "" if v is none else (v | string) -%}
{% if loop.first %}
{# Row anchor cell — heavier weight, stronger color, no
wrap. Matches the reference's `<th scope="row">`
pattern (the leftmost column tells you which entity
the row is about). #}
<th
scope="row"
class="px-md py-sm font-medium text-on-surface whitespace-nowrap truncate max-w-[220px]"
title="{{ vstr }}"
>{{ vstr }}</th>
{% else %}
<td
class="px-md py-sm truncate max-w-[200px] tabular-nums"
title="{{ vstr }}"
>{{ vstr }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% else %}
<p class="text-label-sm text-outline italic px-md py-md mt-auto">No data</p>
{% endif %}
</div>
{% endmacro %}