mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 13:36:48 +00:00
77dddd5e8a
Release branch for 4.0.0.
110 lines
4.4 KiB
JavaScript
110 lines
4.4 KiB
JavaScript
/**
|
|
* Turn hand-built spreads into auto-layout templates.
|
|
*
|
|
* Reads the book from a journey and writes the spreads out as data: every
|
|
* measurement divided by the page it was drawn on, so the same template lays
|
|
* out on an A4 landscape book as it does on the 210mm square it was designed
|
|
* for. Run from server/, output goes to the client.
|
|
*/
|
|
const Database = require('better-sqlite3')
|
|
const fs = require('fs')
|
|
|
|
const JOURNEY = Number(process.argv[2] || 7)
|
|
const OUT = process.argv[3] || '../client/src/components/Studio/bookTemplates.data.ts'
|
|
|
|
const db = new Database('data/travel.db', { readonly: true })
|
|
const row = db.prepare('SELECT document FROM journey_books WHERE journey_id = ?').get(JOURNEY)
|
|
db.close()
|
|
if (!row) throw new Error(`no book on journey ${JOURNEY}`)
|
|
|
|
/*
|
|
* Through the contract on the way in, so a template carries every field the
|
|
* document has — including any the schema gained since the spread was drawn.
|
|
* Without it a template written today is missing tomorrow's defaults and does
|
|
* not typecheck as a BookElement.
|
|
*/
|
|
const { normalizeBookDocument } = require('@trek/shared')
|
|
const doc = normalizeBookDocument(JSON.parse(row.document))
|
|
const PW = doc.page.pageWidth
|
|
const PH = doc.page.pageHeight
|
|
|
|
const r4 = n => Math.round(n * 10000) / 10000
|
|
|
|
/** A frame as fractions of one page's width and of the page height. */
|
|
function relFrame(f) {
|
|
return { x: r4(f.x / PW), y: r4(f.y / PH), w: r4(f.w / PW), h: r4(f.h / PH) }
|
|
}
|
|
|
|
/** Type size as a fraction of the page height, so it scales with the sheet. */
|
|
const relSize = n => r4(n / PH)
|
|
|
|
function element(e) {
|
|
// The id travels with the template and is replaced when it is applied —
|
|
// dropping it here would leave the element off the BookElement union.
|
|
const out = { ...e, frame: relFrame(e.frame) }
|
|
if (typeof out.size === 'number') out.size = relSize(out.size)
|
|
if (typeof out.radius === 'number') out.radius = r4(out.radius / PW)
|
|
if (typeof out.strokeWidth === 'number') out.strokeWidth = r4(out.strokeWidth / PW)
|
|
return out
|
|
}
|
|
|
|
const spreads = doc.spreads
|
|
.map((s, i) => ({ index: i, role: s.role, background: s.background, elements: s.elements.map(element) }))
|
|
.filter(s => s.role === 'inner')
|
|
|
|
const body = spreads.map((s, i) => ` {
|
|
id: 'ref-${i + 1}',
|
|
background: ${JSON.stringify(s.background)},
|
|
elements: ${JSON.stringify(s.elements, null, 6).replace(/\n/g, '\n ')},
|
|
},`).join('\n')
|
|
|
|
const file = `import type { BookElement } from '@trek/shared'
|
|
|
|
/**
|
|
* The spread templates, as data.
|
|
*
|
|
* ── Where these come from ────────────────────────────────────────────────
|
|
*
|
|
* Not from this file's author. They were built by hand in Studio and read back
|
|
* out of the document — which is the point: what a page should look like is a
|
|
* matter of taste, and taste is not something a layout function arrives at by
|
|
* reasoning. The editor is the design tool, and this is its output.
|
|
*
|
|
* To add one: build the spread in Studio, then run
|
|
*
|
|
* node scripts/extract-templates.cjs <journeyId>
|
|
*
|
|
* from server/ and commit what it writes here.
|
|
*
|
|
* ── Why the numbers are fractions ────────────────────────────────────────
|
|
*
|
|
* Every frame is divided by the page it was drawn on — x and w by one page's
|
|
* width, y and h by its height — and type sizes by the page height. A template
|
|
* built on a 210mm square therefore lays out on an A4 landscape book without
|
|
* being redrawn, which it would otherwise have to be for every trim size the
|
|
* picker offers.
|
|
*
|
|
* ── What gets filled in ──────────────────────────────────────────────────
|
|
*
|
|
* Elements carrying a \`binding\` take their text from the entry; empty photo
|
|
* frames take its photographs in order; the day, coordinate and country marks
|
|
* take what the entry knows about its stop. Everything else — the panels, the
|
|
* rules, the shapes that run off the page — is the design, and is kept as it
|
|
* was drawn.
|
|
*/
|
|
|
|
export interface SpreadTemplate {
|
|
id: string
|
|
background: string | null
|
|
/** Frames and sizes are fractions — see the note above. */
|
|
elements: BookElement[]
|
|
}
|
|
|
|
export const SPREAD_TEMPLATES: SpreadTemplate[] = [
|
|
${body}
|
|
]
|
|
`
|
|
|
|
fs.writeFileSync(OUT, file)
|
|
console.log(`wrote ${spreads.length} templates to ${OUT}`)
|