C1b: the resource palette moves to library/colors/, and the local colour globs go with it
Completes C1. Source only; studio rebuilds (rule 5B). Cut on top of C1a because it
depends on that move. Rebuild scope: country-posters, doxa-research-map,
research-dashboard, dashboard-plus-grid, gospel-resources.
resource.js existed as TWO identical plugin-local copies with no library original,
while library composables resolved it through the registry — so the library depended
on a plugin registering a module the library itself documented. Now it lives in
library/colors/ like the other eight, both copies are gone, and src/colors/ holds no
.js in either plugin. The local `registerStrategies(import.meta.glob('./src/colors/*.js'))`
in both index.js files is therefore DELETED: it matched nothing after the move, and a
glob that matches nothing reads as a deliberate override. Their now-unused
registerStrategies imports went with them. That also completes the shepherd's original
C1 instruction, which C1a had to defer for exactly this reason.
★ MY OWN PREDICTION HERE WAS WRONG, and the measurement is the only reason this is
clean. I predicted check:one-palette would FAIL after the move, reasoning that the
dashboards carry 6 of resource's 8 hexes (because 6 are SHARED with affinity-block and
language-family, which they legitimately ship) while the 2 unique ones — #20c997
jesusFilm and #2c3e50 noResources — are absent, and the gate fails a PARTIAL palette.
The gate PASSES: 9 strategies, 18 pairs. Once the module is in library/colors/,
_registry.js bundles it into every consumer, so all 8 hexes are present BY CONSTRUCTION.
I had reasoned about the pre-move bundle and assumed the rebuild would not change it.
That also corrects the diagnosis I gave earlier. simpleresearch was right that there
was no disagreement, but not that the 6 were coincidental substrings in minified
output: they are real hexes, genuinely present, shared across three strategies. The
gate cannot attribute a hex to a strategy — which is a real limitation worth knowing,
just not one that bites here.
Stale comments corrected rather than left to rot: five references across
useLegendData, researchLegendOptions, useWagfRegionsLegendData and my own
wagf-region.js header all claimed these palettes live in a plugin folder. One
parenthetical keeps the old path deliberately, as history.
GATES: check:one-palette PASS 9/18 (baselined 6/12 before C1a). check:library-index
PASS after regenerating the derived menu. check:no-free-identifiers PASS. All six
affected bundles build; their artifacts reverted.
This commit is contained in:
parent
182dc37571
commit
370446390f
8 changed files with 13 additions and 179 deletions
|
|
@ -6,7 +6,7 @@
|
|||
* don tsee the you using htes colors on the reigosn dashbarod hwen you shoudl". Two surfaces
|
||||
* disagreeing about what Africa's colour means is a product defect whichever palette is prettier,
|
||||
* and he chose which one wins. Source of truth:
|
||||
* plugin-designs/doxa-research-map/src/colors/doxa-region.js, which the research dashboard and
|
||||
* library/colors/doxa-region.js (it lived at plugin-designs/doxa-research-map/src/colors/ until C1a), which the research dashboard and
|
||||
* three other consumers already paint from.
|
||||
*
|
||||
* WHAT THE CHANGE COST, measured rather than glossed (dataviz validate_palette.js, light mode,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import { getColorStrategy, COLOR_MODES } from '../../colors/_registry.js'
|
|||
// (inside the builder, at call time) so registration has already run — a
|
||||
// module-load-time read could see an empty palette.
|
||||
const doxaRegionColors = () => getColorStrategy(COLOR_MODES.DOXA_REGION)?.palette ?? {}
|
||||
// resource is likewise research-only (plugin-designs/doxa-research-map/src/colors/
|
||||
// resource is likewise research-only, and now lives in library/colors/ (C1b) (was plugin-designs/doxa-research-map/src/colors/
|
||||
// resource.js), registry-resolved. Lazy + GUARDED on propertyKey — getColorStrategy
|
||||
// falls back to language-family for unregistered modes, and that palette must not
|
||||
// masquerade as resource colors.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const COLUMNS_SIMPLE = [] // e.g. affinity-blocs — no numeric columns
|
|||
|
||||
// ─── Resource palette/names (research-only strategy) ──────────────────────────
|
||||
// resource is a per-map (research-only) strategy that lives in
|
||||
// plugin-designs/doxa-research-map/src/colors/resource.js and is resolved via
|
||||
// library/colors/resource.js (moved there in C1b) and is resolved via
|
||||
// the registry (registered by the research bundle's local src/colors glob).
|
||||
// Read LAZILY (inside the items computed, at call time) so registration has already
|
||||
// run, and GUARDED on propertyKey — getColorStrategy silently falls back to
|
||||
|
|
@ -42,7 +42,7 @@ function resourceStrategy() {
|
|||
|
||||
// ─── Region / Bloc palettes (registry strategies — single source of truth) ───
|
||||
// doxa-region and affinity-block are PER-MAP (research-only) strategies that
|
||||
// live in plugin-designs/doxa-research-map/src/colors/ and register via the
|
||||
// live in library/colors/ and are discovered by _registry.js for every bundle, not via a
|
||||
// research bundle's local src/colors glob. Read LAZILY (inside the items
|
||||
// computed, at call time) so registration has already run, and GUARDED on
|
||||
// propertyKey — getColorStrategy silently falls back to language-family when a
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import { computed } from 'vue'
|
|||
// label-keyed lookup falls back to grey for every region except "Asia" (spelled
|
||||
// identically across locales) once the user switches language. The slug is
|
||||
// locale-independent. Mirrors SLUG_PALETTE in the research bundle's
|
||||
// src/colors/doxa-region.js.
|
||||
// library/colors/doxa-region.js (moved there in C1a).
|
||||
const REGION_COLORS = {
|
||||
'africa': '#ff2e2e',
|
||||
'asia': '#1a8cff',
|
||||
|
|
|
|||
|
|
@ -33,29 +33,14 @@ import { defineCustomElement } from 'vue'
|
|||
import { createPinia } from 'pinia'
|
||||
import ProfileLoader from '@map/ProfileLoader.vue'
|
||||
import { createAppI18n } from '@map/i18n/index.js'
|
||||
import { registerStrategies } from '@map/colors/_registry.js'
|
||||
|
||||
// ─── Bundle-private profile registry ─────────────────────────────────────────
|
||||
const profileModules = import.meta.glob('./*.vue')
|
||||
|
||||
// ─── Bundle-private color strategies ─────────────────────────────────────────
|
||||
// COPIED VERBATIM from doxa-research-map/src/colors/ — affinity-block.js,
|
||||
// doxa-region.js, resource.js. countries-map.vue is a clone of research-map.vue,
|
||||
// so it needs the same three research-only strategies; without doxaRegion in
|
||||
// particular the Countries tab would silently fall back to a different palette
|
||||
// (getColorStrategy() fails soft, so the symptom is wrong colours, not an error).
|
||||
//
|
||||
// Keys are auto-derived from filenames and merged OVER the shared library set.
|
||||
// This bundle inlines its own copy of the registry (IIFE build), so registering
|
||||
// here affects THIS bundle only.
|
||||
// ★ THIS GLOB NOW COVERS resource.js ONLY. doxa-region.js and affinity-block.js moved to
|
||||
// library/colors/ (C1), where _registry.js discovers them for every bundle, so registering them
|
||||
// here would be re-declaring what the shared set already has.
|
||||
// THE GLOB STAYS rather than being deleted: resource.js is still private pending C1b (its palette
|
||||
// has 8 values and the two dashboards ship 6, which needs its owner's answer before it moves).
|
||||
// Removing the glob now would unregister resource and colour those pins by the soft fallback --
|
||||
// the same class of silent wrong-colour bug this migration is fixing.
|
||||
registerStrategies(import.meta.glob('./src/colors/*.js', { eager: true }))
|
||||
// ★ THE LOCAL COLOUR GLOB IS GONE (C1b). This bundle registered its own src/colors/*.js over the
|
||||
// shared set; all three modules (doxa-region, affinity-block, resource) now live in library/colors/
|
||||
// where _registry.js discovers them for every bundle, and src/colors/ holds no .js at all. The glob
|
||||
// matched nothing, so leaving it would be dead code that reads as a deliberate override.
|
||||
|
||||
// ─── Mapbox RTL text plugin — load ONCE before any map instance ──────────────
|
||||
if (typeof window !== 'undefined' && window.mapboxgl?.setRTLTextPlugin) {
|
||||
|
|
|
|||
|
|
@ -21,28 +21,16 @@ import { defineCustomElement } from 'vue'
|
|||
import { createPinia } from 'pinia'
|
||||
import ProfileLoader from '@map/ProfileLoader.vue'
|
||||
import { createAppI18n } from '@map/i18n/index.js'
|
||||
import { registerStrategies } from '@map/colors/_registry.js'
|
||||
|
||||
// ─── Bundle-private profile registry ─────────────────────────────────────────
|
||||
// import.meta.glob is evaluated by Vite at build time relative to THIS file —
|
||||
// so it captures only this bundle's profiles.
|
||||
const profileModules = import.meta.glob('./*.vue')
|
||||
|
||||
// ─── Bundle-private color strategies ─────────────────────────────────────────
|
||||
// Same seam as profileModules, for colors. Any `<name>.js` a contributor drops in
|
||||
// this bundle's `src/colors/` folder is merged OVER the shared library set
|
||||
// (same mode key = override; new key = profile-private). This bundle inlines its own
|
||||
// copy of the registry (IIFE build), so registering here affects THIS bundle only.
|
||||
// This bundle ships THREE research-only strategies: affinity-block.js,
|
||||
// doxa-region.js, resource.js (shared modes like religion stay in the library).
|
||||
// ★ THIS GLOB NOW COVERS resource.js ONLY. doxa-region.js and affinity-block.js moved to
|
||||
// library/colors/ (C1), where _registry.js discovers them for every bundle, so registering them
|
||||
// here would be re-declaring what the shared set already has.
|
||||
// THE GLOB STAYS rather than being deleted: resource.js is still private pending C1b (its palette
|
||||
// has 8 values and the two dashboards ship 6, which needs its owner's answer before it moves).
|
||||
// Removing the glob now would unregister resource and colour those pins by the soft fallback --
|
||||
// the same class of silent wrong-colour bug this migration is fixing.
|
||||
registerStrategies(import.meta.glob('./src/colors/*.js', { eager: true }))
|
||||
// ★ THE LOCAL COLOUR GLOB IS GONE (C1b). This bundle registered its own src/colors/*.js over the
|
||||
// shared set; all three modules (doxa-region, affinity-block, resource) now live in library/colors/
|
||||
// where _registry.js discovers them for every bundle, and src/colors/ holds no .js at all. The glob
|
||||
// matched nothing, so leaving it would be dead code that reads as a deliberate override.
|
||||
|
||||
// ─── Mapbox RTL text plugin — load ONCE before any map instance ──────────────
|
||||
if (typeof window !== 'undefined' && window.mapboxgl?.setRTLTextPlugin) {
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
/**
|
||||
* Gospel Resources Color Strategy
|
||||
*
|
||||
* Colors pins based on available gospel resources.
|
||||
* DEFAULT: Binary coloring - Green (has ANY resource) / Black (no resources)
|
||||
* LEGEND COUNTS: Show TOTAL for each resource (can overlap)
|
||||
*/
|
||||
|
||||
export const PROPERTY_KEY = 'resourceType'
|
||||
|
||||
/**
|
||||
* Gospel Resources Colors
|
||||
* DEFAULT: Binary coloring - Green (has ANY resource) / Black (no resources)
|
||||
* LEGEND: Show TOTAL count for each resource (INCLUSIVE, can overlap)
|
||||
*/
|
||||
export const PALETTE = {
|
||||
bible: '#3498db', // Blue - Bible available
|
||||
jesusFilm: '#20c997', // Fisher Green (teal-green) - Jesus Film available
|
||||
radio: '#9b59b6', // Purple - Radio broadcast available
|
||||
gospel: '#f39c12', // Orange - Gospel recordings available
|
||||
audio: '#1abc9c', // Teal - Audio resources available
|
||||
stories: '#e74c3c', // Red - Stories available
|
||||
hasResources: '#27ae60', // Green - Has ANY gospel resource (default pin color)
|
||||
noResources: '#2c3e50' // Dark/Black - No gospel resources
|
||||
}
|
||||
|
||||
export const RESOURCE_COLORS = PALETTE
|
||||
|
||||
/** Resource priority order for pin coloring */
|
||||
export const RESOURCE_PRIORITY = ['bible', 'jesusFilm', 'radio', 'gospel', 'audio', 'stories']
|
||||
|
||||
/** Resource display names for legend */
|
||||
export const NAMES = {
|
||||
bible: 'Bible',
|
||||
jesusFilm: 'Jesus Film',
|
||||
radio: 'Radio',
|
||||
gospel: 'Gospel',
|
||||
audio: 'Audio',
|
||||
stories: 'Stories',
|
||||
hasResources: 'Has Resources',
|
||||
noResources: 'No Resources'
|
||||
}
|
||||
|
||||
export const RESOURCE_NAMES = NAMES
|
||||
|
||||
/**
|
||||
* Get CSV column name for a resource key.
|
||||
*/
|
||||
export function getCSVColumn(resourceKey) {
|
||||
const mapping = {
|
||||
bible: 'Bible',
|
||||
jesusFilm: 'Jesus',
|
||||
radio: 'Radio',
|
||||
gospel: 'Gospel',
|
||||
audio: 'Audio',
|
||||
stories: 'Stories'
|
||||
}
|
||||
return mapping[resourceKey]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color for a feature based on resource availability.
|
||||
* Binary logic: Green if has ANY resource, Black if none.
|
||||
*/
|
||||
export function getColor(properties) {
|
||||
for (const resourceKey of RESOURCE_PRIORITY) {
|
||||
const value = properties[resourceKey] || properties._raw?.[getCSVColumn(resourceKey)]
|
||||
if (value === 'Available') {
|
||||
return PALETTE.hasResources // Green
|
||||
}
|
||||
}
|
||||
return PALETTE.noResources // Black
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if feature has ANY resource (for hasResources).
|
||||
*/
|
||||
export function hasAnyResource(properties) {
|
||||
for (const resourceKey of RESOURCE_PRIORITY) {
|
||||
const value = properties[resourceKey] || properties._raw?.[getCSVColumn(resourceKey)]
|
||||
if (value === 'Available') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the highest priority resource type for a feature.
|
||||
* Returns the resource key that determines the pin color.
|
||||
*/
|
||||
export function getResourceType(properties) {
|
||||
for (const resourceKey of RESOURCE_PRIORITY) {
|
||||
const value = properties[resourceKey] || properties._raw?.[getCSVColumn(resourceKey)]
|
||||
if (value === 'Available') {
|
||||
return resourceKey
|
||||
}
|
||||
}
|
||||
return 'noResources'
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Mapbox color expression for gospel resources.
|
||||
* DEFAULT: Binary coloring - Green if has ANY resource, Black if none.
|
||||
*/
|
||||
export function applyColor() {
|
||||
return [
|
||||
'case',
|
||||
// If ANY resource is Available → Green (hasResources)
|
||||
['any',
|
||||
['==', ['get', 'bible'], 'Available'],
|
||||
['==', ['get', 'jesusFilm'], 'Available'],
|
||||
['==', ['get', 'radio'], 'Available'],
|
||||
['==', ['get', 'gospel'], 'Available'],
|
||||
['==', ['get', 'audio'], 'Available'],
|
||||
['==', ['get', 'stories'], 'Available']
|
||||
],
|
||||
PALETTE.hasResources, // Green
|
||||
// Default: No resources → Black
|
||||
PALETTE.noResources // Black
|
||||
]
|
||||
}
|
||||
|
||||
export const buildColorExpression = applyColor
|
||||
|
||||
export default {
|
||||
name: 'Gospel Resources',
|
||||
propertyKey: PROPERTY_KEY,
|
||||
palette: PALETTE,
|
||||
colors: PALETTE,
|
||||
names: NAMES,
|
||||
priority: RESOURCE_PRIORITY,
|
||||
getColor,
|
||||
applyColor,
|
||||
buildColorExpression,
|
||||
hasAnyResource,
|
||||
getResourceType,
|
||||
getCSVColumn
|
||||
}
|
||||
Loading…
Reference in a new issue