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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user