Commit 29e4ace
* feat(preview): add makeSelfContainedHtml inliner for printable export (issue #315)
Phase 1 of bd-vhdknrvl. Adds a pure, DI-based transform that turns the
WASM HTML-pipeline output (standalone document, but with /.quarto/…
<link>/<script> refs and relative <img> srcs) into a single
self-contained document suitable for opening as a bare top-level tab:
- CSS <link> → inline <style> (with url() font/image refs → data: URIs)
- <script src> → executing inline <script> (reveal.js must run)
- <img src> (relative + /.quarto) → base64 data: URIs
VFS access is injected (SelfContainedReaders) so it is decoupled from the
WASM singleton; production binding is deferred to the Phase 3 glue. Adds
web-font MIME types to the shared vfsPaths.guessMimeType.
Tested via 9 jsdom cases; full preview-renderer suite stays green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(wasm): add render_printable export for printable document export (issue #315)
Phase 2 of bd-vhdknrvl. Adds a path-aware WASM render that produces the
standalone printable form of an in-scope preview document:
- coerce_format_for_print: inverse of map_format_for_preview
(q2-preview→html, q2-slides→revealjs, q2-debug/q2-raw→html, else
passthrough) so the HTML pipeline (and reveal deck assembler) runs.
- render_single_doc_to_response gains a format_override param (existing
4 callers pass None); render_printable(path) reads the VFS file,
coerces the detected format, and renders through the HTML branch with
the real path so relative image srcs resolve against the doc dir.
- renderPrintable wrapper + type decls in preview-runtime.
The output still links /.quarto/ artifacts; the JS makeSelfContainedHtml
inliner (Phase 1) embeds them before the doc opens in a top-level tab.
Load-bearing render contract pinned natively in a new quarto-core
integration test (the WASM crate is cdylib-only): a q2-preview-frontmatter
doc renders to full HTML with its relative image src preserved, and a
revealjs doc renders to a standalone deck. WASM rebuilt and verified.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(wasm): sync Cargo.lock (quarto-util edge) after wasm build
Lockfile catch-up materialized by the WASM build; unrelated to the
render_printable change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(hub-client): "Open printable version" button for preview (issue #315)
Phases 3-4 of bd-vhdknrvl. Wires the printable-export end to end and
exposes it in the preview UI:
- forceRevealPrintMode (preview-renderer): inject view:"print" into a
deck's own Reveal.initialize config, so reveal enters its paginated
PDF layout when opened from a blob: URL (whose query string is not
reliably exposed via location.search).
- printableDocument service (hub-client): renderPrintable →
makeSelfContainedHtml (readers bound to the WASM VFS) →
forceRevealPrintMode for slides → Blob URL → window.open in a new
top-level tab, with pop-up-block detection and delayed revoke.
- Floating 🖨 button in the preview pane (Editor.tsx/.css), shown for
q2-preview / q2-slides / revealjs, with a dismissible error toast.
Pure logic unit-tested (revealPrintMode, isPrintableSlidesFormat,
buildPrintableHtml throw path). hub-client production build (tsc -b &&
vite build) passes. Browser E2E still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(hub-client): changelog entry for printable-version button (issue #315)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(hub-client): end-to-end WASM test for printable export (issue #315)
Drives the real render_printable WASM export against a VFS project and
runs makeSelfContainedHtml + forceRevealPrintMode over the output — the
production pipeline minus window.open. Verifies a q2-preview doc renders
to full HTML (image src preserved) and inlines to a self-contained
document (no /.quarto refs, image as data URI), and a revealjs doc
renders to a standalone deck forced into reveal print layout.
Both artifacts were also opened in Chrome and visually confirmed: the
doc renders themed/self-contained; the deck shows reveal's print-pdf
stacked-slide layout.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(preview): print-quality stylesheet for printable documents (issue #315)
Phase 5 of bd-vhdknrvl. q2's HTML template inlines only the theme's
@media print rules and omits pandoc's default print partial, so a
printable document lacked heading break-avoidance, orphan/widow control,
and figure/code/table break-inside protection.
injectPrintStylesheet appends a conservative @media print block (before
</head>) covering those basics plus @page margins and a white-background
reset. Wired into buildPrintableHtml's document branch; reveal decks skip
it (they ship their own precise per-slide print CSS). Injected
printable-only in the JS glue, so q2 render and the live preview are
untouched.
The E2E wasm test now drives the full buildPrintableHtml glue and asserts
data-q2-print present for docs / absent for decks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(plan): update issue #315 plan — phases 0-5 done, phase 6 status
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(preview): strip BOM when inlining CSS/JS so themes apply in printable export (issue #315)
Field bug: the printable document opened with no theme styling in both
Firefox and Chrome. Root cause found by reproducing the exact browser
pipeline: the compiled Bootstrap theme CSS artifact carries a leading
UTF-8 BOM (U+FEFF). A <link> load strips it from the byte stream, but
makeSelfContainedHtml injected the bytes verbatim into a <style>, where
the BOM prefixes the first selector (`:root,[data-bs-theme=light]`)
— an invalid selector in a comma list drops the WHOLE rule, so
Bootstrap's `--bs-*` variables were never defined and the theme silently
fell back to unstyled serif defaults.
Fix: strip a leading BOM from inlined CSS and JS text. Verified
end-to-end in a real browser (Chrome via CDP): stripping the BOM makes
`--bs-body-font-family` resolve and the cosmo theme render correctly.
Tests: 2 unit cases (BOM strip for CSS + JS) in makeSelfContainedHtml,
and a themed real-WASM regression in printableDocument.wasm.test.ts that
fails without the fix (asserts no inlined <style> begins with a BOM).
This was missed originally because the first E2E fixture used a minimal
themeless doc with no BOM-prefixed theme CSS to inline.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs: changelog + plan for BOM theme fix (issue #315)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(plan): record revealjs deck browser verification (issue #315)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(hub-client): move "Open printable version" button to the Files panel (issue #315)
Relocates the 🖨 print affordance out of the floating preview-pane overlay
into the Files sidebar header (next to New / Upload), per user request.
The entire printable concern (button, in-flight + error state, handler)
now lives in FileSidebar, driven by a new optional `currentFormat` prop;
Editor just threads that prop through. Removes the preview-pane button,
error toast, and associated CSS.
Adds FileSidebar integration tests: the button is shown only for
printable formats (q2-preview / q2-slides / revealjs), hidden otherwise,
and clicking opens the printable document for the current file.
Verified in an isolated browser mount: "🖨 Print" renders in the Files
header matching the New/Upload button style.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(hub-client): equalize Files-panel button sizes (issue #315)
Adding the Print button made three buttons compete for the narrow
sidebar header; flex-shrink squeezed New/Upload below their content
width so their labels wrapped to a second line, making them taller than
the single-line Print button.
Give all header buttons white-space:nowrap + flex-shrink:0 and a fixed
line-height (so an emoji's taller line box doesn't inflate one button),
and let the header flex-wrap so whole buttons drop to a second row when
the width is too small — instead of one button going two-line. All three
are now the same height (28px); verified at 250px (one row) and 190px
(Upload wraps as a whole button).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 09a0382 commit 29e4ace
22 files changed
Lines changed: 1737 additions & 6 deletions
File tree
- claude-notes/plans
- crates
- quarto-core/tests/integration
- wasm-quarto-hub-client
- src
- hub-client
- src
- components
- services
- ts-packages
- preview-renderer/src/utils
- preview-runtime/src
Lines changed: 420 additions & 0 deletions
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
Lines changed: 143 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
673 | 673 | | |
674 | 674 | | |
675 | 675 | | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
676 | 694 | | |
677 | 695 | | |
678 | 696 | | |
| |||
1000 | 1018 | | |
1001 | 1019 | | |
1002 | 1020 | | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
| 1050 | + | |
| 1051 | + | |
| 1052 | + | |
| 1053 | + | |
| 1054 | + | |
| 1055 | + | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
1003 | 1074 | | |
1004 | 1075 | | |
1005 | 1076 | | |
| |||
1032 | 1103 | | |
1033 | 1104 | | |
1034 | 1105 | | |
| 1106 | + | |
1035 | 1107 | | |
1036 | 1108 | | |
1037 | 1109 | | |
| |||
1164 | 1236 | | |
1165 | 1237 | | |
1166 | 1238 | | |
| 1239 | + | |
1167 | 1240 | | |
1168 | 1241 | | |
1169 | 1242 | | |
| |||
1257 | 1330 | | |
1258 | 1331 | | |
1259 | 1332 | | |
| 1333 | + | |
1260 | 1334 | | |
1261 | 1335 | | |
1262 | 1336 | | |
| |||
1352 | 1426 | | |
1353 | 1427 | | |
1354 | 1428 | | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
1355 | 1435 | | |
1356 | 1436 | | |
1357 | 1437 | | |
1358 | 1438 | | |
1359 | 1439 | | |
1360 | | - | |
1361 | | - | |
1362 | | - | |
| 1440 | + | |
| 1441 | + | |
1363 | 1442 | | |
1364 | | - | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
1365 | 1449 | | |
1366 | 1450 | | |
1367 | 1451 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1000 | 1000 | | |
1001 | 1001 | | |
1002 | 1002 | | |
| 1003 | + | |
1003 | 1004 | | |
1004 | 1005 | | |
1005 | 1006 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
24 | | - | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
30 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
31 | 36 | | |
32 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
33 | 43 | | |
34 | 44 | | |
35 | 45 | | |
36 | | - | |
| 46 | + | |
| 47 | + | |
37 | 48 | | |
38 | 49 | | |
39 | 50 | | |
40 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
41 | 81 | | |
42 | 82 | | |
43 | 83 | | |
| |||
0 commit comments