Parameterize the grid for the merge, and correct what the merge actually is
Measuring the two grids changed the shape of this. The ruling reads as porting the regions dashboard's filters control into this one; the control is already here. Same class, same show/hide labels, same aria-expanded, same caret. What differs is the styling: this one is a bordered pill with a hover fill and a COUNT BADGE of active filters, the regions one is borderless text whose caret turns over on open. So the prop is filtersToggle — which toggle, not whether — and 'link' keeps the count badge. The Driver asked for the look of the control; removing a feature along with the border would not be a restyle. The backdrop is the same story. Both sides already use assets/images/worldmap.svg; this one scopes it to the filters block, the regions dashboard puts it on the list root at 60% / top / 400px floor, measured off their live page. So backdrop is a placement prop, and 'root' switches the filters copy OFF — the same artwork painted twice at two sizes reads as a rendering fault rather than a design. Both defaults reproduce today's grid exactly, so the three hosts that already ship it are unchanged until each opts in. C3 measured before building, as asked: nil. This grid declares no scroll container and no viewport-height unit, and neither does the regions list it replaces, so embedding it inside .rd-scroll cannot produce a scroller inside a scroller. One defect caught in passing: my first attempt redeclared filtersExpanded, which already exists. The parse gate named the line, and the duplicate was the thing that revealed the control was already there.
This commit is contained in:
parent
e5dd83dad9
commit
b1e839a33f
1 changed files with 51 additions and 1 deletions
|
|
@ -72,6 +72,25 @@ defineOptions({ inheritAttrs: false })
|
|||
const props = defineProps({
|
||||
// ── injected standalone deps (replace Nuxt useRuntimeConfig / useI18n / useLocalePath) ──
|
||||
profileConfig: { type: String, default: '' },
|
||||
// ── the merge props (Driver 2026-09-28: one parameterized grid) ──────────────────────────────
|
||||
// Both defaults reproduce TODAY's grid exactly, so every existing host is unchanged until it
|
||||
// opts in. That is deliberate: this component already ships in three places and a merge that
|
||||
// moved any of them without being asked would be the drift the merge exists to remove.
|
||||
//
|
||||
// filtersToggle: WHICH TOGGLE, not whether. Measuring the two grids turned up that this one
|
||||
// ALREADY has the show/hide control — same class, same labels, same aria-expanded, same caret —
|
||||
// so the ruling's "keep the regions filters control" is a RESTYLE, not a capability to port.
|
||||
// 'button' = today: a bordered pill with a hover fill and a COUNT BADGE of active filters.
|
||||
// 'link' = the regions dashboard's: borderless text with a caret that rotates 180 on open.
|
||||
// The count badge exists only on 'button'. Losing it would be a real regression, so 'link' keeps
|
||||
// it rather than reproducing the regions markup exactly — the Driver asked for the look of the
|
||||
// control, not for a feature to be removed with it.
|
||||
filtersToggle: { type: String, default: 'button' },
|
||||
// backdrop: where worldmap.svg goes. 'filters' = today (behind the filters block, and only when
|
||||
// search or filters are on). 'root' = the regions treatment, measured off dx-life's live page:
|
||||
// the LIST ROOT at background-size 60%, background-position top, min-height 400px. 'none' = off.
|
||||
// Same asset either way — assets/images/worldmap.svg — so this is placement, not a second copy.
|
||||
backdrop: { type: String, default: 'filters' },
|
||||
prayBaseUrl: { type: String, default: '' },
|
||||
languageCode: { type: String, default: '' },
|
||||
// ★ default '' NOT '/research/': a non-empty prop default is ALWAYS truthy, so the computed
|
||||
|
|
@ -237,6 +256,9 @@ const cfg = computed(() => {
|
|||
// Only drawn when the block actually exists: with show-search and show-filters both off there is
|
||||
// no filter block to sit behind, and a backdrop with nothing on it is just noise.
|
||||
const filtersBackdrop = computed(() => {
|
||||
// 'root' takes the watermark over, so the filters block must NOT also paint it: two copies of
|
||||
// the same artwork at different sizes reads as a rendering fault, not a design.
|
||||
if (backdropMode.value !== 'filters') return null
|
||||
if (!useSearch.value && !useFilters.value) return null
|
||||
const base = resolveAssetsBase(cfg.value)
|
||||
return {
|
||||
|
|
@ -326,6 +348,25 @@ const t = computed(() => {
|
|||
|
||||
// ── Cat-2 show/hide (accept the DOM-attribute string 'false') ──────────────────
|
||||
const truthy = (v) => !(v === false || v === 'false' || v === '0' || v === 0)
|
||||
const toggleStyle = computed(() => (props.filtersToggle === 'link' ? 'link' : 'button'))
|
||||
const backdropMode = computed(() => (['filters', 'root', 'none'].includes(props.backdrop) ? props.backdrop : 'filters'))
|
||||
/**
|
||||
* The root treatment, measured off dx-life's live /regions page rather than invented: the LIST
|
||||
* ROOT carries worldmap.svg at background-size 60%, background-position top, no-repeat, with a
|
||||
* 400px floor so the watermark has room to read on a short list. Same asset the 'filters' mode
|
||||
* uses — this is placement, not a second copy.
|
||||
*/
|
||||
const rootBackdrop = computed(() => {
|
||||
if (backdropMode.value !== 'root') return null
|
||||
const base = resolveAssetsBase(cfg.value)
|
||||
return {
|
||||
backgroundImage: `url(${base}/images/worldmap.svg)`,
|
||||
backgroundSize: '60%',
|
||||
backgroundPosition: 'top',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
minHeight: '400px',
|
||||
}
|
||||
})
|
||||
const useSearch = computed(() => truthy(props.showSearch))
|
||||
const useFilters = computed(() => truthy(props.showFilters))
|
||||
const useTotal = computed(() => truthy(props.showTotal))
|
||||
|
|
@ -894,7 +935,7 @@ onMounted(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pgg-root">
|
||||
<div class="pgg-root" :style="rootBackdrop">
|
||||
<!-- The element's OWN filters block: shown by default, hidden when driven externally. -->
|
||||
<div v-if="useSearch || useFilters" id="filters" class="filters" :style="filtersBackdrop">
|
||||
<!-- ★ EXACT BELONGS IN THE SEARCH ROW, because it modifies the SEARCH.
|
||||
|
|
@ -923,6 +964,7 @@ onMounted(() => {
|
|||
<button
|
||||
v-if="useFilters"
|
||||
class="filters__toggle"
|
||||
:class="{ 'filters__toggle--link': toggleStyle === 'link' }"
|
||||
type="button"
|
||||
:aria-expanded="filtersExpanded"
|
||||
@click="toggleFilters"
|
||||
|
|
@ -1122,6 +1164,14 @@ onMounted(() => {
|
|||
.filters__toggle:hover { background: var(--dx-accent-weak, rgba(146,177,149,.18)); border-color: var(--dx-accent, #92b195); }
|
||||
.filters__toggle:focus-visible { outline: 2px solid var(--dx-accent, #92b195); outline-offset: 2px; }
|
||||
.filters__toggle-icon { color: var(--dx-accent, #92b195); flex: none; }
|
||||
/* The regions dashboard's variant: borderless, and the caret turns over on open so the control
|
||||
states its own direction rather than relying on the word beside it. The rotation is the part
|
||||
that reads as "better"; the count badge is kept, because losing a feature is not a restyle. */
|
||||
.filters__toggle--link { background: none; border-color: transparent; padding-inline: 0; }
|
||||
.filters__toggle--link:hover { background: none; text-decoration: underline; }
|
||||
.filters__toggle--link .filters__toggle-icon { transition: transform 200ms ease; }
|
||||
.filters__toggle--link[aria-expanded="true"] .filters__toggle-icon { transform: rotate(180deg); }
|
||||
@media (prefers-reduced-motion: reduce) { .filters__toggle--link .filters__toggle-icon { transition: none; } }
|
||||
.filters__toggle-count {
|
||||
background: var(--dx-accent, #92b195); color: #fff; border-radius: 999px;
|
||||
min-width: 18px; padding: 0 5px; font-size: 0.75rem; line-height: 18px; text-align: center;
|
||||
|
|
|
|||
Loading…
Reference in a new issue