From 5969795d04336069217ca378fb0aaa32e23ca389 Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Tue, 11 Aug 2026 20:58:29 +0000 Subject: [PATCH] fix: a header or footer takes the document's font, not the editor's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The zone was pinned to Liberation Serif 12pt, so a run whose font the file leaves to the default — every page-number field in a fixture fixture — rendered serif inside an Arial footer. Both formats base the Header/Footer style on the default paragraph style, so the zone now takes its text half. --- src/lib/components/CLAUDE.md | 2 +- src/lib/components/HeaderFooterLayer.svelte | 4 +++- src/lib/styles/styleSheet.ts | 7 ++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/lib/components/CLAUDE.md b/src/lib/components/CLAUDE.md index fcc9513..84771f6 100644 --- a/src/lib/components/CLAUDE.md +++ b/src/lib/components/CLAUDE.md @@ -48,7 +48,7 @@ Both anchors differ: a wheel zoom holds the **point under the cursor** fixed (`p One header and one footer (`HfDoc` = a single-paragraph TipTap doc per zone, persisted to `odf-editor-header`/`-footer`), repeated on every page. Double-clicking a page margin — or the Layout-panel "Edit header/footer" buttons — opens the zone for editing; clicking back into the body (`onFocus`) or Escape ends it. The edge→zone distance (header from top, footer from bottom) is user-configurable in cm via the Layout panel (`HfDistances`, persisted to `odf-editor-hf-distances`, default `HF_DISTANCE_CM` 1.27cm, clamped 0–10 and below the body margin). - **Fields:** the bar beside the active zone inserts the `pageField.ts` atoms — page number, page count, chapter (the running head, level 1). Each is patched per page, so the same zone shows a different value on every page. -- **Rendering:** `HeaderFooterLayer.svelte` mounts inside the scaled `.paper` (like `.band-layer`), positioning per-page zone boxes in unscaled doc px. A zone's out-of-flow frame (`wrap` ≠ inline) is hidden in the box and painted per page by `.hf-bg-layer` at `z-index: -1` — hence `.paper`, not `.tiptap`, paints the page surface, so the image lands between the sheet and the body text. Inactive zones render as static HTML (`generateHTML` + `hfExtensions`); the active zone hosts the single live TipTap editor. `App.svelte`'s `activeEditor`/`activeTick` route the top toolbars to `hfEditor` while a zone is active, so all body formatting works on the header/footer with no toolbar changes. +- **Rendering:** the zone's own font is the document's **default paragraph style** (`styleCss` gives `.paper .hf-layer .hf-zone` its text half): both formats base the Header/Footer style on it, so a file whose body is Arial 10pt has an Arial footer, not the editor's serif. `HeaderFooterLayer.svelte` mounts inside the scaled `.paper` (like `.band-layer`), positioning per-page zone boxes in unscaled doc px. A zone's out-of-flow frame (`wrap` ≠ inline) is hidden in the box and painted per page by `.hf-bg-layer` at `z-index: -1` — hence `.paper`, not `.tiptap`, paints the page surface, so the image lands between the sheet and the body text. Inactive zones render as static HTML (`generateHTML` + `hfExtensions`); the active zone hosts the single live TipTap editor. `App.svelte`'s `activeEditor`/`activeTick` route the top toolbars to `hfEditor` while a zone is active, so all body formatting works on the header/footer with no toolbar changes. ## Debug tooling (dev only) diff --git a/src/lib/components/HeaderFooterLayer.svelte b/src/lib/components/HeaderFooterLayer.svelte index 9f4b96b..2cb693e 100644 --- a/src/lib/components/HeaderFooterLayer.svelte +++ b/src/lib/components/HeaderFooterLayer.svelte @@ -526,7 +526,9 @@ min-height: 0; width: 100%; background: none !important; - font-size: 12pt; + /* The zone's own size, which follows the document's default style — not the 12pt + `.paper .tiptap` puts on the body. */ + font-size: inherit; line-height: 1.15; outline: none; /* Keep the editable root at its content height (min-height:0 would otherwise let diff --git a/src/lib/styles/styleSheet.ts b/src/lib/styles/styleSheet.ts index be34234..c3b53b7 100644 --- a/src/lib/styles/styleSheet.ts +++ b/src/lib/styles/styleSheet.ts @@ -291,7 +291,12 @@ export function styleCss(sheet: StyleSheet): string { const text = textDeclarations(resolveStyle(sheet, style.name).text); if (!text.length) continue; const items = [`.paper .tiptap li:has(> ${attr})`]; - if (style.name === DEFAULT_STYLE) items.push('.paper .tiptap li:has(> p:not([data-style]))'); + if (style.name === DEFAULT_STYLE) { + items.push('.paper .tiptap li:has(> p:not([data-style]))'); + // A header/footer zone is a paragraph of the file too, and both formats base its + // style on the default one — without this it renders in the editor's own font. + items.push('.paper .hf-layer .hf-zone'); + } rules.push(`${items.join(',\n')} {\n ${text.join(';\n ')};\n}`); } // Table styles last: their cell selectors must outrank the paragraph rules above.