Files
edentext/scripts/showcase/book.ts
T
Steffen Becker 99f10c9399 docs: each showcase shot opens the tab its feature lives in
A shot names a ribbon tab and, optionally, where the caret goes: the tables
one lands in a cell, so the contextual Table Layout tab is up. The floating
table toolbar is hidden while shooting — it covered the table the ribbon is
already showing. `data-tab` on the tab buttons is what the script clicks.
2026-09-06 19:07:24 +02:00

86 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// A book: Alice's Adventures in Wonderland (Lewis Carroll, 1865, public domain), A5 with
// mirrored margins, every chapter opening on a right-hand page, running heads that
// differ between left and right pages, and a contents page. Text from alice.txt.
import { builtinStyleSheet } from '../../src/lib/styles/styleSheet';
import { EMPTY_HF_SET, type HfSet } from '../../src/lib/storage/headerFooter';
import { T, P, BR, INDEX, HF, PAGE_NUMBER, ITALIC, type N, type Showcase } from './lib';
// `_like this_` is the plain-text edition's italic.
function runs(text: string): N[] {
return text.split('_').map((part, i) => part && T(part, ...(i % 2 ? [ITALIC] : []))).filter(Boolean) as N[];
}
function body(raw: string): N[] {
const out: N[] = [];
let first = true; // the paragraph after a heading takes no first-line indent
for (const block of raw.split(/\n\s*\n/)) {
const chapter = /^CHAPTER ([IVX]+)\.\n(.+)$/.exec(block.trim());
if (chapter) {
out.push(P({ styleName: 'Chapter Number', sectionBreak: true }, T(`Chapter ${chapter[1]}`)));
out.push({ type: 'heading', attrs: { level: 1 }, content: [T(chapter[2].trim())] });
first = true;
} else if (/^[*\s]+$/.test(block)) {
out.push(P({ textAlign: 'center', spaceBefore: 8, spaceAfter: 8 }, T('* * *')));
} else if (block.split('\n').every((l) => /^\s/.test(l))) {
const lines = block.split('\n').map((l) => l.trim());
out.push(P({ styleName: 'Verse' }, ...lines.flatMap((l, i) => [...(i ? [BR] : []), ...runs(l)])));
} else {
const text = block.split('\n').map((l) => l.trim()).join(' ');
out.push(P(first ? null : { indentFirst: 0.6 }, ...runs(text)));
first = false;
}
}
return out;
}
export async function build(): Promise<Showcase> {
const raw = await (await fetch('/scripts/showcase/alice.txt')).text();
const styles = builtinStyleSheet();
styles.paragraph['Standard'].text = { fontFamily: 'Liberation Serif', fontSizePt: 11 };
styles.paragraph['Standard'].para = { textAlign: 'justify', lineHeight: '1.25', spaceAfter: 0 };
styles.paragraph['Heading 1'].text = { fontFamily: 'Liberation Serif', fontSizePt: 20, bold: false, italic: true };
styles.paragraph['Heading 1'].para = { textAlign: 'center', spaceBefore: 0, spaceAfter: 30 };
styles.paragraph['Chapter Number'] = { name: 'Chapter Number', parent: 'Standard', next: 'Heading 1',
para: { textAlign: 'center', spaceBefore: 84, spaceAfter: 4 },
text: { caps: 'smallCaps', letterSpacingPt: 1.5 } };
styles.paragraph['Verse'] = { name: 'Verse', parent: 'Standard', next: 'Standard',
para: { textAlign: 'left', indent: 1.5, spaceBefore: 6, spaceAfter: 6 }, text: {} };
styles.paragraph['Front Matter Heading'] = { name: 'Front Matter Heading', parent: 'Heading 1', next: 'Standard',
para: { spaceBefore: 84, spaceAfter: 24 }, text: {} };
styles.paragraph['Title'].text = { fontFamily: 'Liberation Serif', fontSizePt: 26, bold: false };
styles.paragraph['Subtitle'].text = { fontFamily: 'Liberation Serif', fontSizePt: 14, bold: false, italic: true };
const doc: N = { type: 'doc', content: [
P({ styleName: 'Title', spaceBefore: 180, spaceAfter: 24 }, T('Alice’s Adventures in Wonderland')),
P({ styleName: 'Subtitle' }, T('by Lewis Carroll')),
P({ styleName: 'Front Matter Heading', breakBefore: 'page' }, T('Contents')),
INDEX('toc', '', { maxLevel: 1 }),
...body(raw),
] };
// Right-hand pages carry the chapter, left-hand pages the book; the number sits outside.
const right = HF({ tabStops: '11r' }, { type: 'chapterField', attrs: { level: 1, text: 'Down the Rabbit-Hole' } }, T('\t'), PAGE_NUMBER);
const left = HF({ tabStops: '11r' }, PAGE_NUMBER, T('\t'), T('Alice’s Adventures in Wonderland', ITALIC));
// A chapter opens on a right-hand page with no running head, its number at the foot.
const chapterSet: HfSet = { ...EMPTY_HF_SET, header: right, headerEven: left, differentOddEven: true, startsOn: 'odd',
differentFirstPage: true, headerFirst: null, footerFirst: HF({ textAlign: 'center' }, PAGE_NUMBER) };
const front: HfSet = { ...EMPTY_HF_SET };
const sections = [front, ...Array.from({ length: 12 }, () => chapterSet)];
sections[1] = { ...chapterSet, pageNumberStart: 1 };
return {
name: 'book', doc, styles,
pageFormat: 'A5',
margins: { top: 2, bottom: 2.2, left: 2.2, right: 1.6, mirrored: true },
hf: { header: null, footer: null, sections, pageCount: 120, headerDistanceCm: 1.2, footerDistanceCm: 1.2 },
language: { language: 'en', country: 'GB' },
hyphenate: true,
props: { title: 'Alice’s Adventures in Wonderland', subject: '', author: 'Lewis Carroll', keywords: '', description: '' },
shots: [
{ file: 'book', page: 3 },
{ file: 'book-spread', page: 3, columns: 2, tab: 'layout' },
],
};
}