feat(md-print): use mm font and corner page numbers
Body font size is now specified in millimetres and defaults to 3mm. Page numbers move from the centre footer to the outer bottom corners, alternating left and right per A5 page.
This commit is contained in:
@@ -116,13 +116,13 @@ Prefer the `yaml role=tag` form — it is the only form that supports template l
|
||||
|
||||
Paginates a markdown document into A4 landscape sheets for printing.
|
||||
|
||||
Each sheet holds two A5 pages side by side, and each A5 page flows the markdown into `columns` columns. `margin` and `gap` are in millimetres, `font` is in points. `pageNumbers` adds an `n / total` footer and `cutMarks` draws the centre cut line. The preview modal exports through the browser's print dialog (choose A4 landscape, no margins, 100% scale).
|
||||
Each sheet holds two A5 pages side by side, and each A5 page flows the markdown into `columns` columns. `margin`, `gap`, and `font` are in millimetres (the body font defaults to 3mm). `pageNumbers` adds an `n / total` footer in the outer corner and `cutMarks` draws the centre cut line. The preview modal exports through the browser's print dialog (choose A4 landscape, no margins, 100% scale).
|
||||
|
||||
- Body: markdown path, optional #section
|
||||
- Attributes: `columns`, `margin`, `gap`, `font`, `title`, `pageNumbers`, `cutMarks`
|
||||
|
||||
```markdown
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="9"}
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}
|
||||
```
|
||||
|
||||
````markdown
|
||||
@@ -132,7 +132,7 @@ body: ./rules.md
|
||||
columns: 2
|
||||
margin: 10
|
||||
gap: 5
|
||||
font: 9
|
||||
font: 3
|
||||
title: 规则书
|
||||
```
|
||||
````
|
||||
|
||||
+4
-4
@@ -464,7 +464,7 @@ data-config:
|
||||
|
||||
```markdown
|
||||
:md-print[./rules.md]
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="9"}
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}
|
||||
```
|
||||
|
||||
**功能:**
|
||||
@@ -480,9 +480,9 @@ data-config:
|
||||
| `columns` | number | `2` | 每个 A5 页面的列数(1–4) |
|
||||
| `margin` | number | `10` | 页面边距(毫米) |
|
||||
| `gap` | number | `5` | 列间距(毫米) |
|
||||
| `font` | number | `9` | 正文字号(磅) |
|
||||
| `font` | number | `3` | 正文字号(毫米) |
|
||||
| `title` | string | - | 页眉标题 |
|
||||
| `pageNumbers` | boolean | `true` | 是否显示页码 |
|
||||
| `pageNumbers` | boolean | `true` | 是否在页面外侧角落显示页码 |
|
||||
| `cutMarks` | boolean | `true` | 是否显示 A4 中缝裁切线 |
|
||||
|
||||
**YAML 写法:**
|
||||
@@ -493,7 +493,7 @@ body: ./rules.md
|
||||
columns: 2
|
||||
margin: 10
|
||||
gap: 5
|
||||
font: 9
|
||||
font: 3
|
||||
title: 规则书
|
||||
```
|
||||
|
||||
|
||||
+3
-3
@@ -116,13 +116,13 @@ Prefer the `yaml role=tag` form — it is the only form that supports template l
|
||||
|
||||
Paginates a markdown document into A4 landscape sheets for printing.
|
||||
|
||||
Each sheet holds two A5 pages side by side, and each A5 page flows the markdown into `columns` columns. `margin` and `gap` are in millimetres, `font` is in points. `pageNumbers` adds an `n / total` footer and `cutMarks` draws the centre cut line. The preview modal exports through the browser's print dialog (choose A4 landscape, no margins, 100% scale).
|
||||
Each sheet holds two A5 pages side by side, and each A5 page flows the markdown into `columns` columns. `margin`, `gap`, and `font` are in millimetres (the body font defaults to 3mm). `pageNumbers` adds an `n / total` footer in the outer corner and `cutMarks` draws the centre cut line. The preview modal exports through the browser's print dialog (choose A4 landscape, no margins, 100% scale).
|
||||
|
||||
- Body: markdown path, optional #section
|
||||
- Attributes: `columns`, `margin`, `gap`, `font`, `title`, `pageNumbers`, `cutMarks`
|
||||
|
||||
```markdown
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="9"}
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}
|
||||
```
|
||||
|
||||
````markdown
|
||||
@@ -132,7 +132,7 @@ body: ./rules.md
|
||||
columns: 2
|
||||
margin: 10
|
||||
gap: 5
|
||||
font: 9
|
||||
font: 3
|
||||
title: 规则书
|
||||
```
|
||||
````
|
||||
|
||||
@@ -82,11 +82,11 @@ export const KNOWN_ELEMENTS: readonly ElementSpec[] = [
|
||||
summary:
|
||||
"Paginates a markdown document into A4 landscape sheets for printing.",
|
||||
details:
|
||||
"Each sheet holds two A5 pages side by side, and each A5 page flows the markdown into `columns` columns. `margin` and `gap` are in millimetres, `font` is in points. `pageNumbers` adds an `n / total` footer and `cutMarks` draws the centre cut line. The preview modal exports through the browser's print dialog (choose A4 landscape, no margins, 100% scale).",
|
||||
"Each sheet holds two A5 pages side by side, and each A5 page flows the markdown into `columns` columns. `margin`, `gap`, and `font` are in millimetres (the body font defaults to 3mm). `pageNumbers` adds an `n / total` footer in the outer corner and `cutMarks` draws the centre cut line. The preview modal exports through the browser's print dialog (choose A4 landscape, no margins, 100% scale).",
|
||||
refKind: "md",
|
||||
examples: [
|
||||
':md-print[./rules.md]{columns="2" margin="10" gap="5" font="9"}',
|
||||
"```yaml role=tag\ntag: md-print\nbody: ./rules.md\ncolumns: 2\nmargin: 10\ngap: 5\nfont: 9\ntitle: 规则书\n```",
|
||||
':md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}',
|
||||
"```yaml role=tag\ntag: md-print\nbody: ./rules.md\ncolumns: 2\nmargin: 10\ngap: 5\nfont: 3\ntitle: 规则书\n```",
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -90,7 +90,15 @@ export function PrintPreview(props: PrintPreviewProps) {
|
||||
const result = paginate(source, options(), mount);
|
||||
result.pages.forEach((page, index) => {
|
||||
const footer = page.querySelector(".md-print-footer");
|
||||
if (footer) footer.textContent = `${index + 1} / ${result.pages.length}`;
|
||||
if (footer) {
|
||||
footer.textContent = `${index + 1} / ${result.pages.length}`;
|
||||
// Left A5 gets the left corner, right A5 gets the right corner.
|
||||
footer.classList.add(
|
||||
index % 2 === 0
|
||||
? "md-print-footer--left"
|
||||
: "md-print-footer--right",
|
||||
);
|
||||
}
|
||||
});
|
||||
setPages(result.pages);
|
||||
setWarnings(result.warnings);
|
||||
@@ -224,7 +232,7 @@ export function PrintPreview(props: PrintPreviewProps) {
|
||||
class="md-print-content prose"
|
||||
style={{
|
||||
width: `${columnWidthMm(props.config)}mm`,
|
||||
"--md-print-font-size": `${props.config.font}pt`,
|
||||
"--md-print-font-size": `${props.config.font}mm`,
|
||||
position: "absolute",
|
||||
left: "-99999px",
|
||||
top: "0",
|
||||
|
||||
@@ -18,11 +18,16 @@ describe("normalizePrintConfig", () => {
|
||||
expect(config.columns).toBe(3);
|
||||
expect(config.margin).toBe(40);
|
||||
expect(config.gap).toBe(0);
|
||||
expect(config.font).toBe(16);
|
||||
expect(config.font).toBe(6);
|
||||
expect(config.pageNumbers).toBe(false);
|
||||
expect(config.cutMarks).toBe(false);
|
||||
});
|
||||
|
||||
test("clamps font to 2..6mm", () => {
|
||||
expect(normalizePrintConfig({ font: "1" }).font).toBe(2);
|
||||
expect(normalizePrintConfig({ font: "20" }).font).toBe(6);
|
||||
});
|
||||
|
||||
test("clamps columns to 1..4", () => {
|
||||
expect(normalizePrintConfig({ columns: "0" }).columns).toBe(1);
|
||||
expect(normalizePrintConfig({ columns: "9" }).columns).toBe(4);
|
||||
@@ -33,7 +38,7 @@ describe("normalizePrintConfig", () => {
|
||||
columns: 2,
|
||||
margin: 12,
|
||||
gap: 6,
|
||||
font: 10,
|
||||
font: 3,
|
||||
title: "规则书",
|
||||
pageNumbers: true,
|
||||
cutMarks: false,
|
||||
@@ -43,7 +48,7 @@ describe("normalizePrintConfig", () => {
|
||||
columns: 2,
|
||||
margin: 12,
|
||||
gap: 6,
|
||||
font: 10,
|
||||
font: 3,
|
||||
title: "规则书",
|
||||
pageNumbers: true,
|
||||
cutMarks: false,
|
||||
|
||||
@@ -4,7 +4,7 @@ export const PRINT_DEFAULTS: PrintConfig = {
|
||||
columns: 2,
|
||||
margin: 10,
|
||||
gap: 5,
|
||||
font: 9,
|
||||
font: 3,
|
||||
title: "",
|
||||
pageNumbers: true,
|
||||
cutMarks: true,
|
||||
@@ -43,7 +43,7 @@ export function normalizePrintConfig(
|
||||
),
|
||||
margin: clamp(toNumber(input.margin, PRINT_DEFAULTS.margin), 5, 40),
|
||||
gap: clamp(toNumber(input.gap, PRINT_DEFAULTS.gap), 0, 20),
|
||||
font: clamp(toNumber(input.font, PRINT_DEFAULTS.font), 6, 16),
|
||||
font: clamp(toNumber(input.font, PRINT_DEFAULTS.font), 2, 6),
|
||||
title:
|
||||
typeof input.title === "string" ? input.title : PRINT_DEFAULTS.title,
|
||||
pageNumbers: toBoolean(input.pageNumbers, PRINT_DEFAULTS.pageNumbers),
|
||||
|
||||
@@ -12,7 +12,7 @@ customElement<PrintProps>(
|
||||
columns: "2",
|
||||
margin: "10",
|
||||
gap: "5",
|
||||
font: "9",
|
||||
font: "3",
|
||||
title: "",
|
||||
pageNumbers: "true",
|
||||
cutMarks: "true",
|
||||
|
||||
@@ -54,7 +54,7 @@ export function createPageElement(opts: PaginateOptions): {
|
||||
page.style.position = "relative";
|
||||
page.style.overflow = "hidden";
|
||||
page.style.background = "white";
|
||||
page.style.setProperty("--md-print-font-size", `${opts.font}pt`);
|
||||
page.style.setProperty("--md-print-font-size", `${opts.font}mm`);
|
||||
|
||||
if (opts.title) {
|
||||
const header = document.createElement("div");
|
||||
|
||||
@@ -5,7 +5,7 @@ export interface PrintConfig {
|
||||
margin: number;
|
||||
/** Column gap in millimetres. */
|
||||
gap: number;
|
||||
/** Body font size in points. */
|
||||
/** Body font size in millimetres. */
|
||||
font: number;
|
||||
/** Running header text. Empty hides the header. */
|
||||
title: string;
|
||||
|
||||
@@ -17,7 +17,7 @@ title: 打印版式
|
||||
**自定义版式:**
|
||||
|
||||
```markdown
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="9"}
|
||||
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}
|
||||
```
|
||||
|
||||
**YAML 写法:**
|
||||
@@ -28,7 +28,7 @@ body: ./rules.md
|
||||
columns: 2
|
||||
margin: 10
|
||||
gap: 5
|
||||
font: 9
|
||||
font: 3
|
||||
title: 规则书
|
||||
```
|
||||
|
||||
@@ -41,9 +41,9 @@ title: 规则书
|
||||
| `columns` | number | `2` | 每个 A5 页面的列数(1–4) |
|
||||
| `margin` | number | `10` | 页面边距(毫米) |
|
||||
| `gap` | number | `5` | 列间距(毫米) |
|
||||
| `font` | number | `9` | 正文字号(磅) |
|
||||
| `font` | number | `3` | 正文字号(毫米) |
|
||||
| `title` | string | — | 页眉标题 |
|
||||
| `pageNumbers` | boolean | `true` | 是否显示 `n / 总数` 页码 |
|
||||
| `pageNumbers` | boolean | `true` | 是否在页面外侧角落显示 `n / 总数` 页码 |
|
||||
| `cutMarks` | boolean | `true` | 是否显示 A4 中缝裁切线 |
|
||||
|
||||
## 打印设置
|
||||
|
||||
+20
-7
@@ -204,7 +204,7 @@ icon.big .icon-label-stroke {
|
||||
}
|
||||
|
||||
.md-print-content {
|
||||
font-size: var(--md-print-font-size, 9pt);
|
||||
font-size: var(--md-print-font-size, 3mm);
|
||||
line-height: 1.45;
|
||||
color: #000;
|
||||
max-width: none;
|
||||
@@ -257,11 +257,11 @@ icon.big .icon-label-stroke {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.md-print-header,
|
||||
.md-print-footer {
|
||||
.md-print-header {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 3mm;
|
||||
text-align: center;
|
||||
font-size: 8pt;
|
||||
color: #6b7280;
|
||||
@@ -270,12 +270,25 @@ icon.big .icon-label-stroke {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.md-print-header {
|
||||
top: 3mm;
|
||||
.md-print-footer {
|
||||
position: absolute;
|
||||
bottom: 3mm;
|
||||
left: 3mm;
|
||||
font-size: 8pt;
|
||||
color: #6b7280;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.md-print-footer {
|
||||
bottom: 3mm;
|
||||
.md-print-footer--left {
|
||||
left: 3mm;
|
||||
right: auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.md-print-footer--right {
|
||||
left: auto;
|
||||
right: 3mm;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
Reference in New Issue
Block a user