From 458ca5ff59785392df26fa60dba57fdf91d2e0f4 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Sun, 27 Sep 2026 03:10:01 +0000 Subject: [PATCH] The prayer-progress cards become shared components too The three goal cards, the stat row and their bars were the regions dashboard's own markup. They are library components now, and the plugin renders them instead of holding a copy: GoalCard title + figure + a goal line pinned to the card's bottom, with a slot for whatever sits between StatCard one figure and its caption ProgressBar a single-value track, or a segmented one with a legend useCardSurface the card surface both cards share, injected once per root under a stable label instead of copied into each The bar and its legend now read from ONE list of segments, so a width and the number printed beside it come from the same figure and cannot drift apart; before, each was computed separately. A segment's colour is a prop carrying the same token its .rd-seg--full/--partial/--none class used to set, so a shared bar needs no vocabulary about prayer and those three rules are deleted rather than left unreachable. ProgressBar carries its own reduced-motion guard. The plugin's reset is scoped to .rd-root and would not have followed the component anywhere else, which would have reintroduced the one-second sliding bar their own site suppresses. The rendered DOM is unchanged for all four instances, measured by server-rendering the real components and comparing against the markup that was deleted, including that the bar widths equal the percentOfSubject() they replace. check:regions-uses-library grows to cover all four, asserting both halves again: the plugin imports and renders them, and no longer ships their markup or CSS. The .rd-root strong rule STAYS in the plugin -- UupgsList renders a in the same shadow root and depends on it, which a file-scoped read would have called dead. --- documentation/reference-library-index.md | 18 +- library/components/charts/ProgressBar.vue | 133 ++++++++++ library/components/regions/GoalCard.vue | 156 ++++++++++++ library/components/regions/StatCard.vue | 63 +++++ library/composables/useCardSurface.js | 44 ++++ .../regions-dashboard/region-dashboards.vue | 227 ++++++------------ .../scripts/check-regions-uses-library.mjs | 67 +++++- 7 files changed, 540 insertions(+), 168 deletions(-) create mode 100644 library/components/charts/ProgressBar.vue create mode 100644 library/components/regions/GoalCard.vue create mode 100644 library/components/regions/StatCard.vue create mode 100644 library/composables/useCardSurface.js diff --git a/documentation/reference-library-index.md b/documentation/reference-library-index.md index 989bc83f7..c23c9b26a 100644 --- a/documentation/reference-library-index.md +++ b/documentation/reference-library-index.md @@ -26,10 +26,8 @@ and a change here can break other maps. `import … from '@map/components/ViewSelect.vue'` - **BarChart** — BarChart.vue — THE SHARED HORIZONTAL BAR CHART (hand-rolled SVG, zero dependencies). `import … from '@map/components/charts/BarChart.vue'` -- **DashboardFacetRail** — DashboardFacetRail (was Sidebar.vue) — RDASH redesign phase 2: the floating @map SemanticTreeLegend is DROPPED - `import … from '@map/components/dashboards/DashboardFacetRail.vue'` -- **DashboardFilterChips** — DashboardFilterChips — the live filterSet rendered as removable AND-stacked chips - `import … from '@map/components/dashboards/DashboardFilterChips.vue'` +- **ProgressBar** — ProgressBar.vue — the DX-life progress bar: a single-value track, or a segmented one with a legend. + `import … from '@map/components/charts/ProgressBar.vue'` - **PinHint** — PinHint.vue — the conversion coach-mark (bottom-center of any map). `import … from '@map/components/hints/PinHint.vue'` - **ApproxPinNote** — ApproxPinNote.vue — the ONE wording every map with people-group pins uses (APPROXPIN, 2026-09-26). @@ -88,8 +86,12 @@ and a change here can break other maps. `import … from '@map/components/poster/slots/TitleSlot.vue'` - **QaCorner** — QaCorner.vue — the embeddable QA corner widget (bottom-right of any map). `import … from '@map/components/qa/QaCorner.vue'` +- **GoalCard** — GoalCard.vue — a headline figure with a goal line pinned to the bottom of the card. + `import … from '@map/components/regions/GoalCard.vue'` - **RegionSectionCard** — RegionSectionCard.vue — one region as a card: a heading, a summary line, a grid of its countries, `import … from '@map/components/regions/RegionSectionCard.vue'` +- **StatCard** — StatCard.vue — one figure with a caption, on the DX-life card surface. + `import … from '@map/components/regions/StatCard.vue'` - **FilterDropdown** — FilterDropdown.vue — SHARED (@map/components/search/FilterDropdown.vue). `import … from '@map/components/search/FilterDropdown.vue'` - **SearchBar** — SearchBar.vue — SHARED (@map/components/search/SearchBar.vue). @@ -121,6 +123,8 @@ and a change here can break other maps. `import … from '@map/composables/retryableAsyncComponent.js'` - **useAvatarGenerator** — Avatar Generator Composable `import … from '@map/composables/useAvatarGenerator.js'` +- **useCardSurface** — useCardSurface.js — the DX-life card surface, as ONE rule set shared by every card component. + `import … from '@map/composables/useCardSurface.js'` - **useCountryOutline** — useCountryOutline.js — country boundary OUTLINE overlay on country search. `import … from '@map/composables/useCountryOutline.js'` - **useCsvExport** — useCsvExport.js — ★ SHARED LIBRARY CODE (dashboard-kit landing 3). Two parameters make it @@ -133,8 +137,6 @@ and a change here can break other maps. `import … from '@map/composables/useDocumentFont.js'` - **useEdgeScrollAffordance** — useEdgeScrollAffordance — the gray "you can scroll past this" edge strips. `import … from '@map/composables/useEdgeScrollAffordance.js'` -- **useFacetAggregation** — useFacetAggregation.js — count rows by a facet accessor, and roll the tail into one bucket. - `import … from '@map/composables/useFacetAggregation.js'` - **useGeocoderSearch** — Shared geocoder→map search logic (kind-switch + Mapbox filter builder + the `import … from '@map/composables/useGeocoderSearch.js'` - **useMapAttribution** — useMapAttribution.js — the data-credit line every map MUST carry. @@ -200,8 +202,6 @@ and a change here can break other maps. `import … from '@map/utils/colocation.js'` - **countries-meta** — countries-meta.js — a PORT of DX-life's config/countries-meta.ts (326 lines), the rollup `import … from '@map/utils/countries-meta.js'` -- **countryName** — countryName.js — a country's name in the reader's language. - `import … from '@map/utils/countryName.js'` - **embedBase** — embedBase.js — Where THIS bundle's built tree is served from, resolved at runtime. `import … from '@map/utils/embedBase.js'` - **geoUtils** — geoUtils.js — Geographic / GeoJSON Utility Functions @@ -243,8 +243,6 @@ and a change here can break other maps. `import … from '@map/data/country-posters.json'` - **iso-numeric-to-alpha2** — "4":"AF","8":"AL","12":"DZ","24":"AO","32":"AR","36":"AU","40":"AT","50":"BD", `import … from '@map/data/iso-numeric-to-alpha2.json'` -- **iso3-to-alpha2** — "_meta": { - `import … from '@map/data/iso3-to-alpha2.json'` - **langFamilyByIso** — "aar": "Afro-Asiatic", `import … from '@map/data/langFamilyByIso.json'` - **langFamilyByLanguage** — {"Chamacoco":"Zamucoan","Ninam":"Yanomaman","Yagua":"Yaguan","Muinane":"Witotoan","Finnish":"Uralic","Hill Mar diff --git a/library/components/charts/ProgressBar.vue b/library/components/charts/ProgressBar.vue new file mode 100644 index 000000000..c839dee7d --- /dev/null +++ b/library/components/charts/ProgressBar.vue @@ -0,0 +1,133 @@ +...) instead of a single element. Measured by server-rendering it. So the branches + are bare and the explanation lives here: + • showLegend -> root is the ported .stack.stack--xs wrapper, 10px above the legend + • segments only -> root is the segmented .rd-bar + • neither -> root IS the plain .rd-bar, exactly as their cards 2 and 3 render it + + DOM IS UNCHANGED FOR ALL THREE INSTANCES, deliberately, because the clone is measured against the + live site. With a legend the root is the ported .stack.stack--xs wrapper (10px between bar and + legend); without one the root IS the .rd-bar element, exactly as their cards 2 and 3 render it -- + hence the three template branches rather than one uniform wrapper, which would have added a box + DX-life does not have to two of the three cards. + + NOT ADDED HERE, ON PURPOSE: role="progressbar" / aria-valuenow. Neither their bar nor our port has + it, and inventing an accessibility tree the clone target does not have is a change to request, not + to slip in. Carded for a ruling instead. + + CONTRACT: the containing shadow root carries the DX-life token layer (--dx-track, --dx-accent, + --spacing-*). No i18n is installed or required -- every string arrives pre-localized. +--> + + + diff --git a/library/components/regions/GoalCard.vue b/library/components/regions/GoalCard.vue new file mode 100644 index 000000000..7e83280d4 --- /dev/null +++ b/library/components/regions/GoalCard.vue @@ -0,0 +1,156 @@ + + + + diff --git a/library/components/regions/StatCard.vue b/library/components/regions/StatCard.vue new file mode 100644 index 000000000..8f24f6d91 --- /dev/null +++ b/library/components/regions/StatCard.vue @@ -0,0 +1,63 @@ + + + + diff --git a/library/composables/useCardSurface.js b/library/composables/useCardSurface.js new file mode 100644 index 000000000..b8c0bcebc --- /dev/null +++ b/library/composables/useCardSurface.js @@ -0,0 +1,44 @@ +/** + * useCardSurface.js — the DX-life card surface, as ONE rule set shared by every card component. + * + * WHY THIS IS A MODULE AND NOT A COPY IN EACH CARD. Vue only injects the ROOT component's