Add ProviderCard molecule — first molecule in design system

First molecule component. Listing card for funeral providers on the
provider select screen (map + scrollable list layout).

- Verified providers: hero image, 48px logo overlay, "Trusted Partner"
  badge, name, location, reviews, capability badge, footer with price
- Unverified providers: text-only with same content alignment
- 7 component tokens (image height, logo size, footer/content spacing)
- Composes Card (interactive, padding="none") + Badge + Typography
- Capability badges accept arbitrary label + colour (categories may change)
- Footer bar with warm brand.100 bg, "Packages from $X >"
- 9 Storybook stories including mixed list layout demo
- Decisions D026-D030 logged

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 17:39:03 +11:00
parent c10a5e4e1c
commit f31e37c837
10 changed files with 843 additions and 3 deletions

View File

@@ -219,3 +219,43 @@ contradict a previous one.
**Rationale:** Leading icons (email, phone, dollar) are essential for FA's arrangement forms. Success state provides positive feedback after validation. The Figma only had trailing icon, but leading icons are a near-universal production need. The `startIcon`/`endIcon` props are simpler than MUI's `InputAdornment` pattern while remaining compatible with raw adornments via `startAdornment`/`endAdornment`.
**Affects:** Input component API, InputAdornment usage, Storybook stories
**Alternatives considered:** Only supporting MUI's raw adornment API — rejected as too verbose for the common case. The convenience props are ergonomic while the raw props remain available for complex cases (e.g., password toggle with IconButton).
### D026 — ProviderCard establishes the molecule pattern
**Date:** 2026-03-25
**Category:** architecture
**Decision:** ProviderCard is the first molecule. Molecules compose existing atoms via `sx` props — no MUI theme overrides. All styling from token CSS variables and theme accessors.
**Rationale:** Keeps molecules lightweight and composable. Theme overrides are reserved for atoms where global consistency matters. Molecules are higher-level compositions with more context-specific layouts.
**Affects:** All future molecules (VenueCard, MapCard, ServiceOption, etc.)
**Alternatives considered:** Adding MuiProviderCard theme overrides — rejected as molecules are page-specific compositions, not reusable primitives.
### D027 — ProviderCard image is a URL string, not a ReactNode
**Date:** 2026-03-25
**Category:** component
**Decision:** `imageUrl` prop accepts a string rendered as CSS `background-image` with `cover`. Logo is also a URL string rendered as `<img>`.
**Rationale:** Simpler API for the common case (CDN URLs). CSS background-image handles aspect ratio cropping automatically. `<img>` for logo supports `alt` text natively for accessibility.
**Affects:** ProviderCard, VenueCard, MapCard APIs
**Alternatives considered:** ReactNode for image — rejected as over-flexible. A ReactNode slot would allow video/carousel but adds API complexity for a feature we don't need yet.
### D028 — Logo is 48px (not 75px from Figma)
**Date:** 2026-03-25
**Category:** component
**Decision:** Logo overlay is 48px diameter, not the 75px shown in Figma.
**Rationale:** On a ~340-400px card in a list panel, a 75px logo dominates the content area. 48px provides clear brand visibility while leaving sufficient space for the provider name and meta row.
**Affects:** providerCard.logo.size token
**Alternatives considered:** 75px from Figma — too large for the card width. 64px — still large relative to content.
### D029 — Footer is built into ProviderCard, not a slot
**Date:** 2026-03-25
**Category:** component
**Decision:** The "Packages from $X >" footer is rendered via a `startingPrice` number prop, not a children/slot pattern.
**Rationale:** The footer is structurally identical across all provider cards — warm background, "Packages from" text, price, chevron. Only the price value changes. A slot would add API complexity for no flexibility gain. If footer is omitted (no startingPrice), the bar is simply absent.
**Affects:** ProviderCard API, VenueCard may use a similar pattern
**Alternatives considered:** children/render prop for footer — rejected as over-engineered for a fixed layout.
### D030 — Verified is an explicit boolean, not derived from imageUrl
**Date:** 2026-03-25
**Category:** component
**Decision:** `verified` boolean prop controls the visual treatment independently from `imageUrl`/`logoUrl`.
**Rationale:** A provider could be verified but have a broken/missing image URL. The boolean is the source of truth from the business layer. Image and logo are only rendered when `verified` is also true, preventing accidental display of unverified providers with images.
**Affects:** ProviderCard API, data model expectations
**Alternatives considered:** Deriving verified from imageUrl presence — rejected as it couples business logic (partner status) to content availability (image uploaded).