Add comprehensive macro library in app/templates/shared/macros/: - pagination.html: pagination(), pagination_simple() - alerts.html: loading_state(), error_state(), alert(), toast() - badges.html: badge(), status_badge(), role_badge(), severity_badge() - buttons.html: btn(), btn_primary(), btn_danger(), action_button() - forms.html: form_input(), form_select(), form_textarea(), form_toggle() - tables.html: table_wrapper(), table_header(), table_empty_state() - cards.html: stat_card(), card(), info_card(), filter_card() - headers.html: page_header(), section_header(), breadcrumbs() These macros standardize TailAdmin styling with Alpine.js integration and dark mode support, reducing code duplication across templates. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
225 lines
9.2 KiB
HTML
225 lines
9.2 KiB
HTML
{#
|
|
Button Macros
|
|
=============
|
|
Reusable button components for actions, navigation, and forms.
|
|
|
|
Usage:
|
|
{% from 'shared/macros/buttons.html' import btn, btn_primary, btn_secondary, btn_danger, action_button %}
|
|
{{ btn_primary('Save Changes', icon='save', type='submit') }}
|
|
{{ btn_secondary('Cancel', href='/back') }}
|
|
{{ btn_danger('Delete', onclick='deleteItem()') }}
|
|
{{ action_button('eye', 'viewItem()', 'blue', 'View details') }}
|
|
#}
|
|
|
|
|
|
{#
|
|
Base Button
|
|
===========
|
|
A flexible button component that can be styled as primary, secondary, etc.
|
|
|
|
Parameters:
|
|
- text: Button text
|
|
- variant: 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'ghost' (default: 'primary')
|
|
- size: 'sm' | 'md' | 'lg' (default: 'md')
|
|
- icon: Icon name (optional, uses $icon helper)
|
|
- icon_position: 'left' | 'right' (default: 'left')
|
|
- type: 'button' | 'submit' | 'reset' (default: 'button')
|
|
- href: If provided, renders as <a> tag instead of <button>
|
|
- onclick: JavaScript onclick handler
|
|
- disabled: Alpine.js expression for disabled state
|
|
- loading: Alpine.js expression for loading state
|
|
- class_extra: Additional CSS classes
|
|
#}
|
|
{% macro btn(text, variant='primary', size='md', icon=none, icon_position='left', type='button', href=none, onclick=none, disabled=none, loading=none, class_extra='') %}
|
|
{% 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',
|
|
'danger': 'text-white bg-red-600 border-transparent hover:bg-red-700 focus:shadow-outline-red',
|
|
'success': 'text-white bg-green-600 border-transparent hover:bg-green-700 focus:shadow-outline-green',
|
|
'warning': 'text-white bg-yellow-600 border-transparent hover:bg-yellow-700 focus:shadow-outline-yellow',
|
|
'ghost': 'text-gray-600 dark:text-gray-400 bg-transparent border-transparent hover:bg-gray-100 dark:hover:bg-gray-700'
|
|
} %}
|
|
{% set sizes = {
|
|
'sm': 'px-3 py-1 text-xs',
|
|
'md': 'px-4 py-2 text-sm',
|
|
'lg': 'px-6 py-3 text-base'
|
|
} %}
|
|
{% set base_classes = 'inline-flex items-center font-medium leading-5 transition-colors duration-150 border rounded-lg focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed' %}
|
|
|
|
{% if href %}
|
|
<a href="{{ href }}" class="{{ base_classes }} {{ variants[variant] }} {{ sizes[size] }} {{ class_extra }}">
|
|
{% if icon and icon_position == 'left' %}
|
|
<span x-html="$icon('{{ icon }}', 'w-4 h-4 {{ 'mr-2' if text else '' }}')"></span>
|
|
{% endif %}
|
|
{{ text }}
|
|
{% if icon and icon_position == 'right' %}
|
|
<span x-html="$icon('{{ icon }}', 'w-4 h-4 {{ 'ml-2' if text else '' }}')"></span>
|
|
{% endif %}
|
|
</a>
|
|
{% else %}
|
|
<button
|
|
type="{{ type }}"
|
|
{% if onclick %}@click="{{ onclick }}"{% endif %}
|
|
{% if disabled %}:disabled="{{ disabled }}"{% endif %}
|
|
class="{{ base_classes }} {{ variants[variant] }} {{ sizes[size] }} {{ class_extra }}"
|
|
>
|
|
{% if loading %}
|
|
<span x-show="{{ loading }}" x-html="$icon('spinner', 'w-4 h-4 {{ 'mr-2' if text else '' }}')"></span>
|
|
{% endif %}
|
|
{% if icon and icon_position == 'left' %}
|
|
<span {% if loading %}x-show="!{{ loading }}"{% endif %} x-html="$icon('{{ icon }}', 'w-4 h-4 {{ 'mr-2' if text else '' }}')"></span>
|
|
{% endif %}
|
|
{{ text }}
|
|
{% if icon and icon_position == 'right' %}
|
|
<span {% if loading %}x-show="!{{ loading }}"{% endif %} x-html="$icon('{{ icon }}', 'w-4 h-4 {{ 'ml-2' if text else '' }}')"></span>
|
|
{% endif %}
|
|
</button>
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
|
|
{# Convenience macros for common button types #}
|
|
|
|
{% macro btn_primary(text, icon=none, icon_position='left', type='button', href=none, onclick=none, disabled=none, loading=none, size='md') %}
|
|
{{ btn(text, 'primary', size, icon, icon_position, type, href, onclick, disabled, loading) }}
|
|
{% endmacro %}
|
|
|
|
{% macro btn_secondary(text, icon=none, icon_position='left', type='button', href=none, onclick=none, disabled=none, loading=none, size='md') %}
|
|
{{ btn(text, 'secondary', size, icon, icon_position, type, href, onclick, disabled, loading) }}
|
|
{% endmacro %}
|
|
|
|
{% macro btn_danger(text, icon=none, icon_position='left', type='button', href=none, onclick=none, disabled=none, loading=none, size='md') %}
|
|
{{ btn(text, 'danger', size, icon, icon_position, type, href, onclick, disabled, loading) }}
|
|
{% endmacro %}
|
|
|
|
{% macro btn_success(text, icon=none, icon_position='left', type='button', href=none, onclick=none, disabled=none, loading=none, size='md') %}
|
|
{{ btn(text, 'success', size, icon, icon_position, type, href, onclick, disabled, loading) }}
|
|
{% endmacro %}
|
|
|
|
{% macro btn_ghost(text, icon=none, icon_position='left', type='button', href=none, onclick=none, disabled=none, loading=none, size='md') %}
|
|
{{ btn(text, 'ghost', size, icon, icon_position, type, href, onclick, disabled, loading) }}
|
|
{% endmacro %}
|
|
|
|
|
|
{#
|
|
Action Button (Icon Only)
|
|
=========================
|
|
A small icon button for table actions (view, edit, delete).
|
|
|
|
Parameters:
|
|
- icon: Icon name
|
|
- onclick: JavaScript onclick handler
|
|
- color: 'blue' | 'purple' | 'red' | 'green' | 'gray' (default: 'gray')
|
|
- title: Tooltip text
|
|
- disabled: Alpine.js expression for disabled state
|
|
- href: If provided, renders as <a> tag
|
|
#}
|
|
{% macro action_button(icon, onclick=none, color='gray', title='', disabled=none, href=none) %}
|
|
{% set colors = {
|
|
'blue': 'text-blue-600 hover:bg-blue-50 dark:text-blue-400 dark:hover:bg-gray-700',
|
|
'purple': 'text-purple-600 hover:bg-purple-50 dark:text-purple-400 dark:hover:bg-gray-700',
|
|
'red': 'text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-gray-700',
|
|
'green': 'text-green-600 hover:bg-green-50 dark:text-green-400 dark:hover:bg-gray-700',
|
|
'gray': 'text-gray-600 hover:bg-gray-50 dark:text-gray-400 dark:hover:bg-gray-700',
|
|
'orange': 'text-orange-600 hover:bg-orange-50 dark:text-orange-400 dark:hover:bg-gray-700'
|
|
} %}
|
|
{% set base_classes = 'flex items-center justify-center p-2 rounded-lg focus:outline-none transition-colors disabled:opacity-50 disabled:cursor-not-allowed' %}
|
|
|
|
{% if href %}
|
|
<a href="{{ href }}" class="{{ base_classes }} {{ colors[color] }}" title="{{ title }}">
|
|
<span x-html="$icon('{{ icon }}', 'w-5 h-5')"></span>
|
|
</a>
|
|
{% else %}
|
|
<button
|
|
@click="{{ onclick }}"
|
|
{% if disabled %}:disabled="{{ disabled }}"{% endif %}
|
|
class="{{ base_classes }} {{ colors[color] }}"
|
|
title="{{ title }}"
|
|
>
|
|
<span x-html="$icon('{{ icon }}', 'w-5 h-5')"></span>
|
|
</button>
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
|
|
{#
|
|
Action Button Group
|
|
===================
|
|
A group of action buttons (typically for table rows).
|
|
|
|
Usage:
|
|
{{ action_button_group([
|
|
{'icon': 'eye', 'onclick': 'view(item)', 'color': 'blue', 'title': 'View'},
|
|
{'icon': 'edit', 'onclick': 'edit(item)', 'color': 'purple', 'title': 'Edit'},
|
|
{'icon': 'delete', 'onclick': 'delete(item)', 'color': 'red', 'title': 'Delete'}
|
|
]) }}
|
|
#}
|
|
{% macro action_button_group(buttons) %}
|
|
<div class="flex items-center space-x-2 text-sm">
|
|
{% for button in buttons %}
|
|
{{ action_button(
|
|
button.icon,
|
|
button.get('onclick'),
|
|
button.get('color', 'gray'),
|
|
button.get('title', ''),
|
|
button.get('disabled'),
|
|
button.get('href')
|
|
) }}
|
|
{% endfor %}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
|
|
{#
|
|
Button Group
|
|
============
|
|
A group of buttons with proper spacing.
|
|
#}
|
|
{% macro button_group(class_extra='') %}
|
|
<div class="flex items-center space-x-3 {{ class_extra }}">
|
|
{{ caller() }}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
|
|
{#
|
|
Back Button
|
|
===========
|
|
A standardized back navigation button.
|
|
|
|
Parameters:
|
|
- href: URL to navigate back to
|
|
- text: Button text (default: 'Back')
|
|
#}
|
|
{% macro back_button(href, text='Back') %}
|
|
<a href="{{ href }}"
|
|
class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-gray-700 dark:text-gray-300 transition-colors duration-150 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:shadow-outline-gray">
|
|
<span x-html="$icon('arrow-left', 'w-4 h-4 mr-2')"></span>
|
|
{{ text }}
|
|
</a>
|
|
{% endmacro %}
|
|
|
|
|
|
{#
|
|
Submit Button with Loading
|
|
==========================
|
|
A form submit button with built-in loading state.
|
|
|
|
Parameters:
|
|
- text: Button text
|
|
- loading_text: Text shown while loading (default: 'Saving...')
|
|
- loading_var: Alpine.js variable for loading state (default: 'saving')
|
|
- icon: Icon name (default: 'save')
|
|
#}
|
|
{% macro submit_button(text='Save', loading_text='Saving...', loading_var='saving', icon='save') %}
|
|
<button
|
|
type="submit"
|
|
:disabled="{{ loading_var }}"
|
|
class="inline-flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
<span x-show="{{ loading_var }}" x-html="$icon('spinner', 'w-4 h-4 mr-2')"></span>
|
|
<span x-show="!{{ loading_var }}" x-html="$icon('{{ icon }}', 'w-4 h-4 mr-2')"></span>
|
|
<span x-text="{{ loading_var }} ? '{{ loading_text }}' : '{{ text }}'"></span>
|
|
</button>
|
|
{% endmacro %}
|