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>
This commit is contained in:
262
app/templates/shared/macros/storefront/breadcrumbs.html
Normal file
262
app/templates/shared/macros/storefront/breadcrumbs.html
Normal file
@@ -0,0 +1,262 @@
|
||||
{#
|
||||
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 %}
|
||||
Reference in New Issue
Block a user