diff --git a/documentation/reference-capability-exemplars.md b/documentation/reference-capability-exemplars.md index d389b951d..5fdf202cb 100644 --- a/documentation/reference-capability-exemplars.md +++ b/documentation/reference-capability-exemplars.md @@ -13,7 +13,7 @@ > bundle `parameterized` (cap-2) no matter how light it looks, and a `meta.json` `type` > declares tiers 3/4/5. -Generated from 29 bundle(s). +Generated from 30 bundle(s). ### One canonical exemplar per tier (generated — quote these) @@ -38,6 +38,7 @@ Generated from 29 bundle(s). |---|---|---| | `all-people-groups` | `all-people-groups` | `single` | | `bible-posters` | `bible-posters` | `single` | +| `bless-india-posters` | `bless-india-posters` | `single` | | `cities-internet` | `connectivity-list` | `single` | | `cities-internet` | `connectivity-map` | `single` | | `cities-internet` | `data-tables` | `single` | diff --git a/library/i18n/locales/ar/blessIndiaPosters.json b/library/i18n/locales/ar/blessIndiaPosters.json new file mode 100644 index 000000000..9f43bc12e --- /dev/null +++ b/library/i18n/locales/ar/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "ملصقات باركوا الهند", + "rangeBadge60x96": "شارات النطاق · 60×96 (5×8 قدم)", + "count": "{count} مجموعة شعبية", + "desktopOnly": "سطح المكتب فقط حاليًا — لم يَثبُت بعد أن هذا الملصق الكبير يُطبع بأمان على الهاتف." +} diff --git a/library/i18n/locales/de/blessIndiaPosters.json b/library/i18n/locales/de/blessIndiaPosters.json new file mode 100644 index 000000000..f081f89d9 --- /dev/null +++ b/library/i18n/locales/de/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "„Segne Indien“-Poster", + "rangeBadge60x96": "Nummern-Marken · 60×96 (5×8 Fuß)", + "count": "{count} Volksgruppen", + "desktopOnly": "Vorerst nur am Desktop — es ist noch nicht erwiesen, dass dieses große Poster sicher auf einem Telefon druckt." +} diff --git a/library/i18n/locales/en/blessIndiaPosters.json b/library/i18n/locales/en/blessIndiaPosters.json new file mode 100644 index 000000000..fc99767fa --- /dev/null +++ b/library/i18n/locales/en/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "Bless India Posters", + "rangeBadge60x96": "Range badges · 60×96 (5×8 ft)", + "count": "{count} people groups", + "desktopOnly": "Desktop only for now — this large poster isn’t yet proven to print safely on a phone." +} diff --git a/library/i18n/locales/es/blessIndiaPosters.json b/library/i18n/locales/es/blessIndiaPosters.json new file mode 100644 index 000000000..ff4aab3ed --- /dev/null +++ b/library/i18n/locales/es/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "Pósteres «Bendice a la India»", + "rangeBadge60x96": "Insignias numeradas · 60×96 (5×8 pies)", + "count": "{count} grupos de población", + "desktopOnly": "Solo escritorio por ahora: aún no se ha comprobado que este póster grande se imprima de forma segura en un teléfono." +} diff --git a/library/i18n/locales/fr/blessIndiaPosters.json b/library/i18n/locales/fr/blessIndiaPosters.json new file mode 100644 index 000000000..c81bdedce --- /dev/null +++ b/library/i18n/locales/fr/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "Affiches « Bénis l’Inde »", + "rangeBadge60x96": "Badges de numéros · 60×96 (5×8 pi)", + "count": "{count} groupes de population", + "desktopOnly": "Ordinateur uniquement pour l’instant — il n’est pas encore prouvé que cette grande affiche s’imprime correctement sur un téléphone." +} diff --git a/library/i18n/locales/hi/blessIndiaPosters.json b/library/i18n/locales/hi/blessIndiaPosters.json new file mode 100644 index 000000000..0255c1fcf --- /dev/null +++ b/library/i18n/locales/hi/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "भारत को आशीष दें — पोस्टर", + "rangeBadge60x96": "क्रमांकित बैज · 60×96 (5×8 फुट)", + "count": "{count} लोग समूह", + "desktopOnly": "अभी केवल डेस्कटॉप — यह बड़ा पोस्टर अभी फ़ोन पर सुरक्षित रूप से प्रिंट होना सिद्ध नहीं हुआ है।" +} diff --git a/library/i18n/locales/it/blessIndiaPosters.json b/library/i18n/locales/it/blessIndiaPosters.json new file mode 100644 index 000000000..379b8dbf1 --- /dev/null +++ b/library/i18n/locales/it/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "Poster «Benedici l’India»", + "rangeBadge60x96": "Badge numerati · 60×96 (5×8 ft)", + "count": "{count} gruppi di popolazione", + "desktopOnly": "Solo desktop per ora — non è ancora dimostrato che questo grande poster si stampi in sicurezza su un telefono." +} diff --git a/library/i18n/locales/pt/blessIndiaPosters.json b/library/i18n/locales/pt/blessIndiaPosters.json new file mode 100644 index 000000000..d351a1c28 --- /dev/null +++ b/library/i18n/locales/pt/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "Pôsteres «Abençoe a Índia»", + "rangeBadge60x96": "Emblemas numerados · 60×96 (5×8 pés)", + "count": "{count} grupos populacionais", + "desktopOnly": "Apenas no computador por enquanto — ainda não se comprovou que este pôster grande imprime com segurança num telemóvel." +} diff --git a/library/i18n/locales/ro/blessIndiaPosters.json b/library/i18n/locales/ro/blessIndiaPosters.json new file mode 100644 index 000000000..10aa0220e --- /dev/null +++ b/library/i18n/locales/ro/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "Postere „Binecuvântează India”", + "rangeBadge60x96": "Insigne numerotate · 60×96 (5×8 ft)", + "count": "{count} grupuri de popoare", + "desktopOnly": "Doar pe desktop deocamdată — nu s-a dovedit încă că acest poster mare se tipărește în siguranță pe un telefon." +} diff --git a/library/i18n/locales/ru/blessIndiaPosters.json b/library/i18n/locales/ru/blessIndiaPosters.json new file mode 100644 index 000000000..2bd836c01 --- /dev/null +++ b/library/i18n/locales/ru/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "Плакаты «Благослови Индию»", + "rangeBadge60x96": "Номерные значки · 60×96 (5×8 футов)", + "count": "{count} народностей", + "desktopOnly": "Пока только на компьютере — ещё не доказано, что этот большой плакат безопасно печатается на телефоне." +} diff --git a/library/i18n/locales/zh/blessIndiaPosters.json b/library/i18n/locales/zh/blessIndiaPosters.json new file mode 100644 index 000000000..dbf09cefd --- /dev/null +++ b/library/i18n/locales/zh/blessIndiaPosters.json @@ -0,0 +1,6 @@ +{ + "title": "祝福印度海报", + "rangeBadge60x96": "编号标记 · 60×96(5×8 英尺)", + "count": "{count} 个族群", + "desktopOnly": "目前仅限桌面——尚未证明这张大海报能在手机上安全打印。" +} diff --git a/plugin-designs/bless-india-posters/README.md b/plugin-designs/bless-india-posters/README.md new file mode 100644 index 000000000..fd743aa36 --- /dev/null +++ b/plugin-designs/bless-india-posters/README.md @@ -0,0 +1,25 @@ +# bless-india-posters — whole-India poster attempts (generative, experimental) + +A preview surface for the hardest poster we make: every one of India's ~855 people groups on one +printable sheet. Each design attempt is **generated live** from the current people-group data — nothing +is stored — and shown the way Poster Design's Sizes view shows the big formats: the sheet split into its +printable sheets with the glue strips between them. + +Every poster carries the blessing: the header **"Bless India in Jesus' name"** and, as the footer, the +Aaronic blessing (Numbers 6:24-26, public-domain World English Bible, British Edition — switchable). + +- **Public + experimental.** The attempts ship in the public build for this plugin; the whole-country + poster on Country Posters stays withheld (not shipped) until it prints legibly. +- **Phone-safe by default.** A phone sees the preview, but Print is blocked with a "desktop only" message + until a design is proven to generate and print on a phone without crashing. +- **Prints as a document.** A flat image can't carry people-group photos (the photo hosts send no CORS), + and a 60×96 sheet rasterised onto letter would be shrunk — so Print opens the poster as its own document + at its true size. + +## Files +- `index.js` — registers `` and the `blessIndia` poster type (for the catalogue). +- `bless-india-posters.vue` — the view: generate live → the W via the shared library `PanelSheets` + print. +- `src/generate.js` — records + boundaries + format → the finished poster SVG/HTML (pure wiring). +- `src/generators/` — the plugin's own copy of the renderer (a stopgap; attempts move onto the shared + `@map` circular-layout module when it lands, and this copy is deleted). +- `src/blessIndiaPosterType.js` — the poster-type adapter. `src/boundaries.js` — the India boundary fetch. diff --git a/plugin-designs/bless-india-posters/bless-india-posters.meta.json b/plugin-designs/bless-india-posters/bless-india-posters.meta.json new file mode 100644 index 000000000..60bb517c7 --- /dev/null +++ b/plugin-designs/bless-india-posters/bless-india-posters.meta.json @@ -0,0 +1,15 @@ +{ + "label": "Bless India Posters", + "stage": "experimental", + "visibility": "team", + "posterDesign": [ + { + "family": "blessPoster", + "name": "bless-india.range-badge-60x96", + "size": "60x96", + "mobileFriendly": false, + "labelKey": "blessIndiaPosters.rangeBadge60x96" + } + ], + "_comment": "Experimental plugin: our whole-India poster attempts, generated live (no stored rasters). The attempts ship in the PUBLIC build for this plugin; the whole-country poster on Country Posters stays withheld. posterDesign registers each design in the Poster Design catalogue; names are ledgered and never renamed once shipped. mobileFriendly stays false until a design is proven to generate + print on a phone without crashing (the desktop-only rule shows meanwhile). More designs (four-sides 5x8, paired-rows 5.5x5.5) land with later attempts." +} diff --git a/plugin-designs/bless-india-posters/bless-india-posters.vue b/plugin-designs/bless-india-posters/bless-india-posters.vue new file mode 100644 index 000000000..ab722491b --- /dev/null +++ b/plugin-designs/bless-india-posters/bless-india-posters.vue @@ -0,0 +1,155 @@ + + + + + + diff --git a/plugin-designs/bless-india-posters/index.html b/plugin-designs/bless-india-posters/index.html new file mode 100644 index 000000000..5a5ae5de6 --- /dev/null +++ b/plugin-designs/bless-india-posters/index.html @@ -0,0 +1,20 @@ + + + + + + doxa-maps · India Posters staging + + + + + + + + + diff --git a/plugin-designs/bless-india-posters/index.js b/plugin-designs/bless-india-posters/index.js new file mode 100644 index 000000000..63325e122 --- /dev/null +++ b/plugin-designs/bless-india-posters/index.js @@ -0,0 +1,22 @@ +/** + * bless-india-posters / index.js — registers (public, experimental). + * + * Shows our whole-India poster attempts, generated live (no stored rasters). The attempts ship in the + * PUBLIC build for this plugin (the whole-country poster on Country Posters stays withheld; India + * tab is not shipped). Also registers the 'blessIndia' poster type so the standard poster section and the + * Poster Design catalogue can list + offer the same designs. + */ +import { defineCustomElement } from 'vue' +import BlessIndiaPosters from './bless-india-posters.vue' +import { registerPosterType } from '@map/components/poster/posterTypes.js' +import blessIndiaType from './src/blessIndiaPosterType.js' + +registerPosterType('blessIndia', blessIndiaType) + +const BlessIndiaPostersElement = defineCustomElement(BlessIndiaPosters) + +if (typeof customElements !== 'undefined' && !customElements.get('bless-india-posters')) { + customElements.define('bless-india-posters', BlessIndiaPostersElement) +} + +export default BlessIndiaPostersElement diff --git a/plugin-designs/bless-india-posters/src/blessIndiaPosterType.js b/plugin-designs/bless-india-posters/src/blessIndiaPosterType.js new file mode 100644 index 000000000..2c5f7e24d --- /dev/null +++ b/plugin-designs/bless-india-posters/src/blessIndiaPosterType.js @@ -0,0 +1,38 @@ +/** + * blessIndiaPosterType.js — the 'blessIndia' poster type (adapter) for + the + * Poster Design catalogue. The attempts are our whole-India poster designs; each generates live from + * the India people-group records (nothing stored). sheet(card, format) returns the poster HTML. The + * plugin's own page (bless-india-posters.vue) shows the W via PanelSheets and prints as a document; + * this adapter lets the standard poster section/catalogue list and offer the same designs. + */ +import { createPeopleGroupRecords } from '@map/lists/peopleGroupRecords.js' +import { ISO3_NAME } from '@map/data/iso3-name.js' +import seriesJson from '@map/scripts/posters/series.json' +import { generatePoster } from './generate.js' +import { loadBoundaries } from './boundaries.js' + +const seriesDef = (seriesJson && seriesJson.country) || {} +const GEN = { '60x96': '60x96c4b', '66x66': '66x66c4b' } +const ATTEMPTS = [{ id: 'range-badge-60x96', iso3: 'IND', size: '60x96', label: 'Bless India — range badges (60×96)' }] +const isPhone = () => typeof window !== 'undefined' && !!window.matchMedia && window.matchMedia('(max-width: 767px)').matches + +export default { + items() { return ATTEMPTS }, + title(scope, t) { return (t && t('blessIndiaPosters.title')) || 'Bless India Posters' }, + actions({ assetsBase, apiBase, lang, profileConfig, t }) { + const recordsFor = createPeopleGroupRecords({ apiBase, lang, profileConfig }) + const sheet = async (card, format) => { + const genFormat = GEN[format] || GEN['60x96'] + const records = await recordsFor({ type: 'country', values: ['IND'] }) + const b = await loadBoundaries(assetsBase) + const { html } = await generatePoster({ records, ...b, seriesDef, iso3Name: ISO3_NAME, format: genFormat }) + return html + } + return { + records: () => recordsFor({ type: 'country', values: ['IND'] }), + sheet, + unsupported: () => (isPhone() ? ((t && t('blessIndiaPosters.desktopOnly')) || 'Desktop only for now.') : null), + unit: 'UPG', itemCountKey: 'blessIndiaPosters.count', eventName: 'bless-india:show-on-map', downloadPrefix: 'bless-india', cardStocks: true, + } + }, +} diff --git a/plugin-designs/bless-india-posters/src/boundaries.js b/plugin-designs/bless-india-posters/src/boundaries.js new file mode 100644 index 000000000..41a0559e3 --- /dev/null +++ b/plugin-designs/bless-india-posters/src/boundaries.js @@ -0,0 +1,22 @@ +/** + * boundaries.js — fetch the India boundary geojson the generator draws on, from the served tree. + * Cached per base, so re-generating (a size switch, a re-render) costs one fetch. The generator only + * needs India's own ADM0 feature + its ADM1 states + place labels; we fetch the tree files and the + * generator filters India out of ADM0 itself. + */ +const cache = new Map() + +export function loadBoundaries(assetsBase) { + const base = String((typeof assetsBase === 'function' ? assetsBase() : assetsBase) || './assets').replace(/\/$/, '') + if (cache.has(base)) return cache.get(base) + const b = `${base}/boundaries` + const p = Promise.all([ + fetch(`${b}/world-adm0.geojson`).then((r) => r.json()), + fetch(`${b}/gb-IND-ADM1.geojson`).then((r) => r.json()), + fetch(`${b}/ne-places.json`).then((r) => r.json()).catch(() => ({ places: [] })), + ]).then(([adm0, adm1Ind, ne]) => ({ + adm0, adm1Ind, nePlaces: Array.isArray(ne) ? ne : (ne.places || []), + })) + cache.set(base, p) + return p +} diff --git a/plugin-designs/bless-india-posters/src/generate.js b/plugin-designs/bless-india-posters/src/generate.js new file mode 100644 index 000000000..ac85ee205 --- /dev/null +++ b/plugin-designs/bless-india-posters/src/generate.js @@ -0,0 +1,95 @@ +/** + * generate.js — pure wiring: live people-group records + India boundaries + a format → the finished + * poster SVG string, generated at call time (nothing stored). NO fetch and NO DOM here; the caller (the + * Vue view in a browser, or a node test) supplies the records and the boundary geojson, so this stays + * testable and Worker-friendly. The generator is the LOCAL STOPGAP copy under ./generators/; attempts + * move onto the shared @map circular-layout module when it lands and this copy is deleted. + */ +import { createPosterGenerator } from './generators/poster-render.js' + +const INDIA = { + id: 'country-ind', zoneKey: 'country-ind', label: 'India', color: '#d4a640', + adm0: ['IND'], selector: { type: 'country_codes', values: ['IND'] }, + provinces: ['36 states and union territories'], +} + +// The blessing on every poster. Header = the banner; footer = the Aaronic blessing (Numbers 6:24-26). +// WEB British Edition ("The LORD …"), public domain, switchable: pass a different `footer` to change +// the version (e.g. NIV, which needs Biblica's notice). Header mirrors the Wall of People Groups' spirit. +export const BLESSING = { + header: "Bless India in Jesus' name", + footer: { + text: 'The LORD bless you, and keep you. The LORD make his face to shine on you, and be gracious to you. The LORD lift up his face toward you, and give you peace.', + ref: 'Numbers 6:24-26', + }, +} + +/** A people-group record (PRINT_FIELDS: latitude/longitude/name/…) → the generator's pin shape. */ +export function recordsToPins(records) { + return (records || []) + .map((r) => ({ + name: r.name, + lng: r.longitude != null ? +r.longitude : r.lng != null ? +r.lng : null, + lat: r.latitude != null ? +r.latitude : r.lat != null ? +r.lat : null, + country_code: r.country_code || 'IND', + image_url: r.image_url, + population: r.population != null ? +r.population : (r.p != null ? +r.p : undefined), + wagf_region: r.wagf_region, + slug: r.slug, + })) + .filter((p) => p.name && Number.isFinite(p.lng) && Number.isFinite(p.lat)) +} + +// Lift the finished out of the poster HTML WITH its stylesheet inlined. The poster's fills use +// CSS vars (--paper/--sea/--frameline) defined in the HTML's +${esc(title)} — UPG poster +
${svg}
`; + if (c4fork) return { html, title, octiOK, crossings, diagFrac, indiaSheet: c4fork.stats }; + if (classic4) return { html, title, octiOK, crossings, diagFrac, indiaSheet: classic4.stats }; + return sides ? { html, title, octiOK, crossings, diagFrac, sideLanes: sides.stats } : { html, title, octiOK, crossings, diagFrac }; +} + +return { renderPoster, CITIES, COUNTRIES, FILE_SUFFIX, FMT_KEY, FMT, MAP_ONLY, FORMATS }; +} diff --git a/public/README.md b/public/README.md index 9b267ce79..7bf5a208f 100644 --- a/public/README.md +++ b/public/README.md @@ -2,7 +2,7 @@ This folder is GENERATED by `bun run build`; do not edit it by hand. It holds exactly one thing: -- **`dx-maps/`** — the output folder: 29 plugin bundles and 45 pages, self-contained. +- **`dx-maps/`** — the output folder: 30 plugin bundles and 46 pages, self-contained. Copy this one folder to any web host (or open it from disk) and it works. - `dx-maps/index.html` — the front page: the Plugin Studio, every plugin in one place. - `dx-maps//.js` — a plugin's bundle (a custom element; load it with a ` + bless-india-posters · bless-india-posters + + + + + +
+
loading…
+ + + + + + + + diff --git a/public/dx-maps/doxa-maps-spa/manifest.json b/public/dx-maps/doxa-maps-spa/manifest.json index 749463a99..4aac40163 100644 --- a/public/dx-maps/doxa-maps-spa/manifest.json +++ b/public/dx-maps/doxa-maps-spa/manifest.json @@ -2,8 +2,8 @@ "schema": "doxa-maps-manifest@1", "generatedFrom": "plugin-designs/*/*.vue", "embedBase": ".", - "bundleCount": 29, - "profileCount": 45, + "bundleCount": 30, + "profileCount": 46, "runtime": { "apiBaseUrl": "https://pray.doxa.life" }, @@ -138,6 +138,43 @@ } ] }, + { + "bundle": "bless-india-posters", + "scriptUrl": "./bless-india-posters/bless-india-posters.js", + "output": "dx-maps/bless-india-posters/bless-india-posters.js", + "integrity": "sha384-VN7MCE+2tdfGCqB0daTJpdptI3IMCzGdrqIM4yoj2E5ufhWJyaBNBJMe8BuxGnHi", + "elements": [ + "bless-india-posters" + ], + "stage": "experimental", + "profiles": [ + { + "profile": "bless-india-posters", + "stage": "experimental", + "label": "Bless India Posters", + "posterDesign": [ + { + "family": "blessPoster", + "name": "bless-india.range-badge-60x96", + "size": "60x96", + "mobileFriendly": false, + "labelKey": "blessIndiaPosters.rangeBadge60x96" + } + ], + "file": "bless-india-posters.vue", + "description": "A preview surface for the whole-India poster problem — fitting every one of India's people groups onto a single printable sheet. Each design attempt is generated live from the current data (nothing stored) and shown as its printable sheets with the glue strips, headed \"Bless India in Jesus' name\" with the Numbers 6:24-26 blessing. Experimental; a phone sees the preview but Print is blocked until a design is proven safe on a phone.", + "element": "bless-india-posters", + "type": "single", + "isMap": false, + "iframeUrl": "./bless-india-posters/bless-india-posters/index.html", + "scriptUrl": "./bless-india-posters/bless-india-posters.js", + "embed": { + "iframe": "", + "script": "\n\n\n" + } + } + ] + }, { "bundle": "cities-internet", "scriptUrl": "./cities-internet/cities-internet.js", diff --git a/public/dx-maps/manifest.json b/public/dx-maps/manifest.json index 749463a99..4aac40163 100644 --- a/public/dx-maps/manifest.json +++ b/public/dx-maps/manifest.json @@ -2,8 +2,8 @@ "schema": "doxa-maps-manifest@1", "generatedFrom": "plugin-designs/*/*.vue", "embedBase": ".", - "bundleCount": 29, - "profileCount": 45, + "bundleCount": 30, + "profileCount": 46, "runtime": { "apiBaseUrl": "https://pray.doxa.life" }, @@ -138,6 +138,43 @@ } ] }, + { + "bundle": "bless-india-posters", + "scriptUrl": "./bless-india-posters/bless-india-posters.js", + "output": "dx-maps/bless-india-posters/bless-india-posters.js", + "integrity": "sha384-VN7MCE+2tdfGCqB0daTJpdptI3IMCzGdrqIM4yoj2E5ufhWJyaBNBJMe8BuxGnHi", + "elements": [ + "bless-india-posters" + ], + "stage": "experimental", + "profiles": [ + { + "profile": "bless-india-posters", + "stage": "experimental", + "label": "Bless India Posters", + "posterDesign": [ + { + "family": "blessPoster", + "name": "bless-india.range-badge-60x96", + "size": "60x96", + "mobileFriendly": false, + "labelKey": "blessIndiaPosters.rangeBadge60x96" + } + ], + "file": "bless-india-posters.vue", + "description": "A preview surface for the whole-India poster problem — fitting every one of India's people groups onto a single printable sheet. Each design attempt is generated live from the current data (nothing stored) and shown as its printable sheets with the glue strips, headed \"Bless India in Jesus' name\" with the Numbers 6:24-26 blessing. Experimental; a phone sees the preview but Print is blocked until a design is proven safe on a phone.", + "element": "bless-india-posters", + "type": "single", + "isMap": false, + "iframeUrl": "./bless-india-posters/bless-india-posters/index.html", + "scriptUrl": "./bless-india-posters/bless-india-posters.js", + "embed": { + "iframe": "", + "script": "\n\n\n" + } + } + ] + }, { "bundle": "cities-internet", "scriptUrl": "./cities-internet/cities-internet.js",