Every table in the product was shipping Tabulator's DEFAULT theme — #333 header, #666 rows, #444 filter boxes — against a house style that is Material LIGHT and has no dark mode. Measured identically in both served consumers before the change: row rgb(102,102,102), header rgb(51,51,51). OVERRIDDEN BY SPECIFICITY, NOT BY ORDER, and that is the load-bearing part. The vendor sheet is fetched and appended AFTER these rules, so any tie goes to the vendor. Each override is written one class deeper than the rule it replaces: four for the column header, five for the filter inputs, four for the paginator. Re-ordering the injection would have been the fragile fix — it breaks the first time injectCss is made sync. Getting that wrong is visible in stages, which is why it took three passes: at three classes the columns stayed dark while the header went light; at four the filter inputs were still #444 and the "Page Size" label was rendering white on a now-light footer, invisible. The computed-style probe reported the header and row fixed and said nothing about either — both were caught by looking at the screenshot. Dark mode is left alone. .dt.is-dark is three classes and still beats these, so callers using it keep it; this repo ships light only, but silently removing another consumer's dark mode is not this change's business. Blast radius named and checked: three consumers import DataTable — gospel-resources, cities-internet and key-cities. The first two are the ones with a served table page and both were re-checked, by computed style (row #fff, header #f3f3f1 in both) and by reading both screenshots. key-cities ships no data-tables page, so it could not be exercised live. The gospel-resources link and deep-link probes both still pass, so the restyle did not disturb the anchors the table exists for. |
||
|---|---|---|
| .. | ||
| api | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| i18n | ||
| layouts | ||
| maps | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
library/ (@map) — the shared map template
The other half of the architecture (see ../plugin-designs/README.md):
every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here.
Fix something here and every map benefits on the next build; break something here and every map
breaks — read components/WARNING.md before touching shared pieces.
| Folder | What lives there |
|---|---|
ProfileLoader.vue |
The root of every bundle: parses profile-config, loads the profile, provides the stores + config |
components/ |
Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README) |
composables/ |
Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming |
stores/ |
Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children |
api/ |
Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring |
colors/ |
Color sets maps opt into via profile-config.colorSet |
i18n/ |
The shared string catalogs (all maps speak the same languages) |
data/ |
Small shared datasets baked at build time (big served data lives in ../data/) |
constants/ |
Shared constants |
scripts/ |
Maintainer pipelines (posters, research) — not part of any bundle |
The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.