feat: Worker portal Stage 1.5 — upgrade panel-state utility classes to 4 Askama-macro primitives
Description
Phase-1.5 follow-up to #485 (closed) (Stage 1 design system extraction). The original Stage 1 ships the 8 primitives (PanelFrame … MoneyCell) plus four CSS-only panel-state utility classes (cy-pulse, .cy-skeleton, .cy-error-block, .cy-empty-state). Design has confirmed those four are first-class enough to be proper primitives — every panel renders all four states, source is dashboard/states.jsx in the 2026-05-14 design package.
This issue upgrades the four utility classes to four proper Askama-macro primitives with first-class props. Does not block #485 (closed); lands after.
Acceptance Criteria
- Four new Askama-macro primitives at
services/canopy-web/templates/_primitives/:EmptyState:title+body+ optionalicon+ optionalcta(label + href). Centered, ~180 px min-height.Skeleton:height+width+radiusprops; applies thecy-pulsekeyframe animation.SkeletonRow: composesSkeletonfor table-shaped panels (avatar slot + N columns).ErrorBlock:title+body+ optionallast_known_at(timestamp) +retry(htmx target) /status(link) buttons.
- Rule documented + enforced via Askama-template lint or convention test: every panel template must render all four states (
empty,loading,error,populated). - Existing four utility classes (
cy-pulsekeyframe stays;.cy-skeleton/.cy-error-block/.cy-empty-state) deprecated and removed once all callers migrate (within this MR). - At least one in-tree dashboard panel rewritten to use all four state primitives to validate the rule.
- axe-core WCAG 2.1 AA clean for the validating panel
- Playwright E2E: each state renders cleanly
- CHANGELOG entry under
=== Changed
Context & References
- Tracking issue: #460
- Epic: &51
- Plan: worker-portal-redesign.adoc, Stage 1.5
- Source:
dashboard/states.jsxfrom 2026-05-14 design package - Blocks: none in this epic (follow-up that runs in parallel with Stage 2 / Stage 3); strengthens the foundation for every Stage 5+ surface
Blocked by
- #485 (closed) (Stage 1 ships first; this upgrades the four utility classes it leaves behind)
Labels
type::feature, priority::medium, program::infrastructure, service::web, workflow::ready, compliance::wcag-21-aa