{# Header Macros ============= Reusable page header and navigation components. Usage: {% from 'shared/macros/headers.html' import page_header, section_header, breadcrumbs %} {{ page_header('User Management', action_label='Create User', action_url='/users/create') }} {{ section_header('Account Settings') }} {{ breadcrumbs([{'label': 'Home', 'url': '/'}, {'label': 'Users'}]) }} #} {# Page Header =========== A page header with title, optional subtitle, and action button. Parameters: - title: Page title - subtitle: Page subtitle (optional) - action_label: Action button text (optional) - action_url: Action button URL (optional) - action_icon: Action button icon (default: 'plus') - action_onclick: JavaScript onclick handler (optional, instead of URL) - back_url: Back button URL (optional) - back_label: Back button text (default: 'Back') #} {% macro page_header(title, subtitle=none, action_label=none, action_url=none, action_icon='plus', action_onclick=none, back_url=none, back_label='Back') %}

{{ title }}

{% if subtitle %}

{{ subtitle }}

{% endif %}
{% if back_url %} {{ back_label }} {% endif %} {% if action_label and (action_url or action_onclick) %} {% if action_url %} {{ action_label }} {% else %} {% endif %} {% endif %}
{% endmacro %} {# Page Header (Dynamic) ===================== A page header where the title comes from Alpine.js. Parameters: - title_var: Alpine.js variable for the title - subtitle_var: Alpine.js variable for subtitle (optional) - ... other params same as page_header #} {% macro page_header_dynamic(title_var, subtitle_var=none, action_label=none, action_url=none, action_icon='plus', back_url=none, back_label='Back') %}

{% if subtitle_var %}

{% endif %}
{% if back_url %} {{ back_label }} {% endif %} {% if action_label and action_url %} {{ action_label }} {% endif %}
{% endmacro %} {# Section Header ============== A section header within a page. Parameters: - title: Section title - subtitle: Section subtitle (optional) - action_label: Action button text (optional) - action_onclick: Action button onclick (optional) - icon: Section icon (optional) #} {% macro section_header(title, subtitle=none, action_label=none, action_onclick=none, icon=none) %}
{% if icon %} {% endif %}

{{ title }}

{% if subtitle %}

{{ subtitle }}

{% endif %}
{% if action_label and action_onclick %} {% endif %}
{% endmacro %} {# Breadcrumbs =========== Navigation breadcrumbs. Parameters: - items: List of breadcrumb items [{'label': '', 'url': ''}] Last item (without url) is treated as current page - separator: Separator character (default: '/') #} {% macro breadcrumbs(items, separator='/') %} {% endmacro %} {# Card Header =========== A header for card sections. Parameters: - title: Card header title - subtitle: Card header subtitle (optional) - class_extra: Additional CSS classes #} {% macro card_header(title, subtitle=none, class_extra='') %}

{{ title }}

{% if subtitle %}

{{ subtitle }}

{% endif %}
{% endmacro %} {# Tab Header ========== A tab navigation header. Parameters: - tabs: List of tab items [{'id': '', 'label': '', 'icon': ''}] - active_var: Alpine.js variable for active tab #} {% macro tab_header(tabs, active_var='activeTab') %}
{% endmacro %} {# Refresh Button ============== A button with loading state for refresh actions. Parameters: - loading_var: Alpine.js variable for loading state (default: 'loading') - onclick: Alpine.js click handler (default: 'refresh()') - label: Button label (default: 'Refresh') - loading_label: Label while loading (default: 'Loading...') - variant: 'primary' | 'secondary' (default: 'primary') #} {% macro refresh_button(loading_var='loading', onclick='refresh()', label='Refresh', loading_label='Loading...', variant='primary') %} {% set variants = { 'primary': 'text-white bg-purple-600 border-transparent hover:bg-purple-700 focus:shadow-outline-purple', 'secondary': 'text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 focus:shadow-outline-gray' } %} {% endmacro %} {# Action Button (with loading) ============================ A generic action button with loading state. Parameters: - label: Button label - loading_label: Label while loading - loading_var: Alpine.js variable for loading state - onclick: Alpine.js click handler - icon: Button icon (default: 'check') - variant: 'primary' | 'secondary' | 'danger' (default: 'primary') #} {% macro action_button(label, loading_label, loading_var, onclick, icon='check', variant='primary') %} {% set variants = { 'primary': 'text-white bg-purple-600 border-transparent hover:bg-purple-700 focus:shadow-outline-purple', 'secondary': 'text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 focus:shadow-outline-gray', 'danger': 'text-white bg-red-600 border-transparent hover:bg-red-700 focus:shadow-outline-red' } %} {% endmacro %} {# Back Button =========== A simple back navigation button. Parameters: - url: Back URL - label: Button label (default: 'Back') #} {% macro back_button(url, label='Back') %} {{ label }} {% endmacro %} {# Page Header (Flexible) ====================== A flexible page header that accepts custom content via caller(). Use this when you need custom action buttons or dynamic content. Parameters: - title: Page title (static string) - title_var: Alpine.js variable for dynamic title (use instead of title) - subtitle: Page subtitle (static string) - subtitle_var: Alpine.js variable for dynamic subtitle - subtitle_show: Alpine.js condition for showing subtitle (e.g., 'user') Usage: {% call page_header_flex(title='Dashboard') %} {{ refresh_button() }} {% endcall %} {% call page_header_flex(title_var="user?.name || 'User'", subtitle_show='user') %} {{ back_button('/admin/users') }} {% endcall %} #} {% macro page_header_flex(title=none, title_var=none, subtitle=none, subtitle_var=none, subtitle_show=none) %}
{% if title_var %}

{% else %}

{{ title }}

{% endif %} {% if subtitle_var %}

{% elif subtitle %}

{{ subtitle }}

{% endif %}
{{ caller() }}
{% endmacro %} {# Page Header (with Refresh) ========================== A common pattern: static header with refresh button. Parameters: - title: Page title - subtitle: Page subtitle (optional) - loading_var: Alpine.js variable for loading state (default: 'loading') - refresh_action: Alpine.js refresh action (default: 'refresh()') #} {% macro page_header_refresh(title, subtitle=none, loading_var='loading', refresh_action='refresh()') %}

{{ title }}

{% if subtitle %}

{{ subtitle }}

{% endif %}
{{ refresh_button(loading_var=loading_var, onclick=refresh_action) }}
{% endmacro %} {# Detail Page Header ================== Common pattern for detail pages with dynamic title and back button. Parameters: - title_var: Alpine.js expression for title (e.g., "user?.name || 'User Details'") - subtitle_template: Jinja template string for subtitle (rendered as-is) - subtitle_show: Alpine.js condition for showing subtitle - back_url: URL for back button - back_label: Back button label (default: 'Back') #} {% macro detail_page_header(title_var, back_url, subtitle_show=none, back_label='Back') %}

{% if caller is defined %}

{{ caller() }}

{% endif %}
{{ back_button(back_url, back_label) }}
{% endmacro %} {# Edit Page Header ================ Common pattern for edit pages with static title, dynamic subtitle, and back button. Parameters: - title: Static title (e.g., 'Edit Store') - subtitle_var: Alpine.js expression for subtitle parts - subtitle_show: Alpine.js condition for showing subtitle - back_url: URL for back button - back_label: Back button label (default: 'Back') #} {% macro edit_page_header(title, back_url, subtitle_show=none, back_label='Back') %}

{{ title }}

{% if caller is defined %}

{{ caller() }}

{% endif %}
{{ back_button(back_url, back_label) }}
{% endmacro %}