Some checks failed
- Extract login/dashboard from billing module into core (matching admin pattern) - Add merchant auth API with path-isolated cookies (path=/merchants) - Add merchant base layout with sidebar/header partials and Alpine.js init - Add frontend detection and login redirect for MERCHANT type - Wire merchant token in shared api-client.js (get/clear) - Migrate billing templates to merchant base with dark mode support - Fix Tailwind: rename shop→storefront in sources and config - DRY Makefile tailwind targets with TAILWIND_FRONTENDS loop - Rebuild all Tailwind outputs (production minified) - Add Gitea Actions CI workflow (ruff, pytest, architecture, docs) - Add Gitea deployment documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
128 lines
5.4 KiB
HTML
128 lines
5.4 KiB
HTML
{# app/templates/merchant/partials/sidebar.html #}
|
|
{# Collapsible sidebar sections with localStorage persistence - matching store pattern #}
|
|
|
|
{# ============================================================================
|
|
REUSABLE MACROS FOR SIDEBAR ITEMS
|
|
============================================================================ #}
|
|
|
|
{# Macro for collapsible section header #}
|
|
{% macro section_header(title, section_key, icon=none) %}
|
|
<div class="px-6 my-4">
|
|
<hr class="border-gray-200 dark:border-gray-700" />
|
|
</div>
|
|
<button
|
|
@click="toggleSection('{{ section_key }}')"
|
|
class="flex items-center justify-between w-full px-6 py-2 text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
|
|
>
|
|
<span class="flex items-center">
|
|
{% if icon %}
|
|
<span x-html="$icon('{{ icon }}', 'w-4 h-4 mr-2 text-gray-400')"></span>
|
|
{% endif %}
|
|
{{ title }}
|
|
</span>
|
|
<span
|
|
x-html="$icon('chevron-down', 'w-4 h-4 transition-transform duration-200')"
|
|
:class="{ 'rotate-180': openSections.{{ section_key }} }"
|
|
></span>
|
|
</button>
|
|
{% endmacro %}
|
|
|
|
{# Macro for collapsible section content wrapper #}
|
|
{% macro section_content(section_key) %}
|
|
<ul
|
|
x-show="openSections.{{ section_key }}"
|
|
x-transition:enter="transition-all duration-200 ease-out"
|
|
x-transition:enter-start="opacity-0 -translate-y-2"
|
|
x-transition:enter-end="opacity-100 translate-y-0"
|
|
x-transition:leave="transition-all duration-150 ease-in"
|
|
x-transition:leave-start="opacity-100 translate-y-0"
|
|
x-transition:leave-end="opacity-0 -translate-y-2"
|
|
class="mt-1 overflow-hidden"
|
|
>
|
|
{{ caller() }}
|
|
</ul>
|
|
{% endmacro %}
|
|
|
|
{# Macro for menu item - uses static href (no storeCode needed) #}
|
|
{% macro menu_item(page_id, path, icon, label) %}
|
|
<li class="relative px-6 py-3">
|
|
<span x-show="currentPage === '{{ page_id }}'" class="absolute inset-y-0 left-0 w-1 bg-purple-600 rounded-tr-lg rounded-br-lg" aria-hidden="true"></span>
|
|
<a class="inline-flex items-center w-full text-sm font-semibold transition-colors duration-150 hover:text-gray-800 dark:hover:text-gray-200"
|
|
:class="currentPage === '{{ page_id }}' ? 'text-gray-800 dark:text-gray-100' : ''"
|
|
href="{{ path }}">
|
|
<span x-html="$icon('{{ icon }}', 'w-5 h-5')"></span>
|
|
<span class="ml-4">{{ label }}</span>
|
|
</a>
|
|
</li>
|
|
{% endmacro %}
|
|
|
|
{# ============================================================================
|
|
SIDEBAR CONTENT (shared between desktop and mobile)
|
|
============================================================================ #}
|
|
|
|
{% macro sidebar_content() %}
|
|
<div class="py-4 text-gray-500 dark:text-gray-400">
|
|
<!-- Merchant Branding -->
|
|
<a class="ml-6 text-lg font-bold text-gray-800 dark:text-gray-200 flex items-center"
|
|
href="/merchants/dashboard">
|
|
<span x-html="$icon('lightning-bolt', 'w-6 h-6 mr-2 text-purple-600')"></span>
|
|
<span>Merchant Portal</span>
|
|
</a>
|
|
|
|
<!-- Dashboard (always visible) -->
|
|
<ul class="mt-6">
|
|
{{ menu_item('dashboard', '/merchants/dashboard', 'home', 'Dashboard') }}
|
|
</ul>
|
|
|
|
<!-- Billing Section -->
|
|
{{ section_header('Billing', 'billing', 'credit-card') }}
|
|
{% call section_content('billing') %}
|
|
{{ menu_item('subscriptions', '/merchants/billing/subscriptions', 'clipboard-list', 'Subscriptions') }}
|
|
{{ menu_item('billing', '/merchants/billing/billing', 'currency-euro', 'Billing History') }}
|
|
{% endcall %}
|
|
|
|
<!-- Account Section -->
|
|
{{ section_header('Account', 'account', 'cog') }}
|
|
{% call section_content('account') %}
|
|
{{ menu_item('stores', '/merchants/account/stores', 'shopping-bag', 'Stores') }}
|
|
{{ menu_item('profile', '/merchants/account/profile', 'user', 'Profile') }}
|
|
{% endcall %}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{# ============================================================================
|
|
DESKTOP SIDEBAR
|
|
============================================================================ #}
|
|
|
|
<aside class="z-20 hidden w-64 overflow-y-auto bg-white dark:bg-gray-800 md:block flex-shrink-0">
|
|
{{ sidebar_content() }}
|
|
</aside>
|
|
|
|
{# ============================================================================
|
|
MOBILE SIDEBAR
|
|
============================================================================ #}
|
|
|
|
<!-- Mobile sidebar backdrop -->
|
|
<div x-show="isSideMenuOpen"
|
|
x-transition:enter="transition ease-in-out duration-150"
|
|
x-transition:enter-start="opacity-0"
|
|
x-transition:enter-end="opacity-100"
|
|
x-transition:leave="transition ease-in-out duration-150"
|
|
x-transition:leave-start="opacity-100"
|
|
x-transition:leave-end="opacity-0"
|
|
class="fixed inset-0 z-10 flex items-end bg-black bg-opacity-50 sm:items-center sm:justify-center"></div>
|
|
|
|
<!-- Mobile sidebar panel -->
|
|
<aside class="fixed inset-y-0 z-20 flex-shrink-0 w-64 mt-16 overflow-y-auto bg-white dark:bg-gray-800 md:hidden"
|
|
x-show="isSideMenuOpen"
|
|
x-transition:enter="transition ease-in-out duration-150"
|
|
x-transition:enter-start="opacity-0 transform -translate-x-20"
|
|
x-transition:enter-end="opacity-100"
|
|
x-transition:leave="transition ease-in-out duration-150"
|
|
x-transition:leave-start="opacity-100"
|
|
x-transition:leave-end="opacity-0 transform -translate-x-20"
|
|
@click.away="closeSideMenu"
|
|
@keydown.escape="closeSideMenu">
|
|
{{ sidebar_content() }}
|
|
</aside>
|