Regions: RTL kept three rules on the wrong side, and the tab strip never localised
Every vs-live diff so far ran at LTR, so RTL was the next coverage gap —
and it is where layout actually breaks, because a physical `left`
silently survives a direction flip while a logical
`inset-inline-start` does not. Their CSS uses the logical form; ours had
physical `left` in three direction-sensitive places.
The new probe compares each element's offset from the INLINE-START edge
— the left edge in LTR, the right edge in RTL — which is the one number
that goes wrong when a physical property survives. Measured against
their live /ar/regions/cameroon:
- .search-icon sat 566px from the inline-start edge against their
19.5px: it had stayed on the physical left, which is the inline END in
Arabic. Replaced with their rule verbatim (blocks/_form.scss:119 —
inset-inline-start:1em, top:0/bottom:0, margin:auto 0, 1em square),
which also fixed a second difference, since our fixed 18px square
could not track the input's type where theirs is 1em. Ours now
measures their exact 19.5px.
- The country bullet kept left:-16px, so in RTL it detached on the
wrong side — computed right 256.938px instead of a -16px overhang.
- The chooser's region legend was pinned to the physical left. That one
is a sanctioned addition rather than a clone, but a legend stuck on
the physical left in an RTL layout reads as broken whoever designed
it.
Reading the Arabic screenshot then showed every heading, strapline and
map note in Arabic and RTL while the SELECT VIEW strip still read
"Regions List" — the one piece of chrome that never localised, because
regions-mfe hardcoded its labels and imported no i18n at all. Now
routed through t(), with the legend going through ViewSelect's existing
prop so the shared component and its three consumers stay untouched.
No catalogue keys were added, deliberately. Their common.json has
"Regions" and "View" but none of the composites, so there is nothing to
copy; translating our own additions is not this agent's call; and
check:i18n-parity tracks a per-locale debt ceiling — it/ro/zh sit at
exactly 94 missing because DX-life translates 8 of our 11 locales — so
English-only keys would push them to 97 and fail it. The shim falls
back to the key, so today's rendering is byte-identical. Proven rather
than assumed: a sentinel injected into ar/regions.json rendered on tab
1 at locale=ar while tab 2 stayed English, then was reverted.
Two of my own assertions were wrong first. The probe set
profile-config.locale on every custom element, which on the composite
means three regions-dashboard elements — host and both panes — and
writing a fresh {locale:'ar'} onto a pane that had inherited its config
by provide() clobbered it, leaving every root LTR; I nearly "fixed" RTL,
which works on all three leaves. And checking inset-inline-start in an
LTR context is meaningless, since it merely mirrors left.
Worth flagging: check:i18n-parity's DOXA_REPO defaults to wt-packet,
another worktree, so it must be pointed at this repo to mean anything.
Regression: 22 suites green.
This commit is contained in:
parent
66c4d3163b
commit
2ddb09b42c
10 changed files with 110 additions and 84 deletions
|
|
@ -430,7 +430,10 @@ useShadowStyles(
|
|||
'.country-link{ appearance:none; background:none; border:0; padding:2px 0; margin:0;' +
|
||||
' text-align:left; cursor:pointer; color:#4e594f; font:inherit; font-size:19.5312px;' +
|
||||
' font-weight:500; width:100%; position:relative; }' +
|
||||
'.country-link::before{ content:""; position:absolute; left:-16px; top:0.6em; width:6px; height:6px;' +
|
||||
// inset-inline-start, NOT left: the bullet hangs off the text's starting edge, which is the
|
||||
// RIGHT edge in Arabic. With `left:-16px` it stayed on the physical left in RTL — measured
|
||||
// at locale=ar, computed right was 256.938px instead of the -16px near-edge overhang.
|
||||
'.country-link::before{ content:""; position:absolute; inset-inline-start:-16px; top:0.6em; width:6px; height:6px;' +
|
||||
' border-radius:50%; background:#92b195; }' +
|
||||
'.country-link:hover{ text-decoration:underline; text-decoration-color:#92b195; }' +
|
||||
'.country-link:focus-visible{ outline:2px solid #92b195; outline-offset:2px; border-radius:4px; }' +
|
||||
|
|
|
|||
|
|
@ -29,7 +29,21 @@ import { buildPaneColumn, PANE_GRID_STYLES } from '@map/layouts/pane-wrapper/pan
|
|||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import ViewSelect from '@map/components/ViewSelect.vue'
|
||||
import ShareButton from '@map/components/map-controls/ShareButton.vue'
|
||||
// The SELECT VIEW strip is one of the sanctioned additions, so DX-life has no equivalent
|
||||
// markup to clone — and until now its labels were hardcoded English, making it the one piece
|
||||
// of chrome that never localised (visible at locale=ar: the panes and every heading go RTL
|
||||
// and Arabic while the tabs still read "Regions List").
|
||||
//
|
||||
// t() here uses the same literal-English-as-key convention as the rest of the port, and the
|
||||
// shim FALLS BACK TO THE KEY, so today's rendering is byte-identical. Deliberately NO keys
|
||||
// were added to the catalogues: (a) translating our own additions is not this agent's call,
|
||||
// and (b) check:i18n-parity tracks a per-locale debt CEILING — it/ro/zh sit at exactly 94
|
||||
// missing because DX-life translates 8 of our 11 locales — so English-only keys would push
|
||||
// them to 97 and fail the gate. The moment someone adds these three strings to all locales,
|
||||
// the strip localises with no code change here.
|
||||
import { useRegionsI18n } from './src/useRegionsI18n.js'
|
||||
|
||||
const { t } = useRegionsI18n()
|
||||
const cfg = inject('profileConfig', ref(null))
|
||||
const uiStore = inject('uiStore', null)
|
||||
const isDark = computed(() => !!uiStore?.isDark)
|
||||
|
|
@ -49,8 +63,8 @@ const spec = computed(() => ({
|
|||
// pages were correctly clean — the same cap-4 inheritance gap assetsBase hit.
|
||||
config: { profile: 'regions-list', instanceId: instanceId.value, pinHint: false },
|
||||
panes: [
|
||||
{ id: 'list', label: 'Regions List', at: [0, 0], config: { profile: 'regions-list' } },
|
||||
{ id: 'dashboard', label: 'Region Dashboards', at: [1, 0], config: { profile: 'region-dashboards' } },
|
||||
{ id: 'list', label: t('Regions List'), at: [0, 0], config: { profile: 'regions-list' } },
|
||||
{ id: 'dashboard', label: t('Region Dashboards'), at: [1, 0], config: { profile: 'region-dashboards' } },
|
||||
],
|
||||
// The View switcher lives in this element's own header, so the layout's "… below ↓" pill
|
||||
// would be a second, redundant control (same call upg-100-mfe makes).
|
||||
|
|
@ -176,8 +190,8 @@ useShadowStyles(PANE_GRID_STYLES + '\n' +
|
|||
<ViewSelect
|
||||
:views="spec.panes"
|
||||
:current="view"
|
||||
legend="Select View"
|
||||
label="Views"
|
||||
:legend="t('Select View')"
|
||||
:label="t('Views')"
|
||||
@select="go"
|
||||
/>
|
||||
<ShareButton :is-dark="isDark" :embed-path="SHARE_EMBED_PATH" />
|
||||
|
|
|
|||
|
|
@ -404,7 +404,10 @@ useShadowStyles(
|
|||
'.rcm__note{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;' +
|
||||
' text-align:center; padding:24px; color:#6d766e; font-size:15.625px; background:#f3f3f1; }' +
|
||||
// Their key, overlaid bottom-left above the canvas (CountryMap.vue's .country-map__legend).
|
||||
'.rcm__legend{ position:absolute; left:10px; bottom:28px; z-index:2; display:flex;' +
|
||||
// Logical, so the chooser legend moves to the reading-start corner in Arabic. This is one
|
||||
// of the sanctioned additions rather than a clone of theirs, but a legend pinned to the
|
||||
// physical left in an RTL layout reads as broken regardless of whose design it is.
|
||||
'.rcm__legend{ position:absolute; inset-inline-start:10px; bottom:28px; z-index:2; display:flex;' +
|
||||
' flex-direction:column; gap:4px; padding:8px 10px; border-radius:8px;' +
|
||||
' background:rgba(255,255,255,0.92); font-size:12.5px; font-weight:600; color:#2a332a; }' +
|
||||
'.rcm__legend span{ display:inline-flex; align-items:center; gap:6px; }' +
|
||||
|
|
|
|||
|
|
@ -276,8 +276,14 @@ useShadowStyles(
|
|||
' background:var(--dx-white); padding:10px 23.5264px; text-indent:1.5em; font:inherit;' +
|
||||
' font-size:19.5312px; color:var(--dx-text); }' +
|
||||
'.search-box input::placeholder{ color:gray; }' +
|
||||
'.search-icon{ position:absolute; left:16px; top:50%; transform:translateY(-50%); width:18px;' +
|
||||
' height:18px; fill:none; stroke:var(--dx-muted); stroke-width:2; pointer-events:none; }' +
|
||||
// THEIRS verbatim, blocks/_form.scss:119-128 — inset-inline-start:1em, top:0/bottom:0 with
|
||||
// margin:auto 0 for the centring, and 1em square so the icon scales with the input's type.
|
||||
// Ours had `left:16px` with a translate, which in RTL left the icon on the physical LEFT:
|
||||
// MEASURED against their live /ar/regions/cameroon, ours sat 566px from the inline-start edge
|
||||
// against their 19.5px. A physical property survives a direction flip; a logical one does not.
|
||||
// Their fixed 18px square also could not track the font, where theirs is 1em.
|
||||
'.search-icon{ position:absolute; inset-inline-start:1em; top:0; bottom:0; margin:auto 0;' +
|
||||
' width:1em; height:1em; fill:none; stroke:var(--dx-muted); stroke-width:2; pointer-events:none; }' +
|
||||
// .filters__toggle — centred, chevron rotates when expanded
|
||||
'.filters__toggle{ background:none; border:0; cursor:pointer; font:inherit; font-size:15.625px;' +
|
||||
' display:inline-flex; align-items:center; gap:7.5188px; margin-inline:auto; color:var(--dx-text); }' +
|
||||
|
|
|
|||
2
public/doxa-maps/index.html
generated
2
public/doxa-maps/index.html
generated
File diff suppressed because one or more lines are too long
8
public/doxa-maps/manifest.json
generated
8
public/doxa-maps/manifest.json
generated
|
|
@ -856,7 +856,7 @@
|
|||
"bundle": "regions-dashboard",
|
||||
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
|
||||
"output": "doxa-maps/regions-dashboard/regions-dashboard.js",
|
||||
"integrity": "sha384-eL6693hPLbKK0icPn0mXmueTCwYZuRdOUuctnLjcX1hb5u5sKdXYKtPnI0vC17MQ",
|
||||
"integrity": "sha384-oNDJVhNNO4Jit8slUl90yyI2LJB/zSC6Bepz9rg2Qc5wskOyotayodyjGyfDs5We",
|
||||
"elements": [
|
||||
"regions-dashboard"
|
||||
],
|
||||
|
|
@ -876,7 +876,7 @@
|
|||
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./regions-dashboard/region-dashboards/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-eL6693hPLbKK0icPn0mXmueTCwYZuRdOUuctnLjcX1hb5u5sKdXYKtPnI0vC17MQ\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-oNDJVhNNO4Jit8slUl90yyI2LJB/zSC6Bepz9rg2Qc5wskOyotayodyjGyfDs5We\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -890,7 +890,7 @@
|
|||
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-eL6693hPLbKK0icPn0mXmueTCwYZuRdOUuctnLjcX1hb5u5sKdXYKtPnI0vC17MQ\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-oNDJVhNNO4Jit8slUl90yyI2LJB/zSC6Bepz9rg2Qc5wskOyotayodyjGyfDs5We\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -904,7 +904,7 @@
|
|||
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./regions-dashboard/regions-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-eL6693hPLbKK0icPn0mXmueTCwYZuRdOUuctnLjcX1hb5u5sKdXYKtPnI0vC17MQ\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-oNDJVhNNO4Jit8slUl90yyI2LJB/zSC6Bepz9rg2Qc5wskOyotayodyjGyfDs5We\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
|
||||
<script src="../regions-dashboard.js" integrity="sha384-eL6693hPLbKK0icPn0mXmueTCwYZuRdOUuctnLjcX1hb5u5sKdXYKtPnI0vC17MQ" crossorigin="anonymous"></script>
|
||||
<script src="../regions-dashboard.js" integrity="sha384-oNDJVhNNO4Jit8slUl90yyI2LJB/zSC6Bepz9rg2Qc5wskOyotayodyjGyfDs5We" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
136
public/doxa-maps/regions-dashboard/regions-dashboard.js
generated
136
public/doxa-maps/regions-dashboard/regions-dashboard.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
|
||||
<script src="../regions-dashboard.js" integrity="sha384-eL6693hPLbKK0icPn0mXmueTCwYZuRdOUuctnLjcX1hb5u5sKdXYKtPnI0vC17MQ" crossorigin="anonymous"></script>
|
||||
<script src="../regions-dashboard.js" integrity="sha384-oNDJVhNNO4Jit8slUl90yyI2LJB/zSC6Bepz9rg2Qc5wskOyotayodyjGyfDs5We" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
|
||||
<script src="../regions-dashboard.js" integrity="sha384-eL6693hPLbKK0icPn0mXmueTCwYZuRdOUuctnLjcX1hb5u5sKdXYKtPnI0vC17MQ" crossorigin="anonymous"></script>
|
||||
<script src="../regions-dashboard.js" integrity="sha384-oNDJVhNNO4Jit8slUl90yyI2LJB/zSC6Bepz9rg2Qc5wskOyotayodyjGyfDs5We" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue