{#
Tungsten UI kit — the small building blocks every page reuses.
Import with: {% import "tungsten/components/ui.html" as ui %}
#}
{# ---------------------------------------------------------------- buttons #}
{% macro button_classes(color='primary', style='button', size='md', outlined=false) -%}
{%- set sizes = {'sm': 'px-2.5 py-1.5 text-xs', 'md': 'px-3 py-2 text-sm', 'lg': 'px-4 py-2.5 text-sm'} -%}
{%- if style == 'link' -%}
inline-flex items-center gap-1.5 text-sm font-semibold {{ colors.pick(colors.LINK, color) }}
{%- elif style == 'icon' -%}
inline-flex h-9 w-9 items-center justify-center rounded-lg bg-white ring-1 ring-gray-950/10 transition dark:bg-white/5 dark:ring-white/10 {{ colors.pick(colors.ICON_BUTTON, color if color != 'primary' else 'gray') }}
{%- elif style == 'soft' -%}
tw-btn {{ sizes.get(size, sizes.md) }} {{ colors.pick(colors.SOFT_BUTTON, color) }}
{%- elif style == 'dropdown' -%}
flex w-full items-center gap-2 rounded-md px-2 py-2 text-start text-sm transition hover:bg-gray-50 dark:hover:bg-white/5 {{ colors.pick(colors.TEXT, color) if color not in ('primary', 'gray') else 'text-gray-700 dark:text-gray-200' }}
{%- elif outlined -%}
tw-btn {{ sizes.get(size, sizes.md) }} bg-white ring-1 ring-gray-950/10 dark:bg-transparent dark:ring-white/20 {{ colors.pick(colors.LINK, color) }}
{%- else -%}
tw-btn {{ sizes.get(size, sizes.md) }} {{ colors.pick(colors.BUTTON, color) }}
{%- endif -%}
{%- endmacro %}
{% macro button(label, color='primary', icon_name=None, href=None, type='button', style='button', size='md', attrs_='', outlined=false) %}
{% set label = __(label) %}
{% if href %}
{{ icon(icon_name, 'h-4 w-4' if size != 'lg' else 'h-5 w-5') }}{{ label }}
{% else %}
{% endif %}
{% endmacro %}
{% macro icon_button(icon_name, label, color='gray', href=None, attrs_='', bordered=true) %}
{% set label = __(label) %}
{% set cls = button_classes(color, 'icon') if bordered else 'tw-icon-btn ' ~ colors.pick(colors.ICON_BUTTON, color) %}
{% if href %}
{{ icon(icon_name, 'h-4 w-4') }}
{% else %}
{% endif %}
{% endmacro %}
{# ---------------------------------------------------------------- badges #}
{% macro badge(text, color='gray', icon_name=None, size='sm') %}
{{ icon(icon_name, 'h-3.5 w-3.5') }}{{ text }}
{% endmacro %}
{% macro count_pill(n, color='primary') %}
{% if n is not none and n != '' %}
{{ n }}
{% endif %}
{% endmacro %}
{# ---------------------------------------------------------------- avatar #}
{% macro avatar(name, url=None, size='h-9 w-9', text='text-sm') %}
{% if url %}
{{ description }}
{% else %}
{% set parts = (name or '?').split() %}
{% set tones = ['bg-primary-100 text-primary-700 dark:bg-primary-500/20 dark:text-primary-300', 'bg-info-100 text-info-700 dark:bg-info-500/20 dark:text-info-300', 'bg-success-100 text-success-700 dark:bg-success-500/20 dark:text-success-300', 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300', 'bg-pink-100 text-pink-700 dark:bg-pink-500/20 dark:text-pink-300', 'bg-teal-100 text-teal-700 dark:bg-teal-500/20 dark:text-teal-300', 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300'] %}
{% set ns = namespace(h=0) %}{% for ch in (name or '?') %}{% set ns.h = ns.h + ch | string | length * loop.index * (ch | ord_value) %}{% endfor %}
{{- (parts[0][0] ~ (parts[-1][0] if parts | length > 1 else '')) | upper -}}
{% endif %}
{% endmacro %}
{# ---------------------------------------------------------------- cards #}
{% macro card(heading=None, description=None, padding='p-6', classes='', link=None, link_label='View all') %}
{{ heading }}
{% if description %}
{{ description }}
{% endif %} {% if caller %}{{ icon('arrow-up' if direction == 'up' else 'arrow-down', 'h-4 w-4') }}{{ value }} {% if suffix %}{{ suffix }}{% endif %}
{% endmacro %} {% macro sparkline(points, color='primary', id='spark') %} {% if points and points | length > 1 %} {% set lo = points | min %}{% set hi = points | max %}{% set span = (hi - lo) or 1 %} {% set n = points | length - 1 %} {% set ns = namespace(d='') %} {% for p in points %} {% set x = (loop.index0 / n * 100) | round(2) %}{% set y = (36 - (p - lo) / span * 32) | round(2) %} {% set ns.d = ns.d ~ ('M' if loop.first else ' L') ~ x ~ ' ' ~ y %} {% endfor %} {% endif %} {% endmacro %} {% macro stat_card(label, value, icon_name=None, color='primary', description=None, trend_value=None, trend_direction='up', trend_color=None, chart=None, url=None, id='stat') %} {% set tag = 'a' if url else 'div' %} <{{ tag }} {% if url %}href="{{ url }}"{% endif %} class="tw-card relative block overflow-hidden p-5 {{ 'transition hover:ring-primary-500/40' if url }}">{{ label }}
{{ value }}
{{ icon('arrow-up' if trend_direction == 'up' else 'arrow-down', 'h-4 w-4') }}{{ trend_value }}
{% set description = description or __('vs last month') %}{{ description }}
{% elif description %}{{ description }}
{% endif %}