Spaces:
Running
Running
thibaud frere
commited on
Commit
·
98af9a5
1
Parent(s):
89de168
update
Browse files
app/scripts/export-pdf.mjs
CHANGED
|
@@ -64,6 +64,29 @@ function parseMargin(margin) {
|
|
| 64 |
return { top: parts[0] || '12mm', right: parts[1] || '12mm', bottom: parts[2] || '16mm', left: parts[3] || '12mm' };
|
| 65 |
}
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
async function waitForImages(page, timeoutMs = 15000) {
|
| 68 |
await page.evaluate(async (timeout) => {
|
| 69 |
const deadline = Date.now() + timeout;
|
|
@@ -149,9 +172,15 @@ async function main() {
|
|
| 149 |
} catch {}
|
| 150 |
}, theme);
|
| 151 |
const page = await context.newPage();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
await page.goto(baseUrl, { waitUntil: 'load', timeout: 60000 });
|
| 153 |
// Give time for CDN scripts (Plotly/D3) to attach and for our fragment hooks to run
|
| 154 |
try { await page.waitForFunction(() => !!window.Plotly, { timeout: 8000 }); } catch {}
|
|
|
|
| 155 |
// Compute slug from title if needed
|
| 156 |
if (!args.filename) {
|
| 157 |
const title = await page.evaluate(() => {
|
|
|
|
| 64 |
return { top: parts[0] || '12mm', right: parts[1] || '12mm', bottom: parts[2] || '16mm', left: parts[3] || '12mm' };
|
| 65 |
}
|
| 66 |
|
| 67 |
+
function cssLengthToMm(val) {
|
| 68 |
+
if (!val) return 0;
|
| 69 |
+
const s = String(val).trim();
|
| 70 |
+
if (/mm$/i.test(s)) return parseFloat(s);
|
| 71 |
+
if (/cm$/i.test(s)) return parseFloat(s) * 10;
|
| 72 |
+
if (/in$/i.test(s)) return parseFloat(s) * 25.4;
|
| 73 |
+
if (/px$/i.test(s)) return (parseFloat(s) / 96) * 25.4; // 96 CSS px per inch
|
| 74 |
+
const num = parseFloat(s);
|
| 75 |
+
return Number.isFinite(num) ? num : 0; // assume mm if unitless
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
function getFormatSizeMm(format) {
|
| 79 |
+
const f = String(format || 'A4').toLowerCase();
|
| 80 |
+
switch (f) {
|
| 81 |
+
case 'letter': return { w: 215.9, h: 279.4 };
|
| 82 |
+
case 'legal': return { w: 215.9, h: 355.6 };
|
| 83 |
+
case 'a3': return { w: 297, h: 420 };
|
| 84 |
+
case 'tabloid': return { w: 279.4, h: 431.8 };
|
| 85 |
+
case 'a4':
|
| 86 |
+
default: return { w: 210, h: 297 };
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
async function waitForImages(page, timeoutMs = 15000) {
|
| 91 |
await page.evaluate(async (timeout) => {
|
| 92 |
const deadline = Date.now() + timeout;
|
|
|
|
| 172 |
} catch {}
|
| 173 |
}, theme);
|
| 174 |
const page = await context.newPage();
|
| 175 |
+
// Pre-fit viewport width to printable width so charts size correctly
|
| 176 |
+
const fmt = getFormatSizeMm(format);
|
| 177 |
+
const mw = fmt.w - cssLengthToMm(margin.left) - cssLengthToMm(margin.right);
|
| 178 |
+
const printableWidthPx = Math.max(320, Math.round((mw / 25.4) * 96));
|
| 179 |
+
await page.setViewportSize({ width: printableWidthPx, height: 1200 });
|
| 180 |
await page.goto(baseUrl, { waitUntil: 'load', timeout: 60000 });
|
| 181 |
// Give time for CDN scripts (Plotly/D3) to attach and for our fragment hooks to run
|
| 182 |
try { await page.waitForFunction(() => !!window.Plotly, { timeout: 8000 }); } catch {}
|
| 183 |
+
try { await page.waitForFunction(() => !!window.d3, { timeout: 8000 }); } catch {}
|
| 184 |
// Compute slug from title if needed
|
| 185 |
if (!args.filename) {
|
| 186 |
const title = await page.evaluate(() => {
|
app/src/components/HtmlFragment.astro
CHANGED
|
@@ -51,8 +51,8 @@ const mountId = `frag-${Math.random().toString(36).slice(2)}`;
|
|
| 51 |
}
|
| 52 |
});
|
| 53 |
};
|
| 54 |
-
// Ensure execution when ready: run now if Plotly is present or document
|
| 55 |
-
if (window.Plotly || document.readyState === 'complete') execute();
|
| 56 |
else window.addEventListener('load', execute, { once: true });
|
| 57 |
</script>
|
| 58 |
|
|
|
|
| 51 |
}
|
| 52 |
});
|
| 53 |
};
|
| 54 |
+
// Ensure execution when ready: run now if Plotly or D3 is present, or when document is ready; otherwise wait for 'load'
|
| 55 |
+
if (window.Plotly || window.d3 || document.readyState === 'complete') execute();
|
| 56 |
else window.addEventListener('load', execute, { once: true });
|
| 57 |
</script>
|
| 58 |
|
app/src/content/article.mdx
CHANGED
|
@@ -402,7 +402,9 @@ Favor **concise captions** and callouts that clarify what to look at and why it
|
|
| 402 |
|
| 403 |
### Use the right color scale
|
| 404 |
|
| 405 |
-
|
|
|
|
|
|
|
| 406 |
|
| 407 |
<div className="">
|
| 408 |
<HtmlFragment src="palettes.html" />
|
|
|
|
| 402 |
|
| 403 |
### Use the right color scale
|
| 404 |
|
| 405 |
+
A **palette** encodes **meaning** (categories, magnitudes, oppositions), preserves **readability** and **accessibility** (**sufficient contrast**, **color‑vision safety**), and ensures **perceptually smooth transitions**.
|
| 406 |
+
|
| 407 |
+
The three families below illustrate when to use **categorical**, **sequential**, or **diverging** colors and how they evolve from the same **reference hue**.
|
| 408 |
|
| 409 |
<div className="">
|
| 410 |
<HtmlFragment src="palettes.html" />
|
app/src/pages/index.astro
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
---
|
| 2 |
import Article, { frontmatter as articleFM } from '../content/article.mdx';
|
| 3 |
import Meta from '../components/Meta.astro';
|
| 4 |
-
import HtmlFragment from '../components/HtmlFragment.astro';
|
| 5 |
import Footer from '../components/Footer.astro';
|
| 6 |
import Header from '../components/Header.astro';
|
| 7 |
import ThemeToggle from '../components/ThemeToggle.astro';
|
|
|
|
| 1 |
---
|
| 2 |
import Article, { frontmatter as articleFM } from '../content/article.mdx';
|
| 3 |
import Meta from '../components/Meta.astro';
|
|
|
|
| 4 |
import Footer from '../components/Footer.astro';
|
| 5 |
import Header from '../components/Header.astro';
|
| 6 |
import ThemeToggle from '../components/ThemeToggle.astro';
|