feat(admin): separate platform CRUD from CMS, add entity selector macro
Some checks failed
Some checks failed
- Move platforms menu from CMS to Platform Admin section with create/edit - Add platform create page, API endpoint, and service method - Remove CMS-specific content from platform list and detail pages - Create shared entity_selector + entity_selected_badge Jinja macros - Create entity-selector.js generalizing store-selector.js for any entity - Add Tom Select merchant filter to stores page with localStorage persistence - Migrate store-products page to use shared macros (remove 53 lines of duped CSS) - Fix broken icons: puzzle→puzzle-piece, building-storefront→store, language→translate, server→cube Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -284,6 +284,102 @@
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Entity Selector (Tom Select)
|
||||
============================
|
||||
A generic async searchable entity selector using Tom Select.
|
||||
Works for stores, merchants, platforms, or any entity with a search API.
|
||||
|
||||
Includes Tom Select dark mode CSS overrides (no need to add per page).
|
||||
|
||||
Parameters:
|
||||
- ref_name: Alpine.js x-ref name for the select element (default: 'entitySelect')
|
||||
- id: HTML id attribute (default: 'entity-select')
|
||||
- placeholder: Placeholder text (default: 'Search...')
|
||||
- width: CSS width class (default: 'w-80')
|
||||
- label: Accessible label (default: 'Entity selector')
|
||||
|
||||
Usage:
|
||||
{% from 'shared/macros/inputs.html' import entity_selector, entity_selected_badge %}
|
||||
|
||||
{{ entity_selector(ref_name='merchantSelect', id='merchant-select', placeholder='Filter by merchant...') }}
|
||||
{{ entity_selected_badge(entity_var='selectedMerchant', clear_fn='clearMerchantFilter()', color='blue') }}
|
||||
#}
|
||||
{% macro entity_selector(
|
||||
ref_name='entitySelect',
|
||||
id='entity-select',
|
||||
placeholder='Search...',
|
||||
width='w-80',
|
||||
label='Entity selector'
|
||||
) %}
|
||||
{# Dark mode CSS is in admin/base.html — no need to duplicate here #}
|
||||
<div class="{{ width }}">
|
||||
<select
|
||||
id="{{ id }}"
|
||||
x-ref="{{ ref_name }}"
|
||||
placeholder="{{ placeholder }}"
|
||||
aria-label="{{ label }}"
|
||||
></select>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Entity Selected Badge
|
||||
=====================
|
||||
Displays the currently selected entity as a badge with avatar, name, optional code, and clear button.
|
||||
|
||||
Parameters:
|
||||
- entity_var: Alpine.js variable name holding the selected entity (e.g. 'selectedStore')
|
||||
- clear_fn: Alpine.js function to call on clear (e.g. 'clearStoreFilter()')
|
||||
- name_field: Field name for entity name (default: 'name')
|
||||
- code_field: Field name for secondary code display (default: None, omitted if None)
|
||||
- color: Color scheme - 'purple', 'blue', 'teal', 'green' (default: 'purple')
|
||||
|
||||
Usage:
|
||||
{{ entity_selected_badge(
|
||||
entity_var='selectedStore',
|
||||
clear_fn='clearStoreFilter()',
|
||||
code_field='store_code',
|
||||
color='purple'
|
||||
) }}
|
||||
#}
|
||||
{% macro entity_selected_badge(
|
||||
entity_var='selectedEntity',
|
||||
clear_fn='clearEntityFilter()',
|
||||
name_field='name',
|
||||
code_field=None,
|
||||
color='purple'
|
||||
) %}
|
||||
{% set bg = 'bg-' ~ color ~ '-50 dark:bg-' ~ color ~ '-900/20' %}
|
||||
{% set border = 'border-' ~ color ~ '-200 dark:border-' ~ color ~ '-800' %}
|
||||
{% set avatar_bg = 'bg-' ~ color ~ '-100 dark:bg-' ~ color ~ '-900' %}
|
||||
{% set avatar_text = 'text-' ~ color ~ '-600 dark:text-' ~ color ~ '-300' %}
|
||||
{% set name_text = 'text-' ~ color ~ '-800 dark:text-' ~ color ~ '-200' %}
|
||||
{% set code_text = 'text-' ~ color ~ '-600 dark:text-' ~ color ~ '-400' %}
|
||||
{% set btn_text = 'text-' ~ color ~ '-600 dark:text-' ~ color ~ '-400 hover:text-' ~ color ~ '-800 dark:hover:text-' ~ color ~ '-200' %}
|
||||
<div x-show="{{ entity_var }}" x-transition class="mb-6 p-3 {{ bg }} rounded-lg border {{ border }}">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full {{ avatar_bg }} flex items-center justify-center">
|
||||
<span class="text-sm font-semibold {{ avatar_text }}" x-text="{{ entity_var }}?.{{ name_field }}?.charAt(0).toUpperCase()"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium {{ name_text }}" x-text="{{ entity_var }}?.{{ name_field }}"></span>
|
||||
{% if code_field %}
|
||||
<span class="ml-2 text-xs {{ code_text }} font-mono" x-text="{{ entity_var }}?.{{ code_field }}"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<button @click="{{ clear_fn }}" class="{{ btn_text }} text-sm flex items-center gap-1">
|
||||
<span x-html="$icon('x', 'w-4 h-4')"></span>
|
||||
Clear filter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{#
|
||||
Toggle Switch
|
||||
=============
|
||||
|
||||
Reference in New Issue
Block a user