feat: add shared Jinja macros for reusable UI components
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>
This commit is contained in:
211
app/templates/shared/macros/badges.html
Normal file
211
app/templates/shared/macros/badges.html
Normal file
@@ -0,0 +1,211 @@
|
||||
{#
|
||||
Badge Macros
|
||||
============
|
||||
Reusable badge components for status indicators, labels, and tags.
|
||||
|
||||
Usage:
|
||||
{% from 'shared/macros/badges.html' import badge, status_badge, verification_badge, role_badge %}
|
||||
{{ badge('New', 'purple') }}
|
||||
{{ status_badge('is_active', 'Active', 'Inactive') }}
|
||||
{{ verification_badge('item.is_verified') }}
|
||||
{{ role_badge('user.role') }}
|
||||
#}
|
||||
|
||||
|
||||
{#
|
||||
Basic Badge
|
||||
===========
|
||||
A simple colored badge.
|
||||
|
||||
Parameters:
|
||||
- text: Badge text (static)
|
||||
- color: 'gray' | 'red' | 'green' | 'blue' | 'yellow' | 'purple' | 'orange' | 'pink' (default: 'gray')
|
||||
- size: 'sm' | 'md' (default: 'sm')
|
||||
#}
|
||||
{% macro badge(text, color='gray', size='sm') %}
|
||||
{% set colors = {
|
||||
'gray': 'text-gray-700 bg-gray-100 dark:text-gray-100 dark:bg-gray-700',
|
||||
'red': 'text-red-700 bg-red-100 dark:text-red-100 dark:bg-red-700',
|
||||
'green': 'text-green-700 bg-green-100 dark:text-green-100 dark:bg-green-700',
|
||||
'blue': 'text-blue-700 bg-blue-100 dark:text-blue-100 dark:bg-blue-700',
|
||||
'yellow': 'text-yellow-700 bg-yellow-100 dark:text-yellow-100 dark:bg-yellow-700',
|
||||
'purple': 'text-purple-700 bg-purple-100 dark:text-purple-100 dark:bg-purple-700',
|
||||
'orange': 'text-orange-700 bg-orange-100 dark:text-orange-100 dark:bg-orange-700',
|
||||
'pink': 'text-pink-700 bg-pink-100 dark:text-pink-100 dark:bg-pink-700'
|
||||
} %}
|
||||
{% set sizes = {
|
||||
'sm': 'px-2 py-1 text-xs',
|
||||
'md': 'px-3 py-1 text-sm'
|
||||
} %}
|
||||
<span class="inline-flex items-center font-semibold leading-tight rounded-full {{ colors[color] }} {{ sizes[size] }}">
|
||||
{{ text }}
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Dynamic Badge
|
||||
=============
|
||||
A badge with text from Alpine.js variable.
|
||||
|
||||
Parameters:
|
||||
- text_var: Alpine.js variable for badge text
|
||||
- color: Badge color (default: 'gray')
|
||||
- size: 'sm' | 'md' (default: 'sm')
|
||||
#}
|
||||
{% macro badge_dynamic(text_var, color='gray', size='sm') %}
|
||||
{% set colors = {
|
||||
'gray': 'text-gray-700 bg-gray-100 dark:text-gray-100 dark:bg-gray-700',
|
||||
'red': 'text-red-700 bg-red-100 dark:text-red-100 dark:bg-red-700',
|
||||
'green': 'text-green-700 bg-green-100 dark:text-green-100 dark:bg-green-700',
|
||||
'blue': 'text-blue-700 bg-blue-100 dark:text-blue-100 dark:bg-blue-700',
|
||||
'yellow': 'text-yellow-700 bg-yellow-100 dark:text-yellow-100 dark:bg-yellow-700',
|
||||
'purple': 'text-purple-700 bg-purple-100 dark:text-purple-100 dark:bg-purple-700',
|
||||
'orange': 'text-orange-700 bg-orange-100 dark:text-orange-100 dark:bg-orange-700',
|
||||
'pink': 'text-pink-700 bg-pink-100 dark:text-pink-100 dark:bg-pink-700'
|
||||
} %}
|
||||
{% set sizes = {
|
||||
'sm': 'px-2 py-1 text-xs',
|
||||
'md': 'px-3 py-1 text-sm'
|
||||
} %}
|
||||
<span class="inline-flex items-center font-semibold leading-tight rounded-full {{ colors[color] }} {{ sizes[size] }}" x-text="{{ text_var }}"></span>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Status Badge (Boolean)
|
||||
======================
|
||||
A badge that changes based on a boolean condition.
|
||||
|
||||
Parameters:
|
||||
- condition: Alpine.js boolean expression
|
||||
- true_label: Text when true (default: 'Active')
|
||||
- false_label: Text when false (default: 'Inactive')
|
||||
- true_color: Color when true (default: 'green')
|
||||
- false_color: Color when false (default: 'gray')
|
||||
#}
|
||||
{% macro status_badge(condition, true_label='Active', false_label='Inactive', true_color='green', false_color='gray') %}
|
||||
{% set colors = {
|
||||
'gray': 'text-gray-700 bg-gray-100 dark:text-gray-100 dark:bg-gray-700',
|
||||
'red': 'text-red-700 bg-red-100 dark:text-red-100 dark:bg-red-700',
|
||||
'green': 'text-green-700 bg-green-100 dark:text-green-100 dark:bg-green-700',
|
||||
'blue': 'text-blue-700 bg-blue-100 dark:text-blue-100 dark:bg-blue-700',
|
||||
'yellow': 'text-yellow-700 bg-yellow-100 dark:text-yellow-100 dark:bg-yellow-700',
|
||||
'purple': 'text-purple-700 bg-purple-100 dark:text-purple-100 dark:bg-purple-700',
|
||||
'orange': 'text-orange-700 bg-orange-100 dark:text-orange-100 dark:bg-orange-700'
|
||||
} %}
|
||||
<span class="inline-flex items-center px-2 py-1 text-xs font-semibold leading-tight rounded-full"
|
||||
:class="{{ condition }} ? '{{ colors[true_color] }}' : '{{ colors[false_color] }}'">
|
||||
<span x-text="{{ condition }} ? '{{ true_label }}' : '{{ false_label }}'"></span>
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Verification Badge
|
||||
==================
|
||||
A specialized badge for verified/pending status with icon.
|
||||
|
||||
Parameters:
|
||||
- condition: Alpine.js boolean expression (e.g., 'item.is_verified')
|
||||
- verified_label: Text when verified (default: 'Verified')
|
||||
- pending_label: Text when not verified (default: 'Pending')
|
||||
#}
|
||||
{% macro verification_badge(condition, verified_label='Verified', pending_label='Pending') %}
|
||||
<span class="inline-flex items-center px-2 py-1 text-xs font-semibold leading-tight rounded-full"
|
||||
:class="{{ condition }} ? 'text-green-700 bg-green-100 dark:bg-green-700 dark:text-green-100' : 'text-orange-700 bg-orange-100 dark:text-white dark:bg-orange-600'">
|
||||
<span x-show="{{ condition }}" x-html="$icon('badge-check', 'w-3 h-3 mr-1')"></span>
|
||||
<span x-text="{{ condition }} ? '{{ verified_label }}' : '{{ pending_label }}'"></span>
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Role Badge
|
||||
==========
|
||||
A badge for user roles with role-specific colors.
|
||||
|
||||
Parameters:
|
||||
- role_var: Alpine.js variable containing the role string
|
||||
- capitalize: Whether to capitalize the role text (default: true)
|
||||
#}
|
||||
{% macro role_badge(role_var, capitalize=true) %}
|
||||
<span class="px-2 py-1 text-xs font-semibold leading-tight rounded-full {{ 'capitalize' if capitalize else '' }}"
|
||||
:class="{
|
||||
'text-orange-700 bg-orange-100 dark:bg-orange-700 dark:text-orange-100': {{ role_var }} === 'admin',
|
||||
'text-purple-700 bg-purple-100 dark:bg-purple-700 dark:text-purple-100': {{ role_var }} === 'vendor',
|
||||
'text-blue-700 bg-blue-100 dark:bg-blue-700 dark:text-blue-100': {{ role_var }} === 'customer',
|
||||
'text-gray-700 bg-gray-100 dark:bg-gray-700 dark:text-gray-100': !['admin', 'vendor', 'customer'].includes({{ role_var }})
|
||||
}"
|
||||
x-text="{{ role_var }}">
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Order Status Badge
|
||||
==================
|
||||
A specialized badge for order statuses.
|
||||
|
||||
Parameters:
|
||||
- status_var: Alpine.js variable containing the status string
|
||||
#}
|
||||
{% macro order_status_badge(status_var) %}
|
||||
<span class="px-2 py-1 text-xs font-semibold leading-tight rounded-full capitalize"
|
||||
:class="{
|
||||
'text-yellow-700 bg-yellow-100 dark:bg-yellow-700 dark:text-yellow-100': {{ status_var }} === 'pending',
|
||||
'text-blue-700 bg-blue-100 dark:bg-blue-700 dark:text-blue-100': {{ status_var }} === 'processing',
|
||||
'text-purple-700 bg-purple-100 dark:bg-purple-700 dark:text-purple-100': {{ status_var }} === 'shipped',
|
||||
'text-green-700 bg-green-100 dark:bg-green-700 dark:text-green-100': {{ status_var }} === 'delivered',
|
||||
'text-red-700 bg-red-100 dark:bg-red-700 dark:text-red-100': {{ status_var }} === 'cancelled',
|
||||
'text-gray-700 bg-gray-100 dark:bg-gray-700 dark:text-gray-100': !['pending', 'processing', 'shipped', 'delivered', 'cancelled'].includes({{ status_var }})
|
||||
}"
|
||||
x-text="{{ status_var }}">
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Severity Badge
|
||||
==============
|
||||
A badge for severity levels (error, warning, info).
|
||||
|
||||
Parameters:
|
||||
- severity_var: Alpine.js variable containing 'error' | 'warning' | 'info'
|
||||
#}
|
||||
{% macro severity_badge(severity_var) %}
|
||||
<span class="px-2 py-1 text-xs font-semibold leading-tight rounded-full"
|
||||
:class="{
|
||||
'text-red-700 bg-red-100 dark:bg-red-700 dark:text-red-100': {{ severity_var }} === 'error',
|
||||
'text-yellow-700 bg-yellow-100 dark:text-yellow-100 dark:bg-yellow-700': {{ severity_var }} === 'warning',
|
||||
'text-blue-700 bg-blue-100 dark:text-blue-100 dark:bg-blue-700': {{ severity_var }} === 'info'
|
||||
}"
|
||||
x-text="{{ severity_var }}">
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Count Badge
|
||||
===========
|
||||
A small badge typically used for counts (notifications, items, etc.).
|
||||
|
||||
Parameters:
|
||||
- count_var: Alpine.js variable or expression for the count
|
||||
- color: Badge color (default: 'red')
|
||||
- show_zero: Whether to show when count is 0 (default: false)
|
||||
#}
|
||||
{% macro count_badge(count_var, color='red', show_zero=false) %}
|
||||
{% set colors = {
|
||||
'red': 'bg-red-500 text-white',
|
||||
'green': 'bg-green-500 text-white',
|
||||
'blue': 'bg-blue-500 text-white',
|
||||
'purple': 'bg-purple-500 text-white',
|
||||
'gray': 'bg-gray-500 text-white'
|
||||
} %}
|
||||
<span
|
||||
x-show="{{ count_var }} > 0 || {{ 'true' if show_zero else 'false' }}"
|
||||
class="inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none rounded-full {{ colors[color] }}"
|
||||
x-text="{{ count_var }}">
|
||||
</span>
|
||||
{% endmacro %}
|
||||
Reference in New Issue
Block a user