{% from "ui/attrs.html" import attrs %} {% from "ui/icon.html" import icon %} {# button(label, variant, size, href, icon_name, …, **html_attrs) — a button, or an anchor styled as one when `href` is given. variant: primary | secondary | outline | ghost | link | destructive size: xs | sm | default | lg | icon | icon-sm | icon-xs The signature accepts no class string. Callers pick a variant, never a colour: the parameter list is the contract, and a named parameter can refuse what a class attribute cannot. Variants and sizes are attributes, not classes (`data-variant="primary"`), because that is Basecoat's API. Extend it the same way; never invent a parallel `btn-primary` class. #} {% macro button(label, variant="", size="", type="button", href=none, icon_name=none, icon_end=false, disabled=false) -%} {%- set tag = "a" if href else "button" -%} <{{ tag }} class="btn" {%- if variant %} data-variant="{{ variant }}"{% endif %} {%- if size %} data-size="{{ size }}"{% endif %} {%- if href %} href="{{ href }}"{% else %} type="{{ type }}"{% endif %} {%- if disabled %} disabled{% endif %} {%- if kwargs %}{{ attrs(kwargs) }}{% endif %}> {%- if icon_name and not icon_end %}{{ icon(icon_name) }}{% endif -%} {{ label }} {%- if icon_name and icon_end %}{{ icon(icon_name) }}{% endif -%} {%- endmacro %} {# button_group() — a run of related buttons, e.g. a filter bar. {% call button_group() %} {% for value, label in filters %} {{ button(label, size="xs", variant="ghost", hx_get=…) }} {% endfor %} {% endcall %} #} {% from "ui/attrs.html" import attrs %} {% from "ui/layout.html" import row %} {% macro button_group(gap=2, orientation="horizontal") -%} {# Capture `caller()` before the inner {% call %}. Jinja rebinds `caller` inside a call block to that block's own caller, so a macro that forwards its body into another block macro reads the inner, non-existent caller and raises "No caller defined". Every composite macro here captures first. #} {%- set body = caller() -%} {# Basecoat's `.button-group` already reads `data-orientation="vertical"`: it flips the flex direction and moves the shared borders to the horizontal edges. Exposing it costs one branch and saves every app that needs a column of choices from writing `flex-col` itself. #} {%- if orientation == "vertical" -%}
{{ body }}
{%- else -%} {% call row(gap=gap, align="center", **kwargs) %}{{ body }}{% endcall %} {%- endif -%} {%- endmacro %}