Files
orion/app/templates/shared/macros/storefront/breadcrumbs.html
Samir Boulahtit 7245f79f7b refactor: rename shop to storefront for consistency
Rename all "shop" directories and references to "storefront" to match
the API and route naming convention already in use.

Renamed directories:
- app/templates/shop/ → app/templates/storefront/
- static/shop/ → static/storefront/
- app/templates/shared/macros/shop/ → .../macros/storefront/
- docs/frontend/shop/ → docs/frontend/storefront/

Renamed files:
- shop.css → storefront.css
- shop-layout.js → storefront-layout.js

Updated references in:
- app/routes/storefront_pages.py (21 template references)
- app/modules/cms/routes/pages/vendor.py
- app/templates/storefront/base.html (static paths)
- All storefront templates (extends/includes)
- docs/architecture/frontend-structure.md

This aligns the template/static naming with:
- Route file: storefront_pages.py
- API directory: app/api/v1/storefront/
- Module routes: */routes/api/storefront.py
- URL paths: /storefront/*

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:58:28 +01:00

263 lines
9.3 KiB
HTML

{#
Breadcrumbs Components
======================
Navigation breadcrumb trail for shop pages.
Usage:
{% from 'shared/macros/shop/breadcrumbs.html' import shop_breadcrumbs, auto_breadcrumbs %}
#}
{#
Shop Breadcrumbs
================
Breadcrumb navigation trail.
Parameters:
- items: List of breadcrumb items (static)
- items_var: Alpine.js expression for items (dynamic)
- separator: Separator icon (default: 'chevron-right')
- show_home: Show home link (default: true)
- home_url: URL for home (default: '/')
- home_label: Label for home (default: 'Home')
Item structure:
{
label: 'Category Name',
url: '/category/...', // Optional, last item typically has no URL
icon: 'folder' // Optional icon
}
Usage (static):
{{ shop_breadcrumbs(items=[
{'label': 'Electronics', 'url': '/category/electronics'},
{'label': 'Headphones', 'url': '/category/headphones'},
{'label': 'Wireless'}
]) }}
Usage (dynamic):
{{ shop_breadcrumbs(items_var='breadcrumbs') }}
#}
{% macro shop_breadcrumbs(
items=none,
items_var=none,
separator='chevron-right',
show_home=true,
home_url='/',
home_label='Home'
) %}
<nav aria-label="Breadcrumb" class="flex items-center text-sm">
<ol class="flex items-center flex-wrap gap-1">
{% if show_home %}
<li class="flex items-center">
<a
href="{{ home_url }}"
class="flex items-center gap-1 text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
>
<span x-html="$icon('home', 'w-4 h-4')"></span>
<span class="sr-only sm:not-sr-only">{{ home_label }}</span>
</a>
</li>
<li class="flex items-center text-gray-400 dark:text-gray-500" aria-hidden="true">
<span x-html="$icon('{{ separator }}', 'w-4 h-4')"></span>
</li>
{% endif %}
{% if items %}
{# Static items #}
{% for item in items %}
<li class="flex items-center">
{% if item.url and not loop.last %}
<a
href="{{ item.url }}"
class="flex items-center gap-1 text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
>
{% if item.icon %}
<span x-html="$icon('{{ item.icon }}', 'w-4 h-4')"></span>
{% endif %}
<span>{{ item.label }}</span>
</a>
{% else %}
<span class="flex items-center gap-1 text-gray-900 dark:text-white font-medium" aria-current="page">
{% if item.icon %}
<span x-html="$icon('{{ item.icon }}', 'w-4 h-4')"></span>
{% endif %}
<span>{{ item.label }}</span>
</span>
{% endif %}
</li>
{% if not loop.last %}
<li class="flex items-center text-gray-400 dark:text-gray-500" aria-hidden="true">
<span x-html="$icon('{{ separator }}', 'w-4 h-4')"></span>
</li>
{% endif %}
{% endfor %}
{% elif items_var %}
{# Dynamic items from Alpine.js #}
<template x-for="(item, index) in {{ items_var }}" :key="index">
<li class="flex items-center">
<template x-if="item.url && index < {{ items_var }}.length - 1">
<a
:href="item.url"
class="flex items-center gap-1 text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
>
<span x-show="item.icon" x-html="$icon(item.icon, 'w-4 h-4')"></span>
<span x-text="item.label"></span>
</a>
</template>
<template x-if="!item.url || index === {{ items_var }}.length - 1">
<span class="flex items-center gap-1 text-gray-900 dark:text-white font-medium" aria-current="page">
<span x-show="item.icon" x-html="$icon(item.icon, 'w-4 h-4')"></span>
<span x-text="item.label"></span>
</span>
</template>
</li>
</template>
<template x-for="(item, index) in {{ items_var }}.slice(0, -1)" :key="'sep-' + index">
<li class="flex items-center text-gray-400 dark:text-gray-500 order-last" aria-hidden="true" :style="'order: ' + (index * 2 + 1)">
<span x-html="$icon('{{ separator }}', 'w-4 h-4')"></span>
</li>
</template>
{% endif %}
</ol>
</nav>
{% endmacro %}
{#
Auto Breadcrumbs
================
Automatically generates breadcrumbs from category hierarchy.
Parameters:
- product_var: Alpine.js expression for product (optional)
- category_var: Alpine.js expression for current category
- show_home: Show home link (default: true)
Usage:
{{ auto_breadcrumbs(category_var='currentCategory') }}
{{ auto_breadcrumbs(product_var='product') }}
#}
{% macro auto_breadcrumbs(
product_var=none,
category_var='currentCategory',
show_home=true
) %}
<nav
aria-label="Breadcrumb"
class="flex items-center text-sm"
x-data="{
get breadcrumbs() {
const items = [];
{% if product_var %}
// Build from product's category
let cat = {{ product_var }}?.category;
{% else %}
let cat = {{ category_var }};
{% endif %}
// Build category path (from parent to child)
const categoryPath = [];
while (cat) {
categoryPath.unshift(cat);
cat = cat.parent;
}
categoryPath.forEach(c => {
items.push({
label: c.name,
url: c.url || '/category/' + c.slug
});
});
{% if product_var %}
// Add product as last item
items.push({
label: {{ product_var }}?.name,
url: null
});
{% endif %}
return items;
}
}"
>
<ol class="flex items-center flex-wrap gap-1">
{% if show_home %}
<li class="flex items-center">
<a href="/" class="flex items-center gap-1 text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors">
<span x-html="$icon('home', 'w-4 h-4')"></span>
<span class="sr-only sm:not-sr-only">Home</span>
</a>
</li>
<li class="flex items-center text-gray-400 dark:text-gray-500" aria-hidden="true">
<span x-html="$icon('chevron-right', 'w-4 h-4')"></span>
</li>
{% endif %}
<template x-for="(item, index) in breadcrumbs" :key="index">
<li class="flex items-center">
<template x-if="item.url && index < breadcrumbs.length - 1">
<a :href="item.url" class="text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors" x-text="item.label"></a>
</template>
<template x-if="!item.url || index === breadcrumbs.length - 1">
<span class="text-gray-900 dark:text-white font-medium" aria-current="page" x-text="item.label"></span>
</template>
<span x-show="index < breadcrumbs.length - 1" class="mx-2 text-gray-400 dark:text-gray-500" x-html="$icon('chevron-right', 'w-4 h-4')"></span>
</li>
</template>
</ol>
</nav>
{% endmacro %}
{#
Compact Breadcrumbs
===================
Mobile-friendly breadcrumbs showing only parent and current.
Parameters:
- parent: Parent item (static)
- parent_var: Alpine.js expression for parent
- current: Current page label
- current_var: Alpine.js expression for current
Usage:
{{ compact_breadcrumbs(parent={'label': 'Electronics', 'url': '/electronics'}, current='Headphones') }}
#}
{% macro compact_breadcrumbs(
parent=none,
parent_var=none,
current=none,
current_var=none
) %}
<nav aria-label="Breadcrumb" class="flex items-center text-sm">
{% if parent %}
<a
href="{{ parent.url }}"
class="flex items-center gap-1 text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
>
<span x-html="$icon('arrow-left', 'w-4 h-4')"></span>
<span>{{ parent.label }}</span>
</a>
{% elif parent_var %}
<a
:href="{{ parent_var }}?.url || '/'"
class="flex items-center gap-1 text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
>
<span x-html="$icon('arrow-left', 'w-4 h-4')"></span>
<span x-text="{{ parent_var }}?.label || 'Back'"></span>
</a>
{% endif %}
<span class="mx-2 text-gray-400 dark:text-gray-500">/</span>
{% if current %}
<span class="text-gray-900 dark:text-white font-medium" aria-current="page">{{ current }}</span>
{% elif current_var %}
<span class="text-gray-900 dark:text-white font-medium" aria-current="page" x-text="{{ current_var }}"></span>
{% endif %}
</nav>
{% endmacro %}