{# UI Component Macros - Tailwind CSS with Dark Mode #} {# Use these macros for consistent, maintainable UI components #} {# All components support dark mode via dark: variants #} {# ============================================================================ BUTTONS Usage: {{ btn("Submit", variant="primary") }} {{ btn("Cancel", variant="secondary", size="sm") }} {{ btn_link("Delete", href="/delete", variant="danger") }} ============================================================================ #} {# Base button classes - shared across all button variants #} {% set _btn_base = "inline-flex items-center justify-center gap-2 font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-slate-900 disabled:opacity-50 disabled:cursor-not-allowed" %} {# Size variants #} {% set _btn_sizes = { "sm": "px-2.5 py-1.5 text-xs", "md": "px-4 py-2 text-sm", "lg": "px-5 py-2.5 text-base" } %} {# Color variants with dark mode #} {% set _btn_variants = { "primary": "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500 border border-transparent dark:bg-blue-500 dark:hover:bg-blue-600", "secondary": "bg-white text-slate-700 hover:bg-slate-50 focus:ring-slate-500 border border-slate-300 dark:bg-slate-800 dark:text-slate-200 dark:border-slate-600 dark:hover:bg-slate-700", "success": "bg-green-600 text-white hover:bg-green-700 focus:ring-green-500 border border-transparent dark:bg-green-500 dark:hover:bg-green-600", "danger": "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500 border border-transparent dark:bg-red-500 dark:hover:bg-red-600", "warning": "bg-amber-500 text-white hover:bg-amber-600 focus:ring-amber-500 border border-transparent dark:bg-amber-400 dark:hover:bg-amber-500", "ghost": "bg-transparent text-slate-600 hover:bg-slate-100 focus:ring-slate-500 border border-transparent dark:text-slate-300 dark:hover:bg-slate-800", "link": "bg-transparent text-blue-600 hover:text-blue-700 hover:underline focus:ring-blue-500 border-none p-0 dark:text-blue-400 dark:hover:text-blue-300" } %} {# Button macro - renders a {% endmacro %} {# Button link macro - renders an styled as a button #} {% macro btn_link(text, href, variant="primary", size="md", target="", classes="") %} {{ text }} {% endmacro %} {# Icon button macro - button with just an icon #} {% macro btn_icon(icon_html, variant="ghost", size="md", type="button", onclick="", title="", classes="") %} {% endmacro %} {# ============================================================================ FORMS Usage: {{ form_input("email", label="Email", type="email", required=true) }} {{ form_select("role", label="Role", options=roles) }} {{ form_textarea("query", label="SQL Query", rows=6) }} ============================================================================ #} {# Input classes with dark mode #} {% set _input_base = "w-full px-3 py-2 text-sm border border-slate-300 rounded-md bg-white text-slate-900 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:bg-slate-50 disabled:text-slate-500 dark:bg-slate-800 dark:border-slate-600 dark:text-white dark:placeholder-slate-500 dark:disabled:bg-slate-900 dark:disabled:text-slate-400" %} {# Form group wrapper with dark mode #} {% macro form_group(label="", id="", required=false, help_text="", error="") %}
{% if label %} {% endif %} {{ caller() }} {% if help_text %}

{{ help_text }}

{% endif %} {% if error %}

{{ error }}

{% endif %}
{% endmacro %} {# Text input #} {% macro form_input(name, label="", type="text", value="", placeholder="", required=false, disabled=false, readonly=false, id="", help_text="", error="", classes="") %} {% set input_id = id or name %} {% call form_group(label=label, id=input_id, required=required, help_text=help_text, error=error) %} {% endcall %} {% endmacro %} {# Select dropdown #} {% macro form_select(name, label="", options=[], value="", required=false, disabled=false, id="", help_text="", error="", classes="") %} {% set input_id = id or name %} {% call form_group(label=label, id=input_id, required=required, help_text=help_text, error=error) %} {% endcall %} {% endmacro %} {# Textarea #} {% macro form_textarea(name, label="", value="", placeholder="", rows=4, required=false, disabled=false, readonly=false, id="", help_text="", error="", classes="") %} {% set input_id = id or name %} {% call form_group(label=label, id=input_id, required=required, help_text=help_text, error=error) %} {% endcall %} {% endmacro %} {# Checkbox with dark mode #} {% macro form_checkbox(name, label="", checked=false, disabled=false, id="", help_text="", classes="") %} {% set input_id = id or name %}
{% if help_text %}

{{ help_text }}

{% endif %}
{% endmacro %} {# ============================================================================ CARDS Usage: {% call card(title="My Card", subtitle="Optional subtitle") %} Content here {% endcall %} ============================================================================ #} {% macro card(title="", subtitle="", classes="") %}
{% if title %}

{{ title }}

{% if subtitle %}

{{ subtitle }}

{% endif %}
{% endif %}
{{ caller() }}
{% endmacro %} {% macro card_header(title="", subtitle="") %}

{{ title }}

{% if subtitle %}

{{ subtitle }}

{% endif %}
{{ caller() }}
{% endmacro %} {% macro card_body(classes="") %}
{{ caller() }}
{% endmacro %} {# Stat card for dashboards #} {% macro stat_card(label, value, icon="", trend="", trend_up=true, classes="") %}

{{ label }}

{{ value }}

{% if trend %}

{% if trend_up %}↑{% else %}↓{% endif %} {{ trend }}

{% endif %}
{% if icon %}
{{ icon|safe }}
{% endif %}
{% endmacro %} {# ============================================================================ ALERTS Usage: {{ alert("Success!", variant="success") }} {{ alert("Error occurred", variant="error", dismissible=true) }} ============================================================================ #} {% set _alert_variants = { "success": "bg-green-50 border-green-200 text-green-800 dark:bg-green-900/30 dark:border-green-800 dark:text-green-300", "error": "bg-red-50 border-red-200 text-red-800 dark:bg-red-900/30 dark:border-red-800 dark:text-red-300", "warning": "bg-amber-50 border-amber-200 text-amber-800 dark:bg-amber-900/30 dark:border-amber-800 dark:text-amber-300", "info": "bg-blue-50 border-blue-200 text-blue-800 dark:bg-blue-900/30 dark:border-blue-800 dark:text-blue-300" } %} {% macro alert(message, variant="info", title="", dismissible=false, id="") %} {% endmacro %} {# ============================================================================ BADGES / STATUS Usage: {{ badge("Active", variant="success") }} {{ status_dot("success") }} Active ============================================================================ #} {% set _badge_variants = { "default": "bg-slate-100 text-slate-700 dark:bg-slate-700 dark:text-slate-300", "primary": "bg-blue-100 text-blue-800 dark:bg-blue-900/50 dark:text-blue-300", "success": "bg-green-100 text-green-800 dark:bg-green-900/50 dark:text-green-300", "warning": "bg-amber-100 text-amber-800 dark:bg-amber-900/50 dark:text-amber-300", "error": "bg-red-100 text-red-800 dark:bg-red-900/50 dark:text-red-300", "info": "bg-cyan-100 text-cyan-800 dark:bg-cyan-900/50 dark:text-cyan-300" } %} {% macro badge(text, variant="default", size="md", classes="") %} {% set size_classes = "px-2 py-0.5 text-xs" if size == "sm" else "px-2.5 py-1 text-xs" %} {{ text }} {% endmacro %} {% macro status_dot(status="default", classes="") %} {% set colors = { "success": "bg-green-500", "error": "bg-red-500", "warning": "bg-amber-500", "info": "bg-blue-500", "default": "bg-slate-400 dark:bg-slate-500" } %} {% endmacro %} {# ============================================================================ TABLES Usage: {% call table(headers=["Name", "Status", "Actions"]) %} ... {% endcall %} ============================================================================ #} {% macro table(headers=[], classes="") %}
{% if headers %} {% for header in headers %} {% endfor %} {% endif %} {{ caller() }}
{{ header }}
{% endmacro %} {% macro table_cell(classes="") %} {{ caller() }} {% endmacro %} {% macro table_row(classes="") %} {{ caller() }} {% endmacro %} {# ============================================================================ EMPTY STATE Usage: {{ empty_state("No items found", description="Create your first item") }} ============================================================================ #} {% macro empty_state(title, description="", icon="", action_text="", action_href="", classes="") %}
{% if icon %}
{{ icon|safe }}
{% endif %}

{{ title }}

{% if description %}

{{ description }}

{% endif %} {% if action_text and action_href %} {{ btn_link(action_text, action_href, variant="primary") }} {% endif %}
{% endmacro %} {# ============================================================================ LOADING Usage: {{ spinner() }} {{ skeleton_line() }} {{ skeleton_table(rows=5, cols=4) }} ============================================================================ #} {% macro spinner(size="md", classes="") %} {% set sizes = {"sm": "h-4 w-4", "md": "h-6 w-6", "lg": "h-8 w-8"} %} {% endmacro %} {% macro skeleton_line(width="full", classes="") %} {% set widths = {"full": "w-full", "3/4": "w-3/4", "1/2": "w-1/2", "1/3": "w-1/3", "1/4": "w-1/4"} %}
{% endmacro %} {% macro skeleton_card(classes="") %}
{% endmacro %} {# Skeleton table for loading states #} {% macro skeleton_table(rows=5, cols=4, classes="") %}
{# Header #}
{% for _ in range(cols) %}
{% endfor %}
{# Rows #} {% for _ in range(rows) %}
{% for _ in range(cols) %}
{% endfor %}
{% endfor %}
{% endmacro %} {# Skeleton form for loading states #} {% macro skeleton_form(fields=4, classes="") %}
{% for _ in range(fields) %}
{% endfor %}
{% endmacro %} {# ============================================================================ MODAL Usage: {% call modal(id="myModal", title="Modal Title") %} Modal content here {% endcall %} ============================================================================ #} {% macro modal(id, title, size="md") %} {% set sizes = {"sm": "max-w-md", "md": "max-w-lg", "lg": "max-w-2xl", "xl": "max-w-4xl"} %} {% endmacro %} {# Modal footer for action buttons #} {% macro modal_footer() %}
{{ caller() }}
{% endmacro %} {# ============================================================================ INFO ROWS Usage: {{ info_row("Label", "Value") }} ============================================================================ #} {% macro info_row(label, value, classes="") %}
{{ label }} {{ value }}
{% endmacro %} {# ============================================================================ TOOLBAR Usage: {% call toolbar() %}
buttons
{% endcall %} ============================================================================ #} {% macro toolbar(classes="") %}
{{ caller() }}
{% endmacro %} {# ============================================================================ FILTERS ROW Usage: For filter dropdowns and inputs ============================================================================ #} {% macro filters(classes="") %}
{{ caller() }}
{% endmacro %} {# ============================================================================ CODE/PRE BLOCK Usage: {{ code_block(content) }} ============================================================================ #} {% macro code_block(content, classes="") %}
{{ content }}
{% endmacro %}