UTS Phase 22.2 — Flutter shared components (the reusable guide atoms/molecules)
The reuse layer. 22.1 laid the tokens; 22.2 restyles the shared atoms/molecules every post-body block (22.3) and the lightbox (22.4/22.5) compose. Get these right → 22.3/22.4 become layout-only. Every component is specified from THREE sources, each with
file:line— nothing is guessed, nothing is deferred to impl: - Look/values ←static/css/kon_guide_v2.css(the sole guide stylesheet) — the web is the reference. - Markup/behavior ← the kontent templates (…/templates/partials/{molecules,organisms}/…). - The Flutter pattern to follow ← the existing app idiom (accordion_block.dartdisclosure,media_block.dartmedia-type switch, the 22.1 token +colorScheme.primaryconvention). We upgrade existing atoms / port missing web molecules — we do not invent mechanisms. Where CSS and any summary differ, the CSS wins. Every "translation" (CSS→Flutter) is named explicitly below.Anti-rogue discipline (as 22.1): per component — re-open its cited web source + the app pattern → port → independent code-vs-source audit. New
Color.lerponly via 22.1'sgBrandInk/gBrandTint. No new architecture.
Program: Under the Tuscan Sun → Phase 22 → builds on 22.1 tokens. Owner: Flutter (with Travis).
Goal
Restyle the seven shared guide components onto 22.1 g-* tokens — kill the per-type rainbow + decorative icons, and add the two missing molecules the web already has (o_mat_gallery "Show N" disclosure, o_mat_thumb type-aware thumb). These are the atoms 22.3 (blocks) and 22.4/22.5 (lightbox) assemble; 22.2 lands visible changes wherever the atoms are already used.
Scope
In: the 7 components below. Each reads 22.1 g-* tokens; brand via colorScheme.primary. Out: block layout/composition (step_block/material_*/*_collection recompose → 22.3); the lightbox shell (22.4/22.5); deleting the old guide* rainbow consts (→ 22.6, after every consumer migrates). Atoms keep their public API where possible so 22.3 is a near-no-touch recompose (the disc and the strip change signature — listed).
Patterns this phase follows (so we upgrade, not reinvent) — grounded
| Need | The existing app pattern to follow (cited) | The web rule it satisfies |
|---|---|---|
| Expand/collapse (gallery "Show N", section) | accordion_block.dart:106-167 — StatefulWidget + open-state + InkWell header + AnimatedRotation(BootstrapIcons.chevron_down, color: colorScheme.primary) + ClipRect(AnimatedSize(200ms, easeInOut, isOpen ? body : SizedBox(height:0))) |
<details> 0fr→1fr transition + rotating chevron (.g-gal/.g-acc, CSS:246-257,220-226) |
| Render media by type (thumb/tile glyph) | media_block.dart:27 — switch (media.mediaType) over image/video/audio/document; BootstrapIcons for glyphs |
_mat_thumb.gohtml Mime-prefix branches |
| Brand / tokens | 22.1: static const + Theme.of(context).colorScheme.primary + gBrandInk/gBrandTint (no ThemeExtension) |
var(--g-*) |
| §5C block chrome | content_block_renderer.dart:41-81 + block_wrapper.dart already render hidden/heading/showDivider |
the web block dispatcher |
The component ports (the spine) — all resolved from source
22.2-A — Gallery "Show N" disclosure → new GuideGalleryDisclosure (replaces guide_thumbnail_strip.dart)
Web. _mat_gallery.gohtml:9-11 — <details class="g-gal"><summary>Show {{len Items}} <chevron/></summary><div
class="g-gal-reveal"><div><div class="g-strip">tiles</div></div></div></details> (native <details>, no JS). CSS: .g-gal (kon_guide_v2.css:245-257) collapse→reveal grid 0fr→1fr .28s; summary 11px/w600/gBrandInk + 9×6 chevron rotate(180deg) on [open] (:248-251); .g-strip (:230-232) horizontal, gap:6, snap, tiles 64×64(gTile)/gRadius; .g-tile mixed-media (:234-239): image cover / video poster+.g-tile-play (play triangle) / audio poster+waveform / audio-doc .g-tile-ic glyph on gTint; .g-tile-tag 8px label. App pattern. accordion_block.dart disclosure (table above). Current Flutter. guide_thumbnail_strip.dart — always-open ListView, all-images, old tokens. Target. GuideGalleryDisclosure(collection): - collapsed by default; header InkWell → Show <N> (11px/w600, DesignTokens.gBrandInk(colorScheme.primary)) + AnimatedRotation(turns: open?0.5:0, BootstrapIcons.chevron_down, color: gBrandInk(...)). - reveal via ClipRect(AnimatedSize(200ms easeInOut)) (the app idiom = the web's 0fr→1fr). - strip: horizontal scroll, gTile(64) tiles, gap 6, gRadius; tile by media.mediaType (switch, like media_block): image=cover; video=poster + BootstrapIcons.play_fill overlay; audio=poster + BootstrapIcons.soundwave overlay; document=gTint + doc icon; tap → existing viewer (reuse the strip's current openGalleryLightbox routing). - Replaces GuideThumbnailStrip at all 9 call sites (same collection: arg; the per-call thumbSize: is dropped — tiles are fixed gTile). Sites listed under Consumers.