Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions scripts/export.checks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,15 @@ describe('exported content width', () => {

test('the export cap loses to the print block, so the PDF route is unchanged', () => {
// `@media print` in styles.css already forces `.markdown-body` to
// `max-width: 100% !important` with its own .75in padding, and that block
// `max-width: 100% !important` with its own 1cm padding, and that block
// travels into the export with the rest of the sheet. Printing an exported
// file therefore never saw the 900px and must not start seeing the setting
// either — the two routes stay separate concerns.
const css = exportedStylesheet(exportDocumentWithAppStyles(MIN_PREVIEW_MAX_WIDTH));
const printed = declarationsFor(css, 'max-width', 'print');
assert.ok(printed.length >= 1, 'the print block must still cap .markdown-body');
assert.deepEqual(printed.at(-1), { value: '100%', important: true });
assert.deepEqual(declarationsFor(css, 'padding', 'print').at(-1), { value: '0.75in', important: true });
assert.deepEqual(declarationsFor(css, 'padding', 'print').at(-1), { value: '1cm', important: true });
});

test('the app stylesheet copied into an export does not out-rank the cap', () => {
Expand Down Expand Up @@ -801,11 +801,12 @@ describe('oversized media in print', () => {
const printBlock = extractPrintBlock(styles);

// Paper geometry the cap has to satisfy. `@page { margin: 0 }` makes the page
// box the whole sheet, and `.markdown-body` supplies 0.75in of padding top and
// bottom, so the printable column is the sheet height minus 1.5in.
const LETTER_PRINTABLE_IN = 11 - 1.5;
// box the whole sheet, and `.markdown-body` supplies 1cm of padding top and
// bottom, so the printable column is the sheet height minus 2cm.
const MARGINS_IN = 2 / 2.54;
const LETTER_PRINTABLE_IN = 11 - MARGINS_IN;

const A4_PRINTABLE_IN = 11.69 - 1.5;
const A4_PRINTABLE_IN = 11.69 - MARGINS_IN;

/** Print rules whose body sets `property` (never a vendor-prefixed variant). */
function printRulesSetting(property: string): { selector: string; body: string }[] {
Expand Down
68 changes: 68 additions & 0 deletions scripts/export.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import assert from 'node:assert/strict';
import { describe, test } from 'vitest';

import { buildExportDocument } from '../src/lib/utils/export.ts';
import { plainAppearance } from './exportFixtures.ts';
import { readSource } from './sourceTree.js';

const appStyles = readSource('src/styles.css');

/**
* Loads `html` into the jsdom document as it would come out on `media`. jsdom
* applies no media type itself, so each `@media` block that names `media` (or
* `all`) is replaced in place by its own rules, and every other `@media` block
* is dropped.
*/
function render(html: string, media: 'print' | 'screen'): Document {
document.documentElement.innerHTML = html.replace(/^<!DOCTYPE html>\s*<html[^>]*>/, '').replace(/<\/html>\s*$/, '');
for (const sheet of Array.from(document.styleSheets)) {
for (let index = sheet.cssRules.length - 1; index >= 0; index -= 1) {
const rule = sheet.cssRules[index];
if (!(rule instanceof CSSMediaRule)) continue;
const applies = /\ball\b/.test(rule.media.mediaText) || rule.media.mediaText.includes(media);
const inner = applies ? Array.from(rule.cssRules, (r) => r.cssText) : [];
sheet.deleteRule(index);
inner.forEach((text, offset) => sheet.insertRule(text, index + offset));
}
}
return document;
}

function article(doc: Document): CSSStyleDeclaration {
const element = doc.querySelector('article.markdown-body');
assert.ok(element, 'the page has no article');
return getComputedStyle(element);
}

const exported = buildExportDocument({
theme: 'light',
title: 'Notes',
styles: appStyles,
articleHtml: '<p>body</p>',
contentWidth: null,
appearance: plainAppearance,
});

describe('printing an exported HTML file', () => {
test('prints the article instead of a blank page', () => {
// The copied print sheet hides everything outside #app, which an exported
// file does not have, so the article itself was hidden on paper.
assert.notEqual(article(render(exported, 'print')).display, 'none');
});

test('gets the same paper margins as the app’s own PDF', () => {
// The PDF route prints #print-root inside #app; the export used to keep its
// screen padding on paper instead.
const pdf = render(
`<head><style>${appStyles}</style></head><body><div id="app"><div id="print-root"><article class="markdown-body"></article></div></div></body>`,
'print',
);
const paper = article(pdf).paddingTop;
assert.equal(article(render(exported, 'print')).paddingTop, paper);
assert.equal(article(render(exported, 'print')).paddingLeft, paper);
});

test('keeps its 40px padding on screen', () => {
assert.equal(article(render(exported, 'screen')).paddingTop, '40px');
});
});
15 changes: 14 additions & 1 deletion src/lib/utils/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,27 @@ html, body {
padding: 0;
}
.markdown-body {
padding: 40px !important;
max-width: ${exportContentMaxWidth(input.contentWidth)};
${appearance}
margin: 0 auto;
height: auto !important;
overflow: visible !important;
min-height: 100%;
}
@media screen {
.markdown-body {
padding: 40px !important;
}
}
/* The copied print sheet hides everything outside #app, because the app prints
#print-root inside it. An exported file has no #app: its article is the page.
The :not(#app) is there for weight, to outrank that rule. Its padding is left
to the print sheet, so paper gets the same margins as the app's PDF. */
@media print {
body > .markdown-body:not(#app) {
display: block !important;
}
}
.lang-label {
display: none !important;
}
Expand Down
6 changes: 3 additions & 3 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,7 @@ body {
}

.markdown-body {
padding: 0.75in !important;
padding: 1cm !important;
margin: 0 !important;
box-sizing: border-box !important;
box-decoration-break: clone !important;
Expand Down Expand Up @@ -1549,8 +1549,8 @@ body {
margin: 1em auto;
}
/* An image or a diagram taller than the paper used to be clipped at the page
break rather than scaled; 9.5in is what both Letter and A4 hold with the
0.75in margins above. */
break rather than scaled; 9in fits both Letter and A4 inside the
1cm margins above. */
.markdown-body img,
.markdown-body .mermaid-diagram svg {
max-height: 9in !important;
Expand Down
Loading