fix: add missing th_sortable macro for sortable table headers

The subscription templates were importing th_sortable but the macro
didn't exist. Added the macro to tables.html with:
- Clickable header with sort indicator arrows
- Alpine.js integration for sorting state
- Visual feedback for current sort column and direction

Also removed unused empty_state import from subscription-tiers.html.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-25 22:29:16 +01:00
parent 6bd4b71588
commit abfd823ec8
2 changed files with 60 additions and 1 deletions

View File

@@ -3,7 +3,7 @@
{% extends "admin/base.html" %}
{% from 'shared/macros/alerts.html' import alert_dynamic, error_state %}
{% from 'shared/macros/headers.html' import page_header_refresh %}
{% from 'shared/macros/tables.html' import table_wrapper, table_header_custom, th_sortable, empty_state %}
{% from 'shared/macros/tables.html' import table_wrapper, table_header_custom, th_sortable %}
{% from 'shared/macros/modals.html' import modal_confirm %}
{% block title %}Subscription Tiers{% endblock %}

View File

@@ -69,6 +69,65 @@
{% endmacro %}
{#
Sortable Table Header Cell (th_sortable)
========================================
Renders a single sortable table header cell for use inside table_header_custom.
Parameters:
- key: The data key/column name for sorting
- label: Display label for the column
- sort_func: Alpine.js function name to call on click (default: 'sortBy')
- sort_order_var: Alpine.js variable for current sort order (default: 'sortOrder')
Usage:
{% call table_header_custom() %}
{{ th_sortable('name', 'Name', 'sortBy', 'sortOrder') }}
{{ th_sortable('created_at', 'Created', 'sortBy', 'sortOrder') }}
<th class="px-4 py-3">Actions</th>
{% endcall %}
Required Alpine.js:
sortBy: '',
sortOrder: 'asc',
handleSort(key) {
if (this.sortBy === key) {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
} else {
this.sortBy = key;
this.sortOrder = 'asc';
}
this.loadData();
}
#}
{% macro th_sortable(key, label, sort_func='sortBy', sort_order_var='sortOrder') %}
<th class="px-4 py-3">
<button
@click="{{ sort_func }} = '{{ key }}'; {{ sort_order_var }} = {{ sort_func }} === '{{ key }}' && {{ sort_order_var }} === 'asc' ? 'desc' : 'asc'; loadData()"
class="flex items-center space-x-1 hover:text-gray-700 dark:hover:text-gray-200 transition-colors group"
>
<span>{{ label }}</span>
<span class="flex flex-col">
<svg
class="w-3 h-3 -mb-1 transition-colors"
:class="{{ sort_func }} === '{{ key }}' && {{ sort_order_var }} === 'asc' ? 'text-purple-600 dark:text-purple-400' : 'text-gray-300 dark:text-gray-600 group-hover:text-gray-400'"
fill="currentColor" viewBox="0 0 20 20"
>
<path d="M5 12l5-5 5 5H5z"/>
</svg>
<svg
class="w-3 h-3 -mt-1 transition-colors"
:class="{{ sort_func }} === '{{ key }}' && {{ sort_order_var }} === 'desc' ? 'text-purple-600 dark:text-purple-400' : 'text-gray-300 dark:text-gray-600 group-hover:text-gray-400'"
fill="currentColor" viewBox="0 0 20 20"
>
<path d="M15 8l-5 5-5-5h10z"/>
</svg>
</span>
</button>
</th>
{% endmacro %}
{#
Sortable Table Header
=====================