docs: add architecture rules and docs for e-commerce components
Architecture rules added: - FE-008: Use number_stepper macro for quantity inputs - FE-009: Use product_card macro for product displays - FE-010: Use product_grid macro for product listings - FE-011: Use add_to_cart macros for cart interactions - FE-012: Use mini_cart macro for cart dropdown Documentation: - Update ui-components-quick-reference.md with e-commerce section - Add component-standards.md for standardization guidelines - Add ecommerce-components-proposal.md with full 20-component roadmap - Update validate_architecture.py with FE-008 detection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -663,6 +663,124 @@ Show empty state when lists have no items.
|
||||
|
||||
---
|
||||
|
||||
### Jinja Macro Rules (app/templates/**/*.html)
|
||||
|
||||
#### MAC-001: Use Shared Macros for Repeated Patterns
|
||||
**Severity:** Error
|
||||
|
||||
Never copy-paste HTML patterns. Use or create shared macros in `app/templates/shared/macros/`.
|
||||
|
||||
```jinja
|
||||
{# ✅ Good - Using shared macro #}
|
||||
{% from 'shared/macros/tables.html' import table_wrapper, table_header %}
|
||||
{% call table_wrapper() %}
|
||||
{{ table_header(['Name', 'Email', 'Status']) }}
|
||||
<tbody>...</tbody>
|
||||
{% endcall %}
|
||||
|
||||
{# ❌ Bad - Copy-pasting table HTML #}
|
||||
<div class="w-full overflow-hidden rounded-lg shadow-xs">
|
||||
<div class="w-full overflow-x-auto">
|
||||
<table class="w-full whitespace-no-wrap">
|
||||
<thead>...</thead>
|
||||
<tbody>...</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### MAC-002: Import Macros at Template Top
|
||||
**Severity:** Warning
|
||||
|
||||
All macro imports should be at the top of the template, after `{% extends %}`.
|
||||
|
||||
```jinja
|
||||
{# ✅ Good #}
|
||||
{% extends "admin/base.html" %}
|
||||
{% from 'shared/macros/pagination.html' import pagination %}
|
||||
{% from 'shared/macros/tables.html' import table_wrapper %}
|
||||
{% from 'shared/macros/alerts.html' import loading_state %}
|
||||
|
||||
{% block content %}
|
||||
...
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
#### MAC-003: Use {% call %} for Wrapper Macros
|
||||
**Severity:** Error
|
||||
|
||||
Wrapper macros that use `{{ caller() }}` must be invoked with `{% call %}`.
|
||||
|
||||
```jinja
|
||||
{# ✅ Good #}
|
||||
{% call table_wrapper() %}
|
||||
{{ table_header(['Col1', 'Col2']) }}
|
||||
{% endcall %}
|
||||
|
||||
{% call tabs_nav() %}
|
||||
{{ tab_button('tab1', 'First') }}
|
||||
{% endcall %}
|
||||
|
||||
{# ❌ Bad - Missing call block #}
|
||||
{{ table_wrapper() }} {# This won't render inner content! #}
|
||||
```
|
||||
|
||||
#### MAC-004: Document New Macros
|
||||
**Severity:** Warning
|
||||
|
||||
New macros must have JSDoc-style documentation comments.
|
||||
|
||||
```jinja
|
||||
{# ✅ Good #}
|
||||
{#
|
||||
Number Stepper
|
||||
==============
|
||||
A number input with +/- buttons.
|
||||
|
||||
Parameters:
|
||||
- model: Alpine.js x-model variable (required)
|
||||
- min: Minimum value (default: 1)
|
||||
- max: Maximum value (optional)
|
||||
|
||||
Usage:
|
||||
{{ number_stepper(model='quantity', min=1, max=99) }}
|
||||
#}
|
||||
{% macro number_stepper(model, min=1, max=none) %}
|
||||
...
|
||||
{% endmacro %}
|
||||
```
|
||||
|
||||
#### MAC-005: Add Components to Reference Page
|
||||
**Severity:** Warning
|
||||
|
||||
New shared components should be added to `/admin/components` page with live demos.
|
||||
|
||||
---
|
||||
|
||||
### Frontend Component Rules (app/templates/**/*.html)
|
||||
|
||||
#### FE-008: Use number_stepper Macro for Quantity Inputs
|
||||
**Severity:** Warning
|
||||
|
||||
Use the shared `number_stepper` macro instead of raw `<input type="number">` for consistent styling and dark mode support.
|
||||
|
||||
```jinja
|
||||
{# ✅ Good - Using number_stepper macro #}
|
||||
{% from 'shared/macros/inputs.html' import number_stepper %}
|
||||
{{ number_stepper(model='quantity', min=1, max=99) }}
|
||||
|
||||
{# ❌ Bad - Raw number input #}
|
||||
<input type="number" x-model="quantity" min="1" max="99" />
|
||||
```
|
||||
|
||||
**Suppress with `noqa` for ID fields:**
|
||||
```jinja
|
||||
{# noqa: FE-008 - User ID is typed directly, not incremented #}
|
||||
<input type="number" x-model="userId" placeholder="User ID" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Styling Rules (app/templates/**/*.html)
|
||||
|
||||
#### CSS-001: Use Tailwind Utility Classes
|
||||
@@ -885,13 +1003,15 @@ All rules are defined in `.architecture-rules.yaml`. To modify rules:
|
||||
| Backend | 20 | 15 | 5 |
|
||||
| Frontend JS | 7 | 6 | 1 |
|
||||
| Frontend Templates | 7 | 3 | 4 |
|
||||
| Frontend Macros | 5 | 2 | 3 |
|
||||
| Frontend Components | 1 | 0 | 1 |
|
||||
| Frontend Styling | 4 | 1 | 3 |
|
||||
| Naming | 5 | 3 | 2 |
|
||||
| Security | 5 | 5 | 0 |
|
||||
| Quality | 3 | 2 | 1 |
|
||||
| **Total** | **51** | **35** | **16** |
|
||||
| **Total** | **57** | **37** | **20** |
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-12-04
|
||||
**Version:** 2.2
|
||||
**Last Updated:** 2025-12-07
|
||||
**Version:** 2.3
|
||||
|
||||
461
docs/frontend/shared/component-standards.md
Normal file
461
docs/frontend/shared/component-standards.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# Frontend Component Standards
|
||||
|
||||
**Version:** 1.0
|
||||
**Last Updated:** December 2025
|
||||
**Audience:** Frontend Developers
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines mandatory standards for all frontend components across Admin, Vendor, and Shop frontends. Following these standards ensures consistency, maintainability, and a unified user experience.
|
||||
|
||||
---
|
||||
|
||||
## Golden Rules
|
||||
|
||||
1. **Use Jinja Macros** - Never copy-paste HTML patterns; use shared macros
|
||||
2. **Alpine.js for Interactivity** - All client-side logic uses Alpine.js
|
||||
3. **Dark Mode Required** - Every component must support dark mode
|
||||
4. **Accessibility First** - ARIA labels, keyboard navigation, focus states
|
||||
5. **Mobile Responsive** - Mobile-first design with Tailwind breakpoints
|
||||
|
||||
---
|
||||
|
||||
## Jinja Macro System
|
||||
|
||||
### Available Macro Files
|
||||
|
||||
All macros are located in `app/templates/shared/macros/`:
|
||||
|
||||
| File | Purpose | Key Macros |
|
||||
|------|---------|------------|
|
||||
| `pagination.html` | Table pagination | `pagination()`, `pagination_simple()` |
|
||||
| `alerts.html` | Alerts and toasts | `loading_state()`, `error_state()`, `alert_dynamic()` |
|
||||
| `badges.html` | Status indicators | `badge()`, `status_badge()`, `role_badge()` |
|
||||
| `buttons.html` | Button variants | `btn_primary()`, `btn_secondary()`, `action_button()` |
|
||||
| `forms.html` | Form inputs | `form_input()`, `form_select()`, `form_textarea()` |
|
||||
| `tables.html` | Table components | `table_wrapper()`, `table_header()`, `table_empty_state()` |
|
||||
| `cards.html` | Card layouts | `stat_card()`, `card()`, `info_card()` |
|
||||
| `headers.html` | Page headers | `page_header()`, `page_header_flex()`, `refresh_button()` |
|
||||
| `modals.html` | Modal dialogs | `modal()`, `confirm_modal()`, `job_details_modal()` |
|
||||
| `tabs.html` | Tab navigation | `tabs_nav()`, `tabs_inline()`, `tab_button()` |
|
||||
| `inputs.html` | Specialized inputs | `search_autocomplete()`, `number_stepper()` |
|
||||
|
||||
### Macro Usage Rules
|
||||
|
||||
#### RULE 1: Always Import Before Use
|
||||
|
||||
```jinja
|
||||
{# ✅ CORRECT - Import at top of template #}
|
||||
{% from 'shared/macros/tables.html' import table_wrapper, table_header %}
|
||||
{% from 'shared/macros/pagination.html' import pagination %}
|
||||
|
||||
{% block content %}
|
||||
{% call table_wrapper() %}
|
||||
{{ table_header(['Name', 'Email', 'Status']) }}
|
||||
...
|
||||
{% endcall %}
|
||||
{{ pagination() }}
|
||||
{% endblock %}
|
||||
|
||||
{# ❌ WRONG - Inline HTML instead of macro #}
|
||||
{% block content %}
|
||||
<div class="w-full overflow-hidden rounded-lg shadow-xs">
|
||||
<div class="w-full overflow-x-auto">
|
||||
<table class="w-full whitespace-no-wrap">
|
||||
...
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
#### RULE 2: Use Macros for Repeated Patterns
|
||||
|
||||
If you find yourself copying HTML more than once, create or use a macro.
|
||||
|
||||
```jinja
|
||||
{# ✅ CORRECT - Using badge macro #}
|
||||
{{ status_badge(status='active') }}
|
||||
{{ status_badge(status='pending') }}
|
||||
{{ status_badge(status='inactive') }}
|
||||
|
||||
{# ❌ WRONG - Copy-pasting badge HTML #}
|
||||
<span class="px-2 py-1 text-xs font-semibold text-green-800 bg-green-100 rounded-full">Active</span>
|
||||
<span class="px-2 py-1 text-xs font-semibold text-yellow-800 bg-yellow-100 rounded-full">Pending</span>
|
||||
```
|
||||
|
||||
#### RULE 3: Use `{% call %}` for Wrapper Macros
|
||||
|
||||
Macros that wrap content use the `caller()` pattern:
|
||||
|
||||
```jinja
|
||||
{# ✅ CORRECT - Using call block #}
|
||||
{% call table_wrapper() %}
|
||||
{{ table_header(['Column 1', 'Column 2']) }}
|
||||
<tbody>...</tbody>
|
||||
{% endcall %}
|
||||
|
||||
{% call tabs_nav() %}
|
||||
{{ tab_button('tab1', 'First Tab', icon='home') }}
|
||||
{{ tab_button('tab2', 'Second Tab', icon='cog') }}
|
||||
{% endcall %}
|
||||
```
|
||||
|
||||
#### RULE 4: Prefer Macro Parameters Over Custom CSS
|
||||
|
||||
```jinja
|
||||
{# ✅ CORRECT - Using size parameter #}
|
||||
{{ number_stepper(model='qty', size='sm') }}
|
||||
{{ number_stepper(model='qty', size='lg') }}
|
||||
|
||||
{# ❌ WRONG - Adding custom classes #}
|
||||
{{ number_stepper(model='qty') }}
|
||||
<style>.my-stepper { transform: scale(0.8); }</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Categories
|
||||
|
||||
### 1. Layout Components
|
||||
|
||||
#### Page Headers
|
||||
```jinja
|
||||
{% from 'shared/macros/headers.html' import page_header_flex, refresh_button %}
|
||||
|
||||
{% call page_header_flex(title='Page Title', subtitle='Optional description') %}
|
||||
{{ refresh_button(onclick='refreshData()') }}
|
||||
<button class="...">Add New</button>
|
||||
{% endcall %}
|
||||
```
|
||||
|
||||
#### Cards
|
||||
```jinja
|
||||
{% from 'shared/macros/cards.html' import stat_card %}
|
||||
|
||||
{{ stat_card(
|
||||
label='Total Users',
|
||||
value='1,234',
|
||||
icon='user-group',
|
||||
color='purple'
|
||||
) }}
|
||||
```
|
||||
|
||||
### 2. Data Display Components
|
||||
|
||||
#### Tables with Pagination
|
||||
```jinja
|
||||
{% from 'shared/macros/tables.html' import table_wrapper, table_header, table_empty_state %}
|
||||
{% from 'shared/macros/pagination.html' import pagination %}
|
||||
|
||||
{% call table_wrapper() %}
|
||||
{{ table_header(['Name', 'Email', 'Status', 'Actions']) }}
|
||||
<tbody class="bg-white divide-y dark:divide-gray-700 dark:bg-gray-800">
|
||||
<template x-for="item in items" :key="item.id">
|
||||
<tr class="text-gray-700 dark:text-gray-400">
|
||||
...
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
|
||||
{{ table_empty_state(
|
||||
message='No items found',
|
||||
icon='inbox',
|
||||
show_condition='!loading && items.length === 0'
|
||||
) }}
|
||||
|
||||
{{ pagination() }}
|
||||
```
|
||||
|
||||
#### Badges
|
||||
```jinja
|
||||
{% from 'shared/macros/badges.html' import status_badge %}
|
||||
|
||||
{{ status_badge(status='active') }} {# Green #}
|
||||
{{ status_badge(status='pending') }} {# Yellow #}
|
||||
{{ status_badge(status='inactive') }} {# Red #}
|
||||
{{ status_badge(status='processing') }} {# Blue #}
|
||||
```
|
||||
|
||||
### 3. Form Components
|
||||
|
||||
#### Standard Inputs
|
||||
```jinja
|
||||
{% from 'shared/macros/forms.html' import form_input, form_select %}
|
||||
|
||||
{{ form_input(
|
||||
name='email',
|
||||
label='Email Address',
|
||||
type='email',
|
||||
model='formData.email',
|
||||
required=true,
|
||||
error_var='errors.email'
|
||||
) }}
|
||||
|
||||
{{ form_select(
|
||||
name='status',
|
||||
label='Status',
|
||||
model='formData.status',
|
||||
options=[
|
||||
{'value': 'active', 'label': 'Active'},
|
||||
{'value': 'inactive', 'label': 'Inactive'}
|
||||
]
|
||||
) }}
|
||||
```
|
||||
|
||||
#### Number Stepper
|
||||
```jinja
|
||||
{% from 'shared/macros/inputs.html' import number_stepper %}
|
||||
|
||||
{# Cart quantity #}
|
||||
{{ number_stepper(model='quantity', min=1, max=99, size='md') }}
|
||||
|
||||
{# Batch size with step #}
|
||||
{{ number_stepper(model='batchSize', min=100, max=5000, step=100, size='lg') }}
|
||||
```
|
||||
|
||||
#### Search Autocomplete
|
||||
```jinja
|
||||
{% from 'shared/macros/inputs.html' import search_autocomplete, selected_item_display %}
|
||||
|
||||
{{ search_autocomplete(
|
||||
search_var='searchQuery',
|
||||
results_var='searchResults',
|
||||
show_dropdown_var='showDropdown',
|
||||
loading_var='searching',
|
||||
select_action='selectItem(item)',
|
||||
display_field='name',
|
||||
secondary_field='email',
|
||||
placeholder='Search users...'
|
||||
) }}
|
||||
|
||||
{{ selected_item_display(
|
||||
selected_var='selectedUser',
|
||||
display_field='name',
|
||||
secondary_field='email',
|
||||
clear_action='clearSelection()'
|
||||
) }}
|
||||
```
|
||||
|
||||
### 4. Navigation Components
|
||||
|
||||
#### Tabs
|
||||
```jinja
|
||||
{% from 'shared/macros/tabs.html' import tabs_nav, tabs_inline, tab_button %}
|
||||
|
||||
{# Full-width navigation tabs #}
|
||||
{% call tabs_nav() %}
|
||||
{{ tab_button('overview', 'Overview', icon='home') }}
|
||||
{{ tab_button('details', 'Details', icon='document') }}
|
||||
{{ tab_button('settings', 'Settings', icon='cog') }}
|
||||
{% endcall %}
|
||||
|
||||
{# Inline tabs with counts #}
|
||||
{% call tabs_inline() %}
|
||||
{{ tab_button('all', 'All', count_var='items.length') }}
|
||||
{{ tab_button('active', 'Active', count_var='activeCount') }}
|
||||
{{ tab_button('archived', 'Archived', count_var='archivedCount') }}
|
||||
{% endcall %}
|
||||
```
|
||||
|
||||
### 5. Feedback Components
|
||||
|
||||
#### Alerts
|
||||
```jinja
|
||||
{% from 'shared/macros/alerts.html' import alert_dynamic, loading_state, error_state %}
|
||||
|
||||
{{ alert_dynamic(type='success', message_var='successMessage', show_condition='successMessage') }}
|
||||
{{ alert_dynamic(type='error', message_var='errorMessage', show_condition='errorMessage') }}
|
||||
|
||||
{{ loading_state(message='Loading data...', show_condition='loading') }}
|
||||
{{ error_state(title='Error', show_condition='error') }}
|
||||
```
|
||||
|
||||
#### Modals
|
||||
```jinja
|
||||
{% from 'shared/macros/modals.html' import confirm_modal %}
|
||||
|
||||
{{ confirm_modal(
|
||||
show_var='showDeleteModal',
|
||||
title='Confirm Delete',
|
||||
message='Are you sure you want to delete this item?',
|
||||
confirm_action='deleteItem()',
|
||||
confirm_text='Delete',
|
||||
confirm_class='bg-red-600 hover:bg-red-700'
|
||||
) }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dark Mode Requirements
|
||||
|
||||
Every component MUST support dark mode using Tailwind's `dark:` prefix.
|
||||
|
||||
### Color Pairing Reference
|
||||
|
||||
| Element | Light Mode | Dark Mode |
|
||||
|---------|------------|-----------|
|
||||
| Background | `bg-white` | `dark:bg-gray-800` |
|
||||
| Card Background | `bg-gray-50` | `dark:bg-gray-900` |
|
||||
| Text Primary | `text-gray-700` | `dark:text-gray-200` |
|
||||
| Text Secondary | `text-gray-500` | `dark:text-gray-400` |
|
||||
| Border | `border-gray-300` | `dark:border-gray-600` |
|
||||
| Hover Background | `hover:bg-gray-100` | `dark:hover:bg-gray-700` |
|
||||
| Input Background | `bg-white` | `dark:bg-gray-700` |
|
||||
| Focus Ring | `focus:ring-purple-500` | `dark:focus:ring-purple-400` |
|
||||
|
||||
### Example
|
||||
```html
|
||||
<div class="bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 border border-gray-300 dark:border-gray-600">
|
||||
<h3 class="text-gray-900 dark:text-gray-100">Title</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400">Description</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accessibility Requirements
|
||||
|
||||
### Required ARIA Attributes
|
||||
|
||||
```html
|
||||
{# Button with loading state #}
|
||||
<button :aria-busy="loading" :disabled="loading">
|
||||
<span x-show="!loading">Submit</span>
|
||||
<span x-show="loading">Loading...</span>
|
||||
</button>
|
||||
|
||||
{# Icon-only button #}
|
||||
<button aria-label="Delete item" title="Delete">
|
||||
<span x-html="$icon('trash', 'w-4 h-4')"></span>
|
||||
</button>
|
||||
|
||||
{# Number stepper group #}
|
||||
<div role="group" aria-label="Quantity selector">
|
||||
<button aria-label="Decrease quantity">-</button>
|
||||
<input aria-label="Quantity" />
|
||||
<button aria-label="Increase quantity">+</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Focus States
|
||||
|
||||
All interactive elements must have visible focus states:
|
||||
```html
|
||||
<button class="focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2">
|
||||
Click me
|
||||
</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Icon System
|
||||
|
||||
### Usage
|
||||
```html
|
||||
{# Standard icon #}
|
||||
<span x-html="$icon('user', 'w-5 h-5')"></span>
|
||||
|
||||
{# Icon with color #}
|
||||
<span x-html="$icon('check-circle', 'w-5 h-5 text-green-500')"></span>
|
||||
|
||||
{# Inline icon in button #}
|
||||
<button class="flex items-center">
|
||||
<span x-html="$icon('plus', 'w-4 h-4 mr-2')"></span>
|
||||
Add Item
|
||||
</button>
|
||||
```
|
||||
|
||||
### Common Icons Reference
|
||||
|
||||
| Icon | Usage |
|
||||
|------|-------|
|
||||
| `home` | Dashboard/Home |
|
||||
| `user` | Users/Profile |
|
||||
| `cog` | Settings |
|
||||
| `plus` | Add/Create |
|
||||
| `edit` | Edit/Modify |
|
||||
| `trash` | Delete |
|
||||
| `check-circle` | Success/Verified |
|
||||
| `x-circle` | Error/Failed |
|
||||
| `clock` | Pending/Time |
|
||||
| `refresh` | Reload/Sync |
|
||||
| `eye` | View/Details |
|
||||
| `download` | Download/Export |
|
||||
| `upload` | Upload/Import |
|
||||
| `search` | Search |
|
||||
| `filter` | Filter |
|
||||
| `minus` | Decrease |
|
||||
|
||||
---
|
||||
|
||||
## Creating New Components
|
||||
|
||||
### When to Create a Macro
|
||||
|
||||
Create a new macro when:
|
||||
- Pattern is used 3+ times across templates
|
||||
- Component has configurable options
|
||||
- Component requires consistent styling
|
||||
|
||||
### Macro Template
|
||||
```jinja
|
||||
{#
|
||||
Component Name
|
||||
==============
|
||||
Brief description of what the component does.
|
||||
|
||||
Parameters:
|
||||
- param1: Description (required/optional, default: value)
|
||||
- param2: Description
|
||||
|
||||
Usage:
|
||||
{{ component_name(param1='value', param2='value') }}
|
||||
#}
|
||||
{% macro component_name(
|
||||
param1,
|
||||
param2='default'
|
||||
) %}
|
||||
<div class="...">
|
||||
{# Component HTML #}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
```
|
||||
|
||||
### Checklist for New Components
|
||||
|
||||
- [ ] Supports dark mode (`dark:` variants)
|
||||
- [ ] Has ARIA labels for accessibility
|
||||
- [ ] Documented with JSDoc-style comment
|
||||
- [ ] Added to `/admin/components` page
|
||||
- [ ] Added to this documentation
|
||||
- [ ] Uses existing design tokens (colors, spacing)
|
||||
- [ ] Tested in both light and dark mode
|
||||
- [ ] Works on mobile viewport
|
||||
|
||||
---
|
||||
|
||||
## Component Reference Page
|
||||
|
||||
For live examples and copy-paste code, visit:
|
||||
|
||||
**Admin Panel:** `/admin/components`
|
||||
|
||||
This page includes:
|
||||
- Interactive demos
|
||||
- Code snippets with copy button
|
||||
- All available macros
|
||||
- Usage examples
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [UI Components Quick Reference](ui-components-quick-reference.md)
|
||||
- [Icons Guide](../../development/icons-guide.md)
|
||||
- [Tailwind CSS Guide](../tailwind-css.md)
|
||||
- [Frontend Overview](../overview.md)
|
||||
- [Architecture Rules](../../development/architecture-rules.md)
|
||||
@@ -116,6 +116,108 @@
|
||||
</span>
|
||||
```
|
||||
|
||||
## Number Stepper
|
||||
|
||||
A number input with +/- buttons for quantity selection. Ideal for cart quantities, batch sizes, and product pages.
|
||||
|
||||
### Basic Number Stepper
|
||||
```html
|
||||
{% from 'shared/macros/inputs.html' import number_stepper %}
|
||||
|
||||
{# Basic usage - cart quantity #}
|
||||
{{ number_stepper(model='quantity', min=1, max=99) }}
|
||||
```
|
||||
|
||||
### Size Variants
|
||||
```html
|
||||
{# Small - compact for tables/lists #}
|
||||
{{ number_stepper(model='item.qty', min=1, max='item.stock', size='sm') }}
|
||||
|
||||
{# Medium (default) #}
|
||||
{{ number_stepper(model='quantity', min=1, max=99) }}
|
||||
|
||||
{# Large - prominent placement #}
|
||||
{{ number_stepper(model='batchSize', min=100, max=5000, step=100, size='lg') }}
|
||||
```
|
||||
|
||||
### With Disabled State
|
||||
```html
|
||||
{{ number_stepper(model='qty', min=1, disabled_var='isLoading') }}
|
||||
```
|
||||
|
||||
### Number Stepper Parameters
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `model` | required | Alpine.js x-model variable |
|
||||
| `min` | `1` | Minimum allowed value |
|
||||
| `max` | `none` | Maximum allowed value (can be Alpine.js expression) |
|
||||
| `step` | `1` | Increment/decrement step |
|
||||
| `size` | `'md'` | Size variant: `'sm'`, `'md'`, `'lg'` |
|
||||
| `disabled_var` | `none` | Alpine.js variable for disabled state |
|
||||
| `name` | `none` | Input name for form submission |
|
||||
| `id` | `none` | Input id attribute |
|
||||
| `label` | `'Quantity'` | Accessible label for screen readers |
|
||||
|
||||
---
|
||||
|
||||
## Tabs
|
||||
|
||||
Tab navigation components for switching between content sections.
|
||||
|
||||
### 🗂️ Navigation Tabs (with icons)
|
||||
```html
|
||||
{% from 'shared/macros/tabs.html' import tabs_nav, tab_button %}
|
||||
|
||||
{% call tabs_nav() %}
|
||||
{{ tab_button('dashboard', 'Dashboard', icon='home') }}
|
||||
{{ tab_button('settings', 'Settings', icon='cog') }}
|
||||
{{ tab_button('profile', 'Profile', icon='user') }}
|
||||
{% endcall %}
|
||||
|
||||
<!-- Tab content panels -->
|
||||
<div x-show="activeTab === 'dashboard'" x-transition>
|
||||
Dashboard content...
|
||||
</div>
|
||||
```
|
||||
|
||||
### 🗂️ Inline Tabs (with count badges)
|
||||
```html
|
||||
{% from 'shared/macros/tabs.html' import tabs_inline, tab_button %}
|
||||
|
||||
<div class="flex justify-between gap-4">
|
||||
{% call tabs_inline() %}
|
||||
{{ tab_button('all', 'All Items', count_var='allItems.length') }}
|
||||
{{ tab_button('active', 'Active', count_var='activeItems.length') }}
|
||||
{{ tab_button('archived', 'Archived', count_var='archivedItems.length') }}
|
||||
{% endcall %}
|
||||
<div>Search...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 🗂️ Tabs with Custom Click Handlers
|
||||
```html
|
||||
{% call tabs_nav() %}
|
||||
{{ tab_button('database', 'Database Logs',
|
||||
tab_var='logSource',
|
||||
icon='database',
|
||||
onclick="logSource = 'database'; loadDatabaseLogs()") }}
|
||||
{{ tab_button('file', 'File Logs',
|
||||
tab_var='logSource',
|
||||
icon='document',
|
||||
onclick="logSource = 'file'; loadFileLogs()") }}
|
||||
{% endcall %}
|
||||
```
|
||||
|
||||
### Tab Button Parameters
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `id` | required | Tab identifier for comparison |
|
||||
| `label` | required | Display text |
|
||||
| `tab_var` | `'activeTab'` | Alpine.js variable for active state |
|
||||
| `icon` | `none` | Optional icon name |
|
||||
| `count_var` | `none` | Alpine.js variable for count badge |
|
||||
| `onclick` | `none` | Custom click handler (overrides default) |
|
||||
|
||||
## Grid Layouts
|
||||
|
||||
### 2 Columns (Desktop)
|
||||
@@ -223,6 +325,138 @@
|
||||
7. Helper text: `text-xs text-gray-600`
|
||||
8. Error text: `text-xs text-red-600`
|
||||
|
||||
---
|
||||
|
||||
## E-commerce Components (Shop Frontend)
|
||||
|
||||
Reusable macros for shop/storefront functionality. Located in `app/templates/shared/macros/shop/`.
|
||||
|
||||
### 🛍️ Product Card
|
||||
```html
|
||||
{% from 'shared/macros/shop/product-card.html' import product_card %}
|
||||
|
||||
{# Basic product card #}
|
||||
{{ product_card(product_var='product') }}
|
||||
|
||||
{# With size and options #}
|
||||
{{ product_card(
|
||||
product_var='item',
|
||||
size='lg',
|
||||
show_rating=true,
|
||||
show_quick_add=true,
|
||||
show_wishlist=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Size variants:** `sm` (compact), `md` (default), `lg` (featured)
|
||||
|
||||
**Features:**
|
||||
- Sale badge (when `sale_price` exists)
|
||||
- "New" badge (when `is_new` is true)
|
||||
- Out of stock overlay
|
||||
- Star ratings with review count
|
||||
- Wishlist toggle button
|
||||
- Quick add to cart
|
||||
|
||||
### 🛍️ Product Grid
|
||||
```html
|
||||
{% from 'shared/macros/shop/product-grid.html' import product_grid %}
|
||||
|
||||
{# Basic grid #}
|
||||
{{ product_grid(products_var='products', loading_var='loading') }}
|
||||
|
||||
{# With empty state #}
|
||||
{{ product_grid(
|
||||
products_var='searchResults',
|
||||
loading_var='searching',
|
||||
empty_message='No products found',
|
||||
empty_icon='search'
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Responsive columns (auto-adjusts or fixed)
|
||||
- Loading skeleton placeholders
|
||||
- Empty state with customizable icon/message
|
||||
|
||||
### 🛒 Add to Cart
|
||||
```html
|
||||
{% from 'shared/macros/shop/add-to-cart.html' import add_to_cart_button, add_to_cart_form, buy_now_button %}
|
||||
|
||||
{# Simple button #}
|
||||
{{ add_to_cart_button(action='addToCart()') }}
|
||||
|
||||
{# Complete form with quantity #}
|
||||
{{ add_to_cart_form(product_var='product', size='md') }}
|
||||
|
||||
{# Buy now button #}
|
||||
{{ buy_now_button(action='buyNow()') }}
|
||||
```
|
||||
|
||||
**Macros available:**
|
||||
- `add_to_cart_button()` - Simple button with loading state
|
||||
- `add_to_cart_form()` - Form with quantity selector + button
|
||||
- `buy_now_button()` - Direct checkout button
|
||||
- `shop_quantity_selector()` - Stock-aware quantity input
|
||||
|
||||
### 🛒 Mini Cart (Header)
|
||||
```html
|
||||
{% from 'shared/macros/shop/mini-cart.html' import mini_cart, mini_cart_icon %}
|
||||
|
||||
{# Complete mini cart with dropdown #}
|
||||
{{ mini_cart(cart_var='cart', show_var='showCart') }}
|
||||
|
||||
{# Just the icon with badge #}
|
||||
{{ mini_cart_icon(cart_var='cart', size='md') }}
|
||||
```
|
||||
|
||||
**Macros available:**
|
||||
- `mini_cart()` - Combined icon + dropdown
|
||||
- `mini_cart_icon()` - Icon with item count badge
|
||||
- `mini_cart_dropdown()` - Dropdown panel
|
||||
- `cart_item()` - Individual item display
|
||||
- `cart_summary()` - Subtotal, shipping, total
|
||||
|
||||
### E-commerce Alpine.js State
|
||||
```javascript
|
||||
// Required state variables for e-commerce components
|
||||
{
|
||||
// Products
|
||||
products: [],
|
||||
loading: true,
|
||||
|
||||
// Cart
|
||||
cart: {
|
||||
items: [],
|
||||
item_count: 0,
|
||||
subtotal: 0,
|
||||
total: 0
|
||||
},
|
||||
showCart: false,
|
||||
|
||||
// Add to cart
|
||||
quantity: 1,
|
||||
addingToCart: false,
|
||||
addedToCart: false,
|
||||
|
||||
// Wishlist
|
||||
toggleWishlist(product) {
|
||||
product.in_wishlist = !product.in_wishlist;
|
||||
},
|
||||
|
||||
// Cart actions
|
||||
addToCart() {
|
||||
this.addingToCart = true;
|
||||
// API call...
|
||||
},
|
||||
removeFromCart(itemId) {
|
||||
this.cart.items = this.cart.items.filter(i => i.id !== itemId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reference Page
|
||||
|
||||
Visit `/admin/components` for full component library with live examples!
|
||||
|
||||
622
docs/frontend/shop/ecommerce-components-proposal.md
Normal file
622
docs/frontend/shop/ecommerce-components-proposal.md
Normal file
@@ -0,0 +1,622 @@
|
||||
# E-commerce Components Proposal
|
||||
|
||||
**Version:** 1.0
|
||||
**Created:** December 2025
|
||||
**Status:** Proposal
|
||||
**Author:** Development Team
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This document proposes a comprehensive set of reusable Jinja macro components for the shop frontend. These components will standardize the e-commerce experience across all vendor shops while supporting vendor-specific theming via CSS variables.
|
||||
|
||||
---
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Vendor Theming** - Use CSS variables (`var(--color-primary)`) for brand colors
|
||||
2. **Mobile First** - Responsive design starting from mobile
|
||||
3. **Performance** - Lazy loading, optimized images, minimal JS
|
||||
4. **Accessibility** - WCAG 2.1 AA compliant
|
||||
5. **Consistency** - Same UX patterns across all shops
|
||||
|
||||
---
|
||||
|
||||
## Proposed Components
|
||||
|
||||
### Priority 1: Core Shopping Components
|
||||
|
||||
#### 1.1 Product Card
|
||||
**File:** `app/templates/shared/macros/shop/product-card.html`
|
||||
|
||||
A versatile product card for grids, carousels, and lists.
|
||||
|
||||
```jinja
|
||||
{{ product_card(
|
||||
product=product,
|
||||
show_vendor=false,
|
||||
show_rating=true,
|
||||
show_quick_add=true,
|
||||
size='md', {# sm, md, lg #}
|
||||
layout='vertical' {# vertical, horizontal #}
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Product image with lazy loading
|
||||
- Sale badge / "New" badge
|
||||
- Product title (truncated)
|
||||
- Price (with strikethrough for sales)
|
||||
- Star rating
|
||||
- Quick "Add to Cart" button
|
||||
- Wishlist heart icon
|
||||
- Hover effects
|
||||
|
||||
**Variants:**
|
||||
| Size | Use Case |
|
||||
|------|----------|
|
||||
| `sm` | Mobile grids, sidebars |
|
||||
| `md` | Standard product grids |
|
||||
| `lg` | Featured products, hero sections |
|
||||
|
||||
---
|
||||
|
||||
#### 1.2 Product Grid
|
||||
**File:** `app/templates/shared/macros/shop/product-grid.html`
|
||||
|
||||
Responsive grid layout for product listings.
|
||||
|
||||
```jinja
|
||||
{{ product_grid(
|
||||
products=products,
|
||||
columns={'sm': 2, 'md': 3, 'lg': 4},
|
||||
gap='md',
|
||||
show_empty_state=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Responsive column configuration
|
||||
- Loading skeleton state
|
||||
- Empty state with CTA
|
||||
- "Load more" or pagination integration
|
||||
|
||||
---
|
||||
|
||||
#### 1.3 Add to Cart Button
|
||||
**File:** `app/templates/shared/macros/shop/add-to-cart.html`
|
||||
|
||||
Standardized add-to-cart functionality.
|
||||
|
||||
```jinja
|
||||
{{ add_to_cart_button(
|
||||
product_id='product.id',
|
||||
variant_id='selectedVariant?.id',
|
||||
quantity_model='quantity',
|
||||
show_quantity=true,
|
||||
size='md',
|
||||
full_width=false
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Loading state during add
|
||||
- Success animation
|
||||
- Out of stock state
|
||||
- Quantity selector integration (uses `number_stepper`)
|
||||
- "Added!" feedback
|
||||
|
||||
---
|
||||
|
||||
#### 1.4 Quantity Selector (Shop Version)
|
||||
**File:** Already exists as `number_stepper` in `inputs.html`
|
||||
|
||||
Shop-specific wrapper with stock validation:
|
||||
|
||||
```jinja
|
||||
{{ shop_quantity_selector(
|
||||
model='quantity',
|
||||
max='product.stock',
|
||||
disabled_var='addingToCart',
|
||||
out_of_stock_var='product.stock === 0'
|
||||
) }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Priority 2: Cart Components
|
||||
|
||||
#### 2.1 Mini Cart (Header Dropdown)
|
||||
**File:** `app/templates/shared/macros/shop/mini-cart.html`
|
||||
|
||||
Dropdown cart preview in the header.
|
||||
|
||||
```jinja
|
||||
{{ mini_cart(
|
||||
cart_var='cart',
|
||||
max_items=3,
|
||||
show_checkout_button=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Cart item count badge
|
||||
- Item thumbnails
|
||||
- Quick quantity adjust
|
||||
- Remove item button
|
||||
- Subtotal display
|
||||
- "View Cart" and "Checkout" CTAs
|
||||
|
||||
---
|
||||
|
||||
#### 2.2 Cart Item Row
|
||||
**File:** `app/templates/shared/macros/shop/cart-item.html`
|
||||
|
||||
Individual cart line item.
|
||||
|
||||
```jinja
|
||||
{{ cart_item(
|
||||
item='item',
|
||||
index='index',
|
||||
show_image=true,
|
||||
editable=true,
|
||||
compact=false
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Product thumbnail
|
||||
- Product name + variant info
|
||||
- Unit price
|
||||
- Quantity stepper (using `number_stepper` with `size='sm'`)
|
||||
- Line total
|
||||
- Remove button
|
||||
- Stock warning if low
|
||||
|
||||
---
|
||||
|
||||
#### 2.3 Cart Summary
|
||||
**File:** `app/templates/shared/macros/shop/cart-summary.html`
|
||||
|
||||
Order summary sidebar/section.
|
||||
|
||||
```jinja
|
||||
{{ cart_summary(
|
||||
cart_var='cart',
|
||||
show_promo_code=true,
|
||||
show_shipping_estimate=true,
|
||||
checkout_url='/checkout'
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Subtotal
|
||||
- Discount code input
|
||||
- Applied discounts
|
||||
- Estimated shipping
|
||||
- Tax display
|
||||
- Order total
|
||||
- Checkout CTA
|
||||
- Secure payment badges
|
||||
|
||||
---
|
||||
|
||||
### Priority 3: Product Detail Components
|
||||
|
||||
#### 3.1 Product Gallery
|
||||
**File:** `app/templates/shared/macros/shop/product-gallery.html`
|
||||
|
||||
Image gallery with thumbnails and zoom.
|
||||
|
||||
```jinja
|
||||
{{ product_gallery(
|
||||
images='product.images',
|
||||
show_thumbnails=true,
|
||||
enable_zoom=true,
|
||||
enable_fullscreen=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Main image display
|
||||
- Thumbnail navigation
|
||||
- Image zoom on hover
|
||||
- Fullscreen lightbox
|
||||
- Swipe support on mobile
|
||||
- Video support
|
||||
|
||||
---
|
||||
|
||||
#### 3.2 Variant Selector
|
||||
**File:** `app/templates/shared/macros/shop/variant-selector.html`
|
||||
|
||||
Product variant selection (size, color, etc.).
|
||||
|
||||
```jinja
|
||||
{{ variant_selector(
|
||||
variants='product.variants',
|
||||
selected_var='selectedVariant',
|
||||
type='buttons' {# buttons, dropdown, swatches #}
|
||||
) }}
|
||||
```
|
||||
|
||||
**Variant Types:**
|
||||
- **Buttons** - Size selection (S, M, L, XL)
|
||||
- **Dropdown** - Many options
|
||||
- **Swatches** - Color selection with preview
|
||||
|
||||
**Features:**
|
||||
- Out of stock variants disabled
|
||||
- Low stock warning
|
||||
- Price change on selection
|
||||
- Image change on color selection
|
||||
|
||||
---
|
||||
|
||||
#### 3.3 Product Info Block
|
||||
**File:** `app/templates/shared/macros/shop/product-info.html`
|
||||
|
||||
Product details section.
|
||||
|
||||
```jinja
|
||||
{{ product_info(
|
||||
product='product',
|
||||
show_sku=true,
|
||||
show_stock=true,
|
||||
show_vendor=false
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Product title (H1)
|
||||
- Price display (sale price handling)
|
||||
- Rating stars + review count
|
||||
- Short description
|
||||
- SKU display
|
||||
- Stock status
|
||||
- Vendor name (marketplace)
|
||||
|
||||
---
|
||||
|
||||
#### 3.4 Product Tabs
|
||||
**File:** `app/templates/shared/macros/shop/product-tabs.html`
|
||||
|
||||
Tabbed product information.
|
||||
|
||||
```jinja
|
||||
{{ product_tabs(
|
||||
product='product',
|
||||
tabs=['description', 'specifications', 'reviews', 'shipping']
|
||||
) }}
|
||||
```
|
||||
|
||||
**Tab Options:**
|
||||
- Description (HTML content)
|
||||
- Specifications (key-value table)
|
||||
- Reviews (review list + form)
|
||||
- Shipping info
|
||||
- Returns policy
|
||||
|
||||
---
|
||||
|
||||
### Priority 4: Navigation & Discovery
|
||||
|
||||
#### 4.1 Category Navigation
|
||||
**File:** `app/templates/shared/macros/shop/category-nav.html`
|
||||
|
||||
Category browsing sidebar/menu.
|
||||
|
||||
```jinja
|
||||
{{ category_nav(
|
||||
categories='categories',
|
||||
current_category='currentCategory',
|
||||
show_count=true,
|
||||
collapsible=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Nested category tree
|
||||
- Product counts
|
||||
- Active state highlighting
|
||||
- Collapsible sections
|
||||
- Mobile drawer version
|
||||
|
||||
---
|
||||
|
||||
#### 4.2 Breadcrumbs
|
||||
**File:** `app/templates/shared/macros/shop/breadcrumbs.html`
|
||||
|
||||
Navigation breadcrumb trail.
|
||||
|
||||
```jinja
|
||||
{{ shop_breadcrumbs(
|
||||
items=[
|
||||
{'label': 'Home', 'url': '/'},
|
||||
{'label': 'Electronics', 'url': '/category/electronics'},
|
||||
{'label': 'Headphones', 'url': none}
|
||||
]
|
||||
) }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 4.3 Search Bar
|
||||
**File:** `app/templates/shared/macros/shop/search-bar.html`
|
||||
|
||||
Product search with autocomplete.
|
||||
|
||||
```jinja
|
||||
{{ search_bar(
|
||||
placeholder='Search products...',
|
||||
show_suggestions=true,
|
||||
show_categories=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Autocomplete suggestions
|
||||
- Recent searches
|
||||
- Category filter
|
||||
- Voice search (optional)
|
||||
- Mobile fullscreen mode
|
||||
|
||||
---
|
||||
|
||||
#### 4.4 Filter Sidebar
|
||||
**File:** `app/templates/shared/macros/shop/filter-sidebar.html`
|
||||
|
||||
Product filtering panel.
|
||||
|
||||
```jinja
|
||||
{{ filter_sidebar(
|
||||
filters='availableFilters',
|
||||
active_filters='activeFilters',
|
||||
show_price_range=true,
|
||||
show_rating_filter=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Filter Types:**
|
||||
- Checkbox (brand, size)
|
||||
- Color swatches
|
||||
- Price range slider
|
||||
- Rating stars
|
||||
- In-stock toggle
|
||||
|
||||
---
|
||||
|
||||
### Priority 5: Social Proof & Trust
|
||||
|
||||
#### 5.1 Star Rating
|
||||
**File:** `app/templates/shared/macros/shop/star-rating.html`
|
||||
|
||||
Reusable star rating display.
|
||||
|
||||
```jinja
|
||||
{{ star_rating(
|
||||
rating=4.5,
|
||||
max=5,
|
||||
size='md',
|
||||
show_count=true,
|
||||
count=127
|
||||
) }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 5.2 Review Card
|
||||
**File:** `app/templates/shared/macros/shop/review-card.html`
|
||||
|
||||
Individual product review.
|
||||
|
||||
```jinja
|
||||
{{ review_card(
|
||||
review='review',
|
||||
show_verified_badge=true,
|
||||
show_helpful_buttons=true
|
||||
) }}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Reviewer name/avatar
|
||||
- Star rating
|
||||
- Review date
|
||||
- Review text
|
||||
- Verified purchase badge
|
||||
- Helpful/Not helpful buttons
|
||||
- Review images
|
||||
|
||||
---
|
||||
|
||||
#### 5.3 Trust Badges
|
||||
**File:** `app/templates/shared/macros/shop/trust-badges.html`
|
||||
|
||||
Trust and security indicators.
|
||||
|
||||
```jinja
|
||||
{{ trust_badges(
|
||||
badges=['secure_payment', 'free_shipping', 'returns', 'support']
|
||||
) }}
|
||||
```
|
||||
|
||||
**Badge Options:**
|
||||
- Secure payment
|
||||
- Free shipping over X
|
||||
- Easy returns
|
||||
- 24/7 support
|
||||
- Money back guarantee
|
||||
- SSL secured
|
||||
|
||||
---
|
||||
|
||||
### Priority 6: Promotional Components
|
||||
|
||||
#### 6.1 Sale Banner
|
||||
**File:** `app/templates/shared/macros/shop/sale-banner.html`
|
||||
|
||||
Promotional banner with countdown.
|
||||
|
||||
```jinja
|
||||
{{ sale_banner(
|
||||
title='Summer Sale',
|
||||
subtitle='Up to 50% off',
|
||||
end_date='2025-08-31',
|
||||
show_countdown=true,
|
||||
cta_text='Shop Now',
|
||||
cta_url='/sale'
|
||||
) }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 6.2 Product Badge
|
||||
**File:** `app/templates/shared/macros/shop/product-badge.html`
|
||||
|
||||
Product overlay badges.
|
||||
|
||||
```jinja
|
||||
{{ product_badge(type='sale', value='-20%') }}
|
||||
{{ product_badge(type='new') }}
|
||||
{{ product_badge(type='bestseller') }}
|
||||
{{ product_badge(type='low_stock', value='Only 3 left') }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 6.3 Recently Viewed
|
||||
**File:** `app/templates/shared/macros/shop/recently-viewed.html`
|
||||
|
||||
Recently viewed products carousel.
|
||||
|
||||
```jinja
|
||||
{{ recently_viewed(
|
||||
products='recentlyViewed',
|
||||
max_items=6,
|
||||
title='Recently Viewed'
|
||||
) }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Core Components (Week 1-2)
|
||||
- [ ] Product Card
|
||||
- [ ] Product Grid
|
||||
- [ ] Add to Cart Button
|
||||
- [ ] Mini Cart
|
||||
- [ ] Cart Item Row
|
||||
- [ ] Cart Summary
|
||||
|
||||
### Phase 2: Product Detail (Week 3-4)
|
||||
- [ ] Product Gallery
|
||||
- [ ] Variant Selector
|
||||
- [ ] Product Info Block
|
||||
- [ ] Product Tabs
|
||||
- [ ] Star Rating
|
||||
|
||||
### Phase 3: Navigation (Week 5-6)
|
||||
- [ ] Category Navigation
|
||||
- [ ] Breadcrumbs
|
||||
- [ ] Search Bar
|
||||
- [ ] Filter Sidebar
|
||||
|
||||
### Phase 4: Social & Promo (Week 7-8)
|
||||
- [ ] Review Card
|
||||
- [ ] Trust Badges
|
||||
- [ ] Sale Banner
|
||||
- [ ] Product Badge
|
||||
- [ ] Recently Viewed
|
||||
|
||||
---
|
||||
|
||||
## CSS Variables for Theming
|
||||
|
||||
All shop components will use these CSS variables set by the vendor theme:
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Primary brand colors */
|
||||
--color-primary: #7c3aed;
|
||||
--color-primary-hover: #6d28d9;
|
||||
--color-primary-light: #8b5cf6;
|
||||
|
||||
/* Secondary colors */
|
||||
--color-secondary: #f3f4f6;
|
||||
--color-secondary-hover: #e5e7eb;
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #111827;
|
||||
--color-text-secondary: #6b7280;
|
||||
|
||||
/* Status colors */
|
||||
--color-success: #10b981;
|
||||
--color-warning: #f59e0b;
|
||||
--color-error: #ef4444;
|
||||
--color-sale: #dc2626;
|
||||
|
||||
/* UI colors */
|
||||
--color-border: #e5e7eb;
|
||||
--color-background: #ffffff;
|
||||
--color-surface: #f9fafb;
|
||||
|
||||
/* Spacing */
|
||||
--spacing-unit: 0.25rem;
|
||||
|
||||
/* Border radius */
|
||||
--radius-sm: 0.25rem;
|
||||
--radius-md: 0.375rem;
|
||||
--radius-lg: 0.5rem;
|
||||
--radius-full: 9999px;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
app/templates/shared/macros/shop/
|
||||
├── product-card.html
|
||||
├── product-grid.html
|
||||
├── add-to-cart.html
|
||||
├── mini-cart.html
|
||||
├── cart-item.html
|
||||
├── cart-summary.html
|
||||
├── product-gallery.html
|
||||
├── variant-selector.html
|
||||
├── product-info.html
|
||||
├── product-tabs.html
|
||||
├── category-nav.html
|
||||
├── breadcrumbs.html
|
||||
├── search-bar.html
|
||||
├── filter-sidebar.html
|
||||
├── star-rating.html
|
||||
├── review-card.html
|
||||
├── trust-badges.html
|
||||
├── sale-banner.html
|
||||
├── product-badge.html
|
||||
└── recently-viewed.html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Review & Approve** - Team reviews this proposal
|
||||
2. **Prioritize** - Confirm component priority order
|
||||
3. **Design Mockups** - Create visual designs for key components
|
||||
4. **Implementation** - Build components in priority order
|
||||
5. **Documentation** - Add to component reference page
|
||||
6. **Testing** - Test across vendors and themes
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Component Standards](../shared/component-standards.md)
|
||||
- [Shop Architecture](architecture.md)
|
||||
- [Theme System](../../architecture/theme-system/overview.md)
|
||||
- [UI Components Quick Reference](../shared/ui-components-quick-reference.md)
|
||||
Reference in New Issue
Block a user