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:
2025-12-07 17:04:28 +01:00
parent c903248846
commit 95a8ffc645
7 changed files with 1629 additions and 9 deletions

View File

@@ -397,6 +397,10 @@ class ArchitectureValidator:
if not is_components_page and not is_macro:
self._check_icon_helper_usage(file_path, content, lines)
# FE-008: Check for raw number inputs (should use number_stepper)
if not is_components_page and not is_macro:
self._check_number_stepper_macro_usage(file_path, content, lines)
# Only check admin templates for extends
if "/admin/" not in file_path_str and "\\admin\\" not in file_path_str:
return
@@ -630,12 +634,19 @@ class ArchitectureValidator:
# Look for dropdown patterns: @click.outside or @click.away with menu positioning
for i, line in enumerate(lines, 1):
if ("@click.outside=" in line or "@click.away=" in line) and "false" in line:
# Check context for dropdown menu indicators
context_lines = "\n".join(lines[max(0, i-3):min(len(lines), i+10)])
# Look for dropdown menu styling
if "absolute" in context_lines and ("right-0" in context_lines or "left-0" in context_lines):
if "py-2" in context_lines or "py-1" in context_lines:
# Match @click.away="something = false" or @click.outside="..."
if "@click.away=" in line or "@click.outside=" in line:
# Skip if this is a modal (modals also use @click.away but have different structure)
context_lines = "\n".join(lines[max(0, i-5):min(len(lines), i+10)])
# Skip if it looks like a modal (fixed inset-0)
if "fixed inset-0" in context_lines:
continue
# Look for dropdown menu styling: absolute positioning with z-index
if "absolute" in context_lines and ("z-10" in context_lines or "z-20" in context_lines or "z-50" in context_lines):
# Additional indicators: shadow, border, bg-white/dark, rounded
if "shadow" in context_lines or "border" in context_lines:
self._add_violation(
rule_id="FE-006",
rule_name="Use dropdowns macro",
@@ -678,6 +689,56 @@ class ArchitectureValidator:
)
return
def _check_number_stepper_macro_usage(self, file_path: Path, content: str, lines: list[str]):
"""FE-008: Check for raw number inputs that should use number_stepper macro
Detects <input type="number"> that should use the number_stepper macro for
consistent styling and dark mode support.
Exceptions:
- ID fields (placeholder contains 'id' or 'ID')
- Files already importing number_stepper
- Lines with noqa: FE-008 comment
"""
# Check if already using the number_stepper macro
uses_macro = any("number_stepper" in line for line in lines)
if uses_macro:
return
# Check for file-level noqa comment
has_noqa = any("noqa: fe-008" in line.lower() for line in lines)
if has_noqa:
return
# Look for raw number inputs
for i, line in enumerate(lines, 1):
if 'type="number"' in line or "type='number'" in line:
# Skip if line has noqa comment
if "noqa" in line.lower():
continue
# Skip if it looks like an ID field (check surrounding lines for context)
context_lines = "\n".join(lines[max(0, i-3):min(len(lines), i+2)]).lower()
if "user id" in context_lines or "placeholder" in context_lines and "id" in context_lines:
continue
# Skip if it's in a comment
stripped = line.strip()
if stripped.startswith("{#") or stripped.startswith("<!--") or stripped.startswith("//"):
continue
self._add_violation(
rule_id="FE-008",
rule_name="Use number_stepper macro",
severity=Severity.WARNING,
file_path=file_path,
line_number=i,
message="Raw number input found - use number_stepper macro for consistent styling",
context=stripped[:70],
suggestion="{% from 'shared/macros/inputs.html' import number_stepper %}\n{{ number_stepper(model='fieldName', min=1, max=100) }}\nOr add {# noqa: FE-008 #} if this is intentional (e.g., ID field)",
)
return # Only report once per file
def _validate_api_endpoints(self, target_path: Path):
"""Validate API endpoint rules (API-001, API-002, API-003, API-004)"""
print("📡 Validating API endpoints...")
@@ -1225,6 +1286,10 @@ class ArchitectureValidator:
if not is_base_or_partial and not is_macro and not is_components_page:
self._check_headers_macro_usage(file_path, content, lines)
# FE-008: Check for raw number inputs (should use number_stepper)
if not is_base_or_partial and not is_macro and not is_components_page:
self._check_number_stepper_macro_usage(file_path, content, lines)
# Skip base/partials for TPL-001 check
if is_base_or_partial:
continue