diff --git a/app/templates/shared/macros/inputs.html b/app/templates/shared/macros/inputs.html new file mode 100644 index 00000000..22fc0aad --- /dev/null +++ b/app/templates/shared/macros/inputs.html @@ -0,0 +1,233 @@ +{# + Input Macros + ============ + Reusable input components with Alpine.js integration. + + Usage: + {% from 'shared/macros/inputs.html' import search_autocomplete %} + + {{ search_autocomplete( + search_var='userSearchQuery', + results_var='userSearchResults', + show_dropdown_var='showUserDropdown', + loading_var='searchingUsers', + disabled_var='transferring', + select_action='selectUser(user)', + display_field='username', + secondary_field='email', + placeholder='Search by name or email...' + ) }} +#} + + +{# + Search Autocomplete + =================== + A search input with dropdown results for autocomplete functionality. + + Parameters: + - search_var: Alpine.js variable for search query (required) + - results_var: Alpine.js variable containing search results array (required) + - show_dropdown_var: Alpine.js variable controlling dropdown visibility (required) + - loading_var: Alpine.js variable for loading state (default: 'searching') + - disabled_var: Alpine.js variable for disabled state (default: none) + - search_action: Alpine.js action on input (default: 'search()') + - select_action: Alpine.js action when item selected, receives 'item' (required) + - selected_check: Alpine.js expression to check if item is selected (optional) + - display_field: Field name for primary display text (default: 'name') + - secondary_field: Field name for secondary text (optional) + - id_field: Field name for item ID (default: 'id') + - placeholder: Input placeholder text (default: 'Search...') + - min_chars: Minimum characters before showing results (default: 2) + - no_results_text: Text when no results found (default: 'No results found') + - loading_text: Text while loading (default: 'Searching...') +#} +{% macro search_autocomplete( + search_var, + results_var, + show_dropdown_var, + loading_var='searching', + disabled_var=none, + search_action='search()', + select_action='selectItem(item)', + selected_check=none, + display_field='name', + secondary_field=none, + id_field='id', + placeholder='Search...', + min_chars=2, + no_results_text='No results found', + loading_text='Searching...' +) %} +
+ + + {# Search Results Dropdown #} +
+ +
+ + {# No Results #} +
+ {{ no_results_text }} +
+ + {# Loading #} +
+ + {{ loading_text }} +
+
+{% endmacro %} + + +{# + Selected Item Display + ===================== + A display component for showing the currently selected item with clear button. + + Parameters: + - selected_var: Alpine.js variable containing selected item (required) + - display_field: Field name for primary display text (default: 'name') + - secondary_field: Field name for secondary text (optional) + - clear_action: Alpine.js action to clear selection (required) + - label: Label text before the selection (default: 'Selected:') +#} +{% macro selected_item_display( + selected_var, + display_field='name', + secondary_field=none, + clear_action='clearSelection()', + label='Selected:' +) %} +
+ + {{ label }} + {% if secondary_field %} + () + {% endif %} + + +
+{% endmacro %} + + +{# + Number Stepper + ============== + A number input with +/- buttons for incrementing/decrementing values. + Useful for quantity selectors in carts, product pages, batch sizes, etc. + + Parameters: + - model: Alpine.js x-model variable (required) + - min: Minimum allowed value (default: 1) + - max: Maximum allowed value (default: none - unlimited) + - step: Increment/decrement step (default: 1) + - size: 'sm' | 'md' | 'lg' (default: 'md') + - disabled_var: Alpine.js variable for disabled state (optional) + - name: Input name for form submission (optional) + - id: Input id attribute (optional) + - label: Accessible label for screen readers (default: 'Quantity') + + Usage: + {{ number_stepper(model='quantity', min=1, max=99) }} + {{ number_stepper(model='cart.items[index].qty', min=1, max='item.stock', size='sm') }} + {{ number_stepper(model='batchSize', min=100, max=5000, step=100, size='lg') }} +#} +{% macro number_stepper( + model, + min=1, + max=none, + step=1, + size='md', + disabled_var=none, + name=none, + id=none, + label='Quantity' +) %} +{% set sizes = { + 'sm': { + 'btn': 'px-2 py-1', + 'input': 'px-2 py-1 text-xs w-12', + 'icon': 'w-3 h-3' + }, + 'md': { + 'btn': 'px-3 py-2', + 'input': 'px-3 py-2 text-sm w-16', + 'icon': 'w-4 h-4' + }, + 'lg': { + 'btn': 'px-4 py-3', + 'input': 'px-4 py-3 text-base w-20', + 'icon': 'w-5 h-5' + } +} %} +{% set s = sizes[size] %} +
+ + + +
+{% endmacro %} diff --git a/app/templates/shared/macros/tabs.html b/app/templates/shared/macros/tabs.html new file mode 100644 index 00000000..0bcfbbed --- /dev/null +++ b/app/templates/shared/macros/tabs.html @@ -0,0 +1,78 @@ +{# app/templates/shared/macros/tabs.html #} +{# Tab navigation components for consistent UI across admin pages #} + +{# + Tab navigation wrapper (standalone) + Usage: + {% call tabs_nav() %} + {{ tab_button('tab1', 'Tab 1', icon='home') }} + {{ tab_button('tab2', 'Tab 2', icon='cog') }} + {% endcall %} +#} +{% macro tabs_nav(tab_var='activeTab', class='') %} +
+
+ +
+
+{% endmacro %} + +{# + Tab navigation wrapper (inline, for use inside cards/flex containers) + Usage: +
+ {% call tabs_inline() %} + {{ tab_button('all', 'All', count_var='items.length') }} + {% endcall %} + +
+#} +{% macro tabs_inline(tab_var='activeTab') %} +
+ {{ caller() }} +
+{% endmacro %} + +{# + Individual tab button + Args: + id: Tab identifier (used for activeTab comparison) + label: Display text + tab_var: Alpine.js variable name for active tab (default: 'activeTab') + icon: Optional icon name (uses $icon helper) + count_var: Optional Alpine.js variable for count badge + onclick: Optional custom click handler (overrides default tab switching) +#} +{% macro tab_button(id, label, tab_var='activeTab', icon=none, count_var=none, onclick=none) %} + +{% endmacro %} + +{# + Tab panel wrapper (for content that shows/hides based on active tab) + Usage: + {{ tab_panel('tab1') }} +
Tab 1 content
+ {{ endtab_panel() }} + + Or simply use x-show directly: +
+ Content +
+#} +{% macro tab_panel(id, tab_var='activeTab', transition=true) %} +
+{% endmacro %} + +{% macro endtab_panel() %} +
+{% endmacro %}