Spaces:
Running
Running
thibaud frere
commited on
Commit
·
33aefb9
1
Parent(s):
c7b266f
update pdf
Browse files
app/scripts/export-pdf.mjs
CHANGED
@@ -239,6 +239,61 @@ async function main() {
|
|
239 |
}
|
240 |
await page.emulateMedia({ media: 'print' });
|
241 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
// Generate OG thumbnail (1200x630)
|
243 |
try {
|
244 |
const ogW = 1200, ogH = 630;
|
@@ -281,13 +336,84 @@ async function main() {
|
|
281 |
await page.evaluate(() => { window.scrollTo(0, 0); window.dispatchEvent(new Event('resize')); });
|
282 |
try { await waitForD3(page, 8000); } catch {}
|
283 |
await waitForStableLayout(page);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
} catch {}
|
285 |
-
// Temporarily
|
286 |
let pdfCssHandle = null;
|
287 |
try {
|
288 |
pdfCssHandle = await page.addStyleTag({ content: `
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
.hero .points { mix-blend-mode: normal !important; }
|
290 |
-
.d3-galaxy
|
|
|
291 |
` });
|
292 |
} catch {}
|
293 |
await page.pdf({
|
|
|
239 |
}
|
240 |
await page.emulateMedia({ media: 'print' });
|
241 |
|
242 |
+
// Enforce responsive sizing for SVG/iframes by removing hard attrs and injecting CSS (top-level and inside same-origin iframes)
|
243 |
+
try {
|
244 |
+
await page.evaluate(() => {
|
245 |
+
function isSmallSvg(svg){
|
246 |
+
try {
|
247 |
+
const vb = svg && svg.viewBox && svg.viewBox.baseVal ? svg.viewBox.baseVal : null;
|
248 |
+
if (vb && vb.width && vb.height && vb.width <= 50 && vb.height <= 50) return true;
|
249 |
+
const r = svg.getBoundingClientRect && svg.getBoundingClientRect();
|
250 |
+
if (r && r.width && r.height && r.width <= 50 && r.height <= 50) return true;
|
251 |
+
} catch {}
|
252 |
+
return false;
|
253 |
+
}
|
254 |
+
function lockSmallSvgSize(svg){
|
255 |
+
try {
|
256 |
+
const r = svg.getBoundingClientRect ? svg.getBoundingClientRect() : null;
|
257 |
+
const w = (r && r.width) ? Math.round(r.width) : null;
|
258 |
+
const h = (r && r.height) ? Math.round(r.height) : null;
|
259 |
+
if (w) svg.style.setProperty('width', w + 'px', 'important');
|
260 |
+
if (h) svg.style.setProperty('height', h + 'px', 'important');
|
261 |
+
svg.style.setProperty('max-width', 'none', 'important');
|
262 |
+
} catch {}
|
263 |
+
}
|
264 |
+
function fixSvg(svg){
|
265 |
+
if (!svg) return;
|
266 |
+
if (isSmallSvg(svg)) { lockSmallSvgSize(svg); return; }
|
267 |
+
try { svg.removeAttribute('width'); } catch {}
|
268 |
+
try { svg.removeAttribute('height'); } catch {}
|
269 |
+
svg.style.maxWidth = '100%';
|
270 |
+
svg.style.width = '100%';
|
271 |
+
svg.style.height = 'auto';
|
272 |
+
if (!svg.getAttribute('preserveAspectRatio')) svg.setAttribute('preserveAspectRatio','xMidYMid meet');
|
273 |
+
}
|
274 |
+
document.querySelectorAll('svg').forEach(fixSvg);
|
275 |
+
document.querySelectorAll('.mermaid, .mermaid svg').forEach((el)=>{
|
276 |
+
if (el.tagName && el.tagName.toLowerCase() === 'svg') fixSvg(el);
|
277 |
+
else { el.style.display='block'; el.style.width='100%'; el.style.maxWidth='100%'; }
|
278 |
+
});
|
279 |
+
document.querySelectorAll('iframe, embed, object').forEach((el) => {
|
280 |
+
el.style.width = '100%';
|
281 |
+
el.style.maxWidth = '100%';
|
282 |
+
try { el.removeAttribute('width'); } catch {}
|
283 |
+
// Best-effort inject into same-origin frames
|
284 |
+
try {
|
285 |
+
const doc = (el.tagName.toLowerCase()==='object' ? el.contentDocument : el.contentDocument);
|
286 |
+
if (doc && doc.head) {
|
287 |
+
const s = doc.createElement('style');
|
288 |
+
s.textContent = 'html,body{overflow-x:hidden;} svg,canvas,img,video{max-width:100%!important;height:auto!important;} svg[width]{width:100%!important}';
|
289 |
+
doc.head.appendChild(s);
|
290 |
+
doc.querySelectorAll('svg').forEach((svg)=>{ if (isSmallSvg(svg)) lockSmallSvgSize(svg); else fixSvg(svg); });
|
291 |
+
}
|
292 |
+
} catch (_) { /* cross-origin; ignore */ }
|
293 |
+
});
|
294 |
+
});
|
295 |
+
} catch {}
|
296 |
+
|
297 |
// Generate OG thumbnail (1200x630)
|
298 |
try {
|
299 |
const ogW = 1200, ogH = 630;
|
|
|
336 |
await page.evaluate(() => { window.scrollTo(0, 0); window.dispatchEvent(new Event('resize')); });
|
337 |
try { await waitForD3(page, 8000); } catch {}
|
338 |
await waitForStableLayout(page);
|
339 |
+
// Re-apply responsive fixes after viewport change
|
340 |
+
try {
|
341 |
+
await page.evaluate(() => {
|
342 |
+
function isSmallSvg(svg){
|
343 |
+
try {
|
344 |
+
const vb = svg && svg.viewBox && svg.viewBox.baseVal ? svg.viewBox.baseVal : null;
|
345 |
+
if (vb && vb.width && vb.height && vb.width <= 50 && vb.height <= 50) return true;
|
346 |
+
const r = svg.getBoundingClientRect && svg.getBoundingClientRect();
|
347 |
+
if (r && r.width && r.height && r.width <= 50 && r.height <= 50) return true;
|
348 |
+
} catch {}
|
349 |
+
return false;
|
350 |
+
}
|
351 |
+
function lockSmallSvgSize(svg){
|
352 |
+
try {
|
353 |
+
const r = svg.getBoundingClientRect ? svg.getBoundingClientRect() : null;
|
354 |
+
const w = (r && r.width) ? Math.round(r.width) : null;
|
355 |
+
const h = (r && r.height) ? Math.round(r.height) : null;
|
356 |
+
if (w) svg.style.setProperty('width', w + 'px', 'important');
|
357 |
+
if (h) svg.style.setProperty('height', h + 'px', 'important');
|
358 |
+
svg.style.setProperty('max-width', 'none', 'important');
|
359 |
+
} catch {}
|
360 |
+
}
|
361 |
+
function fixSvg(svg){
|
362 |
+
if (!svg) return;
|
363 |
+
if (isSmallSvg(svg)) { lockSmallSvgSize(svg); return; }
|
364 |
+
try { svg.removeAttribute('width'); } catch {}
|
365 |
+
try { svg.removeAttribute('height'); } catch {}
|
366 |
+
svg.style.maxWidth = '100%';
|
367 |
+
svg.style.width = '100%';
|
368 |
+
svg.style.height = 'auto';
|
369 |
+
if (!svg.getAttribute('preserveAspectRatio')) svg.setAttribute('preserveAspectRatio','xMidYMid meet');
|
370 |
+
}
|
371 |
+
document.querySelectorAll('svg').forEach((svg)=>{ if (isSmallSvg(svg)) lockSmallSvgSize(svg); else fixSvg(svg); });
|
372 |
+
document.querySelectorAll('.mermaid, .mermaid svg').forEach((el)=>{
|
373 |
+
if (el.tagName && el.tagName.toLowerCase() === 'svg') fixSvg(el);
|
374 |
+
else { el.style.display='block'; el.style.width='100%'; el.style.maxWidth='100%'; }
|
375 |
+
});
|
376 |
+
document.querySelectorAll('iframe, embed, object').forEach((el) => {
|
377 |
+
el.style.width = '100%';
|
378 |
+
el.style.maxWidth = '100%';
|
379 |
+
try { el.removeAttribute('width'); } catch {}
|
380 |
+
try {
|
381 |
+
const doc = (el.tagName.toLowerCase()==='object' ? el.contentDocument : el.contentDocument);
|
382 |
+
if (doc && doc.head) {
|
383 |
+
const s = doc.createElement('style');
|
384 |
+
s.textContent = 'html,body{overflow-x:hidden;} svg,canvas,img,video{max-width:100%!important;height:auto!important;} svg[width]{width:100%!important}';
|
385 |
+
doc.head.appendChild(s);
|
386 |
+
doc.querySelectorAll('svg').forEach((svg)=>{ if (isSmallSvg(svg)) lockSmallSvgSize(svg); else fixSvg(svg); });
|
387 |
+
}
|
388 |
+
} catch (_) {}
|
389 |
+
});
|
390 |
+
});
|
391 |
+
} catch {}
|
392 |
} catch {}
|
393 |
+
// Temporarily enforce print-safe responsive sizing (SVG/iframes) and improve banner visibility
|
394 |
let pdfCssHandle = null;
|
395 |
try {
|
396 |
pdfCssHandle = await page.addStyleTag({ content: `
|
397 |
+
/* General container safety */
|
398 |
+
html, body { overflow-x: hidden !important; }
|
399 |
+
|
400 |
+
/* Make all vector/bitmap media responsive for print */
|
401 |
+
svg, canvas, img, video { max-width: 100% !important; height: auto !important; }
|
402 |
+
/* Mermaid diagrams */
|
403 |
+
.mermaid, .mermaid svg { display: block; width: 100% !important; max-width: 100% !important; height: auto !important; }
|
404 |
+
/* Any explicit width attributes */
|
405 |
+
svg[width] { width: 100% !important; }
|
406 |
+
/* Iframes and similar embeds */
|
407 |
+
iframe, embed, object { width: 100% !important; max-width: 100% !important; height: auto; }
|
408 |
+
|
409 |
+
/* HtmlEmbed wrappers (defensive) */
|
410 |
+
.html-embed, .html-embed__card { max-width: 100% !important; width: 100% !important; }
|
411 |
+
.html-embed__card > div[id^="frag-"] { width: 100% !important; max-width: 100% !important; }
|
412 |
+
|
413 |
+
/* Banner centering & visibility */
|
414 |
.hero .points { mix-blend-mode: normal !important; }
|
415 |
+
.d3-galaxy { width: 100% !important; height: 300px; max-width: 980px !important; margin-left: auto !important; margin-right: auto !important; }
|
416 |
+
.d3-galaxy svg { background: var(--surface-bg); width: 100% !important; height: auto !important; }
|
417 |
` });
|
418 |
} catch {}
|
419 |
await page.pdf({
|
app/src/components/Hero.astro
CHANGED
@@ -57,7 +57,7 @@ const pdfFilename = `${slugify(pdfBase)}.pdf`;
|
|
57 |
<p>{published}</p>
|
58 |
</div>
|
59 |
)}
|
60 |
-
<div class="meta-container-cell">
|
61 |
<h3>PDF</h3>
|
62 |
<p><button id="download-pdf-btn" data-pdf-filename={pdfFilename}>Download PDF</button></p>
|
63 |
</div>
|
@@ -99,6 +99,7 @@ const pdfFilename = `${slugify(pdfBase)}.pdf`;
|
|
99 |
.meta-container-cell { display: flex; flex-direction: column; gap: 8px; }
|
100 |
.meta-container-cell h3 { margin: 0; font-size: 12px; font-weight: 400; color: var(--muted-color); text-transform: uppercase; letter-spacing: .02em; }
|
101 |
.meta-container-cell p { margin: 0; }
|
|
|
102 |
</style>
|
103 |
|
104 |
|
|
|
57 |
<p>{published}</p>
|
58 |
</div>
|
59 |
)}
|
60 |
+
<div class="meta-container-cell meta-container-cell--pdf">
|
61 |
<h3>PDF</h3>
|
62 |
<p><button id="download-pdf-btn" data-pdf-filename={pdfFilename}>Download PDF</button></p>
|
63 |
</div>
|
|
|
99 |
.meta-container-cell { display: flex; flex-direction: column; gap: 8px; }
|
100 |
.meta-container-cell h3 { margin: 0; font-size: 12px; font-weight: 400; color: var(--muted-color); text-transform: uppercase; letter-spacing: .02em; }
|
101 |
.meta-container-cell p { margin: 0; }
|
102 |
+
@media print { .meta-container-cell--pdf { display: none !important; } }
|
103 |
</style>
|
104 |
|
105 |
|
app/src/components/HtmlEmbed.astro
CHANGED
@@ -102,7 +102,20 @@ const mountId = `frag-${Math.random().toString(36).slice(2)}`;
|
|
102 |
.html-embed__card > div[id^="frag-"] { width: 100% !important; }
|
103 |
}
|
104 |
@media print {
|
|
|
105 |
.html-embed, .html-embed__card { break-inside: avoid; page-break-inside: avoid; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
}
|
107 |
</style>
|
108 |
|
|
|
102 |
.html-embed__card > div[id^="frag-"] { width: 100% !important; }
|
103 |
}
|
104 |
@media print {
|
105 |
+
/* Avoid breaks inside embeds */
|
106 |
.html-embed, .html-embed__card { break-inside: avoid; page-break-inside: avoid; }
|
107 |
+
/* Constrain width and scale inner content */
|
108 |
+
.html-embed, .html-embed__card { max-width: 100% !important; width: 100% !important; }
|
109 |
+
.html-embed__card { padding: 6px; }
|
110 |
+
.html-embed__card.is-frameless { padding: 0; }
|
111 |
+
.html-embed__card svg,
|
112 |
+
.html-embed__card canvas,
|
113 |
+
.html-embed__card img,
|
114 |
+
.html-embed__card video,
|
115 |
+
.html-embed__card iframe { max-width: 100% !important; height: auto !important; }
|
116 |
+
.html-embed__card > div[id^="frag-"] { width: 100% !important; max-width: 100% !important; }
|
117 |
+
/* Center and constrain the banner (galaxy) when printing */
|
118 |
+
.html-embed .d3-galaxy { width: 100% !important; max-width: 980px !important; margin-left: auto !important; margin-right: auto !important; }
|
119 |
}
|
120 |
</style>
|
121 |
|
app/src/content/embeds/palettes.html
CHANGED
@@ -28,11 +28,11 @@
|
|
28 |
.palettes input[type="range"]:focus { outline: none; }
|
29 |
/* WebKit */
|
30 |
.palettes input[type="range"]::-webkit-slider-runnable-track { height: 6px; background: var(--border-color); border-radius: 999px; }
|
31 |
-
.palettes input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; margin-top: -6px; width: 18px; height: 18px; background: var(--primary-color); border: 2px solid var(--surface-bg); border-radius: 50%;
|
32 |
/* Firefox */
|
33 |
.palettes input[type="range"]::-moz-range-track { height: 6px; background: var(--border-color); border: none; border-radius: 999px; }
|
34 |
.palettes input[type="range"]::-moz-range-progress { height: 6px; background: var(--primary-color); border-radius: 999px; }
|
35 |
-
.palettes input[type="range"]::-moz-range-thumb { width: 18px; height: 18px; background: var(--primary-color); border: 2px solid var(--surface-bg); border-radius: 50%;
|
36 |
/* Page-wide color vision simulation classes */
|
37 |
html.cb-grayscale, body.cb-grayscale { filter: grayscale(1) !important; }
|
38 |
html.cb-protanopia, body.cb-protanopia { filter: url(#cb-protanopia) !important; }
|
|
|
28 |
.palettes input[type="range"]:focus { outline: none; }
|
29 |
/* WebKit */
|
30 |
.palettes input[type="range"]::-webkit-slider-runnable-track { height: 6px; background: var(--border-color); border-radius: 999px; }
|
31 |
+
.palettes input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; margin-top: -6px; width: 18px; height: 18px; background: var(--primary-color); border: 2px solid var(--surface-bg); border-radius: 50%; }
|
32 |
/* Firefox */
|
33 |
.palettes input[type="range"]::-moz-range-track { height: 6px; background: var(--border-color); border: none; border-radius: 999px; }
|
34 |
.palettes input[type="range"]::-moz-range-progress { height: 6px; background: var(--primary-color); border-radius: 999px; }
|
35 |
+
.palettes input[type="range"]::-moz-range-thumb { width: 18px; height: 18px; background: var(--primary-color); border: 2px solid var(--surface-bg); border-radius: 50%; }
|
36 |
/* Page-wide color vision simulation classes */
|
37 |
html.cb-grayscale, body.cb-grayscale { filter: grayscale(1) !important; }
|
38 |
html.cb-protanopia, body.cb-protanopia { filter: url(#cb-protanopia) !important; }
|