Compare commits

...

1 commit

Author SHA1 Message Date
Doxa Maps
2c888ffd22 Wall of People Groups: the Bless poster's verse chart is three equal, centred columns
The chart drops its left rail (the rotated "Prayer themes", "Old Testament" and "New Testament" labels):
each theme is one column of the full width, its icon and name, then its Old Testament verse, then its New
Testament verse. The columns are equal, so the chart is symmetric under the title; the verse cells size from
the wider column. Measured on the print at 3x4 and 5x8 ft, en and ar: nothing overflows.
2026-10-03 05:45:49 +00:00
2 changed files with 5 additions and 24 deletions

View file

@ -245,29 +245,16 @@ function posterParts(groups, presetId, texts, withCards = true) {
const L = texts.labels || {}
const lab = (k, en) => L[k] || en
const dir = texts.dir === 'rtl' ? 'rtl' : 'ltr'
const upright = /^(zh|ja|ko)/.test(String(texts.lang || '')) // CJK sidebar labels stand upright
const glueHere = texts.glueHere || 'glue here'
const f = (v) => v.toFixed(3) + 'in'
const W = plan.contentW, FF = FOOTER_FONTS(W, BENEDICTION_FILL[plan.presetId] ?? 1) // the footer's sizes: the same numbers footerHeight() plans with
const vPt = plan.text.versePt, rPt = cardText(plan, '').refPt
// The rotated sidebar labels of the chart are sized from their text: the longest word must fit the row's
// height (a CJK label stands upright, one em a character; other scripts ≈ 0.84 em a capital: 0.72 for the
// letter, 0.06 of letter spacing, and slack, since "TESTAMENT" at 0.72 overran its row), and the wrapped lines
// must fit the sidebar's width.
const railH = plan.tableH * 0.33 - W * 0.006, railW = W * 0.06 - W * 0.004
const railFs = (text) => {
const words = String(text).split(/\s+/), em = upright ? 1.02 : 0.84
const longest = Math.max(...words.map((w) => w.length)) * em
const byH = railH / longest, byW = railW / (Math.min(words.length, 3) * 1.2)
return Math.min(W * 0.0105, byH, byW)
}
// The chart's verse cells: one size for all six, the largest (up to W × 0.0078) at which the longest cell
// (verse at line-height 1.3, then its reference) fits its row. Characters ≈ 0.5 em with 15% slack for breaks.
const cellW = (W - W * 0.06) / 3 - 2 * W * 0.008, cellH = plan.tableH * 0.33 - 2 * W * 0.006 - W * 0.002 - W * 0.0062 * 1.3
const cellW = W / 3 - 2 * W * 0.008, cellH = plan.tableH * 0.33 - 2 * W * 0.006 - W * 0.002 - W * 0.0062 * 1.3
const cellFits = (fs) => THEMES.every((t) => [t.ot, t.nt].every((v) => Math.ceil((String(v.text).length * 0.5 * fs * 1.15) / cellW) * fs * 1.3 <= cellH))
let tvFs = W * 0.0078
while (tvFs > W * 0.005 && !cellFits(tvFs)) tvFs *= 0.97
const railLabel = (text) => `<span style="font-size:${f(railFs(text))}">${esc(text)}</span>`
const card = (c) => {
const g = groups[c.i], v = blessingFor(c.i)
// The photo at print size (photoUrl.js); a resized copy that fails falls back to the original, so a change on
@ -290,12 +277,10 @@ function posterParts(groups, presetId, texts, withCards = true) {
// English verse inside it keeps its punctuation at the end. The same holds for every scripture, name and
// reference on the sheet; the benediction and its credit are set left to right, as the English they are.
const cell = (v) => `<p class="tv" dir="auto">${esc(v.text)}</p><p class="tr" dir="auto">${esc(v.ref)}</p>`
// Three equal, centred columns, one per theme: its icon and name, its Old Testament verse, its New Testament verse.
const table = `<div class="themes" dir="${dir}">`
+ `<div class="rl rl-h">${railLabel(lab('themesLabel', 'Prayer themes'))}</div>`
+ THEMES.map((t) => `<div class="th"><div class="ic">${ICONS[t.id]}</div><div class="tn">${esc(lab('theme_' + t.id, THEME_EN[t.id]))}</div></div>`).join('')
+ `<div class="rl">${railLabel(lab('oldTestament', 'Old Testament'))}</div>`
+ THEMES.map((t) => `<div class="td">${cell(t.ot)}</div>`).join('')
+ `<div class="rl">${railLabel(lab('newTestament', 'New Testament'))}</div>`
+ THEMES.map((t) => `<div class="td">${cell(t.nt)}</div>`).join('')
+ '</div>'
const head = bd.bannerY != null
@ -337,11 +322,10 @@ body,.poster{font-family:Georgia,'Times New Roman',serif;color:${INK};-webkit-pr
.tblw{position:relative}.tblw::after{left:${f(-XR)};right:${f(-XR)};bottom:0;border-top-width:.02in}
.hd h1{margin:0;font-size:${f(plan.titleH * 0.44)};line-height:1.15;font-weight:700;letter-spacing:-.02em;color:#1c1c17}
.hd .subt{margin:${f(plan.titleH * 0.06)} 0 0;font:${f(plan.titleH * 0.085)}/1.35 ${SANS};color:#7E7562;letter-spacing:.01em}
.themes{display:grid;grid-template-columns:${f(W * 0.06)} repeat(3,1fr);grid-template-rows:34% 33% 33%;height:100%;overflow:hidden}
.themes{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:34% 33% 33%;height:100%;overflow:hidden}
.themes > div{padding:${f(W * 0.006)} ${f(PAD)};overflow:hidden;border-inline-start:.01in solid #D6CCB4}
.themes > .rl{display:flex;align-items:center;justify-content:center;color:#8a8470;padding:${f(W * 0.002)};border-inline-start:0}
.themes > .td,.themes > .rl:not(.rl-h){border-top:.01in solid #D6CCB4}
.rl span{writing-mode:vertical-rl;${upright ? 'text-orientation:upright;' : 'transform:rotate(180deg);'}font-weight:700;font-family:${SANS};line-height:1.15;letter-spacing:.06em;text-transform:uppercase;text-align:center}
.themes > div:nth-child(3n+1){border-inline-start:0}
.themes > .td{border-top:.01in solid #D6CCB4}
.themes > .th{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:${f(W * 0.003)};padding-top:${f(W * 0.003)};padding-bottom:${f(W * 0.003)}}
.th .ic{width:${f(W * 0.028)};height:${f(W * 0.028)};color:${ACCENT};flex:none}.th .ic svg{width:100%;height:100%}
.th .tn{font:700 ${f(W * 0.012)}/1.1 Georgia,serif;letter-spacing:.02em;color:${ACCENT}}

View file

@ -240,9 +240,6 @@ export default {
// scripture (cards, chart, blessing, journey) prints in the WEB's English in EVERY locale on
// purpose, until per-locale Bibles are chosen (sheet row 103).
labels: {
themesLabel: this.$t('wall.themesLabel'),
oldTestament: this.$t('wall.oldTestament'),
newTestament: this.$t('wall.newTestament'),
theme_treasure: this.$t('wall.themeTreasure'),
theme_mountain: this.$t('wall.themeMountain'),
theme_sea: this.$t('wall.themeSea'),