Class: Sakusei::PageChromeTranslator
- Inherits:
-
Object
- Object
- Sakusei::PageChromeTranslator
- Defined in:
- lib/sakusei/page_chrome_translator.rb
Overview
Builds the live-preview’s page chrome from the style pack’s PDF configuration, matching what Puppeteer renders for the PDF as closely as possible.
Source of truth is ‘pdf_options.headerTemplate` / `footerTemplate` / `format` / `margin` inside `config.js`. We evaluate `config.js` with Node to expand JS template literals (e.g. `$wordmarkDataUri`), then translate the resulting HTML strings into running elements + @page CSS.
Strategy: Puppeteer’s headerTemplate / footerTemplate are arbitrary HTML (with images, flex layouts, multi-column structures). CSS @page margin boxes only accept a content string, not arbitrary HTML — so we use CSS Paged Media’s running-element mechanism instead:
.sakusei-running-header { position: running(sk_header); }
@page { @top-center { content: element(sk_header); } }
Placeholder rewrites (matching Puppeteer’s chrome semantics):
-
<span class=“pageNumber”></span> → <span class=“sk-pn”></span>, with .sk-pn::after { content: counter(page); }
-
<span class=“totalPages”></span> → <span class=“sk-tp”></span>, similar
-
<span class=“title”></span> → “” (Puppeteer leaves it blank by default)
-
<span class=“date”></span> → today’s date (static at build time)
-
<span class=“url”></span> → “”
-
<img src=“rel/path”> → <img src=“/__pack/rel/path”> so the browser can fetch images from the style-pack directory. Data URIs and absolute URLs pass through unchanged.
Returns { css:, html: } — caller injects css into <head>, prepends html into <body>.
Constant Summary collapse
- HEADER_RUNNING_NAME =
'sk_header'- FOOTER_RUNNING_NAME =
'sk_footer'- HEADER_CLASS =
'sakusei-running-header'- FOOTER_CLASS =
'sakusei-running-footer'- PAGE_NUMBER_CLASS =
'sk-pn'- TOTAL_PAGES_CLASS =
'sk-tp'- NODE_EXTRACT_SCRIPT =
<<~JS.freeze try { const c = require(process.argv[1]); const o = (c && c.pdf_options) || {}; const enabled = o.displayHeaderFooter !== false; process.stdout.write(JSON.stringify({ format: o.format || null, margin: o.margin || null, headerTemplate: enabled ? (o.headerTemplate || null) : null, footerTemplate: enabled ? (o.footerTemplate || null) : null })); } catch (e) { process.stderr.write(String(e && e.stack || e)); process.exit(2); } JS
Instance Method Summary collapse
- #build ⇒ Object
-
#initialize(style_pack) ⇒ PageChromeTranslator
constructor
A new instance of PageChromeTranslator.
Constructor Details
#initialize(style_pack) ⇒ PageChromeTranslator
Returns a new instance of PageChromeTranslator.
63 64 65 |
# File 'lib/sakusei/page_chrome_translator.rb', line 63 def initialize(style_pack) @style_pack = style_pack end |
Instance Method Details
#build ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/sakusei/page_chrome_translator.rb', line 67 def build return empty_result unless @style_pack opts = # Extract chrome strip backgrounds from the templates BEFORE we strip them. # Puppeteer's PDF chrome uses a `position: fixed; top: -10cm; bottom: -10cm` # div that breaks out to fill the full chrome strip. paged.js's running # elements live inside the @top-center / @bottom-center margin boxes which # are constrained to the page's content width, so the same trick covers the # whole page (wrong) instead of just the strip. We replicate the strip via # .pagedjs_page::before / ::after pseudo-elements with the extracted color. header_bg = extract_chrome_bg(opts[:header_template]) = extract_chrome_bg(opts[:footer_template]) header_html = transform_template(opts[:header_template]) = transform_template(opts[:footer_template]) html = +'' html << wrap_running(:header, header_html) if header_html && !header_html.empty? html << wrap_running(:footer, ) if && !.empty? { css: build_css(opts, header_html, , header_bg, ), html: html } end |