@masumdev/markforge 0.2.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -116
- package/dist/App-3QDKBKHG.mjs +328 -0
- package/dist/{chunk-IYGPJIK5.mjs → chunk-BPHDY6VB.mjs} +6 -0
- package/dist/{App-GNRUPFM7.mjs → chunk-CRV7R2BG.mjs} +2094 -570
- package/dist/{chunk-NGC2ZAWZ.mjs → chunk-TNWZ4MFS.mjs} +1 -1
- package/dist/cli.mjs +29 -7
- package/dist/index.d.mts +603 -117
- package/dist/index.d.ts +603 -117
- package/dist/index.js +2863 -202
- package/dist/index.mjs +2851 -202
- package/dist/{loadConfig-PD6ENMAM.mjs → loadConfig-PGJKPE6G.mjs} +1 -1
- package/dist/previewServer-XAUOBNBZ.mjs +893 -0
- package/package.json +5 -1
- package/schema.json +142 -0
|
@@ -7,132 +7,9 @@ try {
|
|
|
7
7
|
});
|
|
8
8
|
}
|
|
9
9
|
} catch {}
|
|
10
|
-
import {
|
|
11
|
-
MARKFORGE_VERSION
|
|
12
|
-
} from "./chunk-NGC2ZAWZ.mjs";
|
|
13
10
|
import {
|
|
14
11
|
DEFAULT_CONFIG
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-YZHGBG4N.mjs";
|
|
17
|
-
|
|
18
|
-
// src/ui/App.tsx
|
|
19
|
-
import { useState, useEffect } from "react";
|
|
20
|
-
import { Box as Box4 } from "ink";
|
|
21
|
-
|
|
22
|
-
// src/ui/Header.tsx
|
|
23
|
-
import { Box, Text } from "ink";
|
|
24
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
25
|
-
var Header = ({ inputFile, theme = "corporate" }) => {
|
|
26
|
-
const themeLabel = typeof theme === "object" ? "custom (ThemeProps)" : String(theme || "corporate");
|
|
27
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs(
|
|
28
|
-
Box,
|
|
29
|
-
{
|
|
30
|
-
borderStyle: "round",
|
|
31
|
-
borderColor: "cyan",
|
|
32
|
-
paddingX: 2,
|
|
33
|
-
paddingY: 0,
|
|
34
|
-
flexDirection: "column",
|
|
35
|
-
children: [
|
|
36
|
-
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
|
|
37
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MARKFORGE DOCUMENT ENGINE" }),
|
|
38
|
-
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
39
|
-
"v",
|
|
40
|
-
MARKFORGE_VERSION
|
|
41
|
-
] })
|
|
42
|
-
] }),
|
|
43
|
-
inputFile && /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
44
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Source: " }),
|
|
45
|
-
/* @__PURE__ */ jsx(Text, { color: "white", bold: true, children: inputFile })
|
|
46
|
-
] }),
|
|
47
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
48
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Theme: " }),
|
|
49
|
-
/* @__PURE__ */ jsx(Text, { color: "blue", children: themeLabel })
|
|
50
|
-
] })
|
|
51
|
-
]
|
|
52
|
-
}
|
|
53
|
-
) });
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// src/ui/LiveProgress.tsx
|
|
57
|
-
import { Box as Box2, Text as Text2 } from "ink";
|
|
58
|
-
import Spinner from "ink-spinner";
|
|
59
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
60
|
-
var LiveProgress = ({ status, isCompiling }) => {
|
|
61
|
-
if (!isCompiling) return null;
|
|
62
|
-
return /* @__PURE__ */ jsxs2(Box2, { marginY: 1, alignItems: "center", children: [
|
|
63
|
-
/* @__PURE__ */ jsx2(Text2, { color: "cyan", children: /* @__PURE__ */ jsx2(Spinner, { type: "dots" }) }),
|
|
64
|
-
/* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, children: [
|
|
65
|
-
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "[COMPILING] " }),
|
|
66
|
-
/* @__PURE__ */ jsx2(Text2, { color: "white", children: status })
|
|
67
|
-
] })
|
|
68
|
-
] });
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// src/ui/SummaryTable.tsx
|
|
72
|
-
import { Box as Box3, Text as Text3 } from "ink";
|
|
73
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
74
|
-
function formatBytes(bytes) {
|
|
75
|
-
if (bytes === 0) return "0 B";
|
|
76
|
-
const k = 1024;
|
|
77
|
-
const sizes = ["B", "KB", "MB", "GB"];
|
|
78
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
79
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
80
|
-
}
|
|
81
|
-
var SummaryTable = ({ result }) => {
|
|
82
|
-
if (!result) return null;
|
|
83
|
-
const hasErrors = result.errors.length > 0;
|
|
84
|
-
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs3(
|
|
85
|
-
Box3,
|
|
86
|
-
{
|
|
87
|
-
borderStyle: "round",
|
|
88
|
-
borderColor: hasErrors ? "red" : "green",
|
|
89
|
-
paddingX: 2,
|
|
90
|
-
paddingY: 1,
|
|
91
|
-
flexDirection: "column",
|
|
92
|
-
children: [
|
|
93
|
-
/* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", children: [
|
|
94
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, color: hasErrors ? "red" : "green", children: hasErrors ? "[COMPILATION ERRORS]" : "[COMPILATION SUCCESSFUL]" }),
|
|
95
|
-
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
96
|
-
result.durationMs,
|
|
97
|
-
"ms"
|
|
98
|
-
] })
|
|
99
|
-
] }),
|
|
100
|
-
/* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
101
|
-
/* @__PURE__ */ jsxs3(Text3, { bold: true, color: "white", children: [
|
|
102
|
-
"Output Documents (",
|
|
103
|
-
result.files.length,
|
|
104
|
-
"):"
|
|
105
|
-
] }),
|
|
106
|
-
result.files.map((f, i) => /* @__PURE__ */ jsxs3(Box3, { marginLeft: 2, justifyContent: "space-between", children: [
|
|
107
|
-
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
108
|
-
/* @__PURE__ */ jsxs3(Text3, { color: "cyan", children: [
|
|
109
|
-
"[",
|
|
110
|
-
f.format.toUpperCase(),
|
|
111
|
-
"] "
|
|
112
|
-
] }),
|
|
113
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: f.filePath })
|
|
114
|
-
] }),
|
|
115
|
-
/* @__PURE__ */ jsxs3(Text3, { color: "yellow", children: [
|
|
116
|
-
" ",
|
|
117
|
-
formatBytes(f.sizeBytes)
|
|
118
|
-
] })
|
|
119
|
-
] }, i))
|
|
120
|
-
] }),
|
|
121
|
-
hasErrors && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
122
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "red", children: "Errors:" }),
|
|
123
|
-
result.errors.map((err, i) => /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
|
|
124
|
-
"- ",
|
|
125
|
-
err
|
|
126
|
-
] }) }, i))
|
|
127
|
-
] })
|
|
128
|
-
]
|
|
129
|
-
}
|
|
130
|
-
) });
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
// src/core/engine.ts
|
|
134
|
-
import * as fs5 from "fs";
|
|
135
|
-
import * as path5 from "path";
|
|
12
|
+
} from "./chunk-BPHDY6VB.mjs";
|
|
136
13
|
|
|
137
14
|
// src/core/parser.ts
|
|
138
15
|
import matter from "gray-matter";
|
|
@@ -166,6 +43,26 @@ function parseInlineSpans(text) {
|
|
|
166
43
|
remaining = remaining.slice(imgMatch[0].length);
|
|
167
44
|
continue;
|
|
168
45
|
}
|
|
46
|
+
const fnMatch = remaining.match(/^\[\^([\w-]+)\]/);
|
|
47
|
+
if (fnMatch) {
|
|
48
|
+
const fnId = fnMatch[1];
|
|
49
|
+
spans.push({
|
|
50
|
+
type: "footnoteRef",
|
|
51
|
+
content: fnId,
|
|
52
|
+
footnoteId: fnId
|
|
53
|
+
});
|
|
54
|
+
remaining = remaining.slice(fnMatch[0].length);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const mathMatch = remaining.match(/^\$([^$\n]+?)\$/);
|
|
58
|
+
if (mathMatch && !mathMatch[1].startsWith("$")) {
|
|
59
|
+
spans.push({
|
|
60
|
+
type: "mathInline",
|
|
61
|
+
content: mathMatch[1]
|
|
62
|
+
});
|
|
63
|
+
remaining = remaining.slice(mathMatch[0].length);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
169
66
|
const linkMatch = remaining.match(/^\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/);
|
|
170
67
|
if (linkMatch) {
|
|
171
68
|
spans.push({
|
|
@@ -265,7 +162,7 @@ function parseInlineSpans(text) {
|
|
|
265
162
|
remaining = remaining.slice(fullTag.length);
|
|
266
163
|
continue;
|
|
267
164
|
}
|
|
268
|
-
const nextSpecial = remaining.search(/[\*\_\[
|
|
165
|
+
const nextSpecial = remaining.search(/[\*\_\[\!`~<\$]/);
|
|
269
166
|
if (nextSpecial === -1) {
|
|
270
167
|
spans.push({
|
|
271
168
|
type: "text",
|
|
@@ -291,6 +188,35 @@ function parseInlineSpans(text) {
|
|
|
291
188
|
function slugify(text) {
|
|
292
189
|
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
293
190
|
}
|
|
191
|
+
function applyHeadingNumbering(nodes, tocEntries, options) {
|
|
192
|
+
const depth = options.depth ?? 3;
|
|
193
|
+
const skipH1 = options.skipH1 ?? false;
|
|
194
|
+
const prefix = options.prefix ?? "";
|
|
195
|
+
const counters = [0, 0, 0, 0, 0, 0];
|
|
196
|
+
for (const node of nodes) {
|
|
197
|
+
if (node.type === "heading" && node.level) {
|
|
198
|
+
const lvl = node.level;
|
|
199
|
+
if (lvl > depth) continue;
|
|
200
|
+
if (lvl === 1 && skipH1) continue;
|
|
201
|
+
const idx = lvl - 1;
|
|
202
|
+
counters[idx]++;
|
|
203
|
+
for (let c = idx + 1; c < counters.length; c++) {
|
|
204
|
+
counters[c] = 0;
|
|
205
|
+
}
|
|
206
|
+
const startIdx = skipH1 ? 1 : 0;
|
|
207
|
+
const parts = counters.slice(startIdx, idx + 1).filter((n) => n > 0);
|
|
208
|
+
const numberStr = parts.join(".") + ".";
|
|
209
|
+
const fullPrefix = prefix ? `${prefix} ${numberStr} ` : `${numberStr} `;
|
|
210
|
+
const originalText = node.text || "";
|
|
211
|
+
node.text = fullPrefix + originalText;
|
|
212
|
+
node.inlines = parseInlineSpans(node.text);
|
|
213
|
+
const toc = tocEntries.find((t) => t.id === node.id);
|
|
214
|
+
if (toc) {
|
|
215
|
+
toc.text = node.text;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
294
220
|
function parseMarkdownDocument(rawMarkdown) {
|
|
295
221
|
const { data: frontmatter, content } = matter(rawMarkdown);
|
|
296
222
|
const metadata = frontmatter || {};
|
|
@@ -302,6 +228,7 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
302
228
|
const lines = cleanContent.split(/\r?\n/);
|
|
303
229
|
const nodes = [];
|
|
304
230
|
const tocEntries = [];
|
|
231
|
+
const footnoteDefs = [];
|
|
305
232
|
let i = 0;
|
|
306
233
|
while (i < lines.length) {
|
|
307
234
|
const line = lines[i];
|
|
@@ -330,6 +257,29 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
330
257
|
i++;
|
|
331
258
|
continue;
|
|
332
259
|
}
|
|
260
|
+
if (line.trim().startsWith("$$")) {
|
|
261
|
+
const mathLines = [];
|
|
262
|
+
const singleLine = line.trim().match(/^\$\$(.+)\$\$$/);
|
|
263
|
+
if (singleLine) {
|
|
264
|
+
nodes.push({
|
|
265
|
+
type: "mathBlock",
|
|
266
|
+
text: singleLine[1].trim()
|
|
267
|
+
});
|
|
268
|
+
i++;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
i++;
|
|
272
|
+
while (i < lines.length && !lines[i].trim().startsWith("$$")) {
|
|
273
|
+
mathLines.push(lines[i]);
|
|
274
|
+
i++;
|
|
275
|
+
}
|
|
276
|
+
if (i < lines.length) i++;
|
|
277
|
+
nodes.push({
|
|
278
|
+
type: "mathBlock",
|
|
279
|
+
text: mathLines.join("\n").trim()
|
|
280
|
+
});
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
333
283
|
const codeBlockMatch = line.match(/^```(\w+)?/);
|
|
334
284
|
if (codeBlockMatch) {
|
|
335
285
|
const language = (codeBlockMatch[1] || "text").trim().toLowerCase();
|
|
@@ -356,6 +306,100 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
356
306
|
}
|
|
357
307
|
continue;
|
|
358
308
|
}
|
|
309
|
+
const colsMatch = line.trim().match(/^:::columns(?:\s+\[?([\w\s=.-]+)\]?)?$/i);
|
|
310
|
+
if (colsMatch) {
|
|
311
|
+
const attrStr = colsMatch[1] || "";
|
|
312
|
+
let colsCount = 2;
|
|
313
|
+
let colGap = "1.5rem";
|
|
314
|
+
if (attrStr) {
|
|
315
|
+
const numMatch = attrStr.trim().match(/^(\d+)$/);
|
|
316
|
+
const cMatch = attrStr.match(/cols=(\d+)/i) || attrStr.match(/columns=(\d+)/i);
|
|
317
|
+
const gMatch = attrStr.match(/gap=([^\s]+)/i);
|
|
318
|
+
if (numMatch) colsCount = parseInt(numMatch[1], 10);
|
|
319
|
+
else if (cMatch) colsCount = parseInt(cMatch[1], 10);
|
|
320
|
+
if (gMatch) colGap = gMatch[1];
|
|
321
|
+
}
|
|
322
|
+
const columnNodes = [];
|
|
323
|
+
let currentColumnLines = [];
|
|
324
|
+
let inColBlock = false;
|
|
325
|
+
i++;
|
|
326
|
+
while (i < lines.length) {
|
|
327
|
+
const curLine = lines[i];
|
|
328
|
+
const trimmed = curLine.trim();
|
|
329
|
+
if (/^:::col(?:umn)?$/i.test(trimmed)) {
|
|
330
|
+
if (currentColumnLines.length > 0) {
|
|
331
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
332
|
+
columnNodes.push({
|
|
333
|
+
type: "column",
|
|
334
|
+
children: subDoc.nodes
|
|
335
|
+
});
|
|
336
|
+
currentColumnLines = [];
|
|
337
|
+
}
|
|
338
|
+
inColBlock = true;
|
|
339
|
+
i++;
|
|
340
|
+
} else if (trimmed === ":::") {
|
|
341
|
+
if (inColBlock) {
|
|
342
|
+
if (currentColumnLines.length > 0) {
|
|
343
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
344
|
+
columnNodes.push({
|
|
345
|
+
type: "column",
|
|
346
|
+
children: subDoc.nodes
|
|
347
|
+
});
|
|
348
|
+
currentColumnLines = [];
|
|
349
|
+
}
|
|
350
|
+
inColBlock = false;
|
|
351
|
+
i++;
|
|
352
|
+
} else {
|
|
353
|
+
if (currentColumnLines.length > 0) {
|
|
354
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
355
|
+
columnNodes.push({
|
|
356
|
+
type: "column",
|
|
357
|
+
children: subDoc.nodes
|
|
358
|
+
});
|
|
359
|
+
currentColumnLines = [];
|
|
360
|
+
}
|
|
361
|
+
i++;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
} else {
|
|
365
|
+
currentColumnLines.push(curLine);
|
|
366
|
+
i++;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (currentColumnLines.length > 0) {
|
|
370
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
371
|
+
columnNodes.push({
|
|
372
|
+
type: "column",
|
|
373
|
+
children: subDoc.nodes
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
nodes.push({
|
|
377
|
+
type: "columns",
|
|
378
|
+
columnsCount: columnNodes.length > 0 ? columnNodes.length : colsCount,
|
|
379
|
+
columnGap: colGap,
|
|
380
|
+
children: columnNodes
|
|
381
|
+
});
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const fnDefMatch = line.match(/^\[\^([\w-]+)\]:\s+(.+)$/);
|
|
385
|
+
if (fnDefMatch) {
|
|
386
|
+
const fnId = fnDefMatch[1];
|
|
387
|
+
const fnText = fnDefMatch[2].trim();
|
|
388
|
+
const inlines = parseInlineSpans(fnText);
|
|
389
|
+
footnoteDefs.push({
|
|
390
|
+
id: fnId,
|
|
391
|
+
text: fnText,
|
|
392
|
+
inlines
|
|
393
|
+
});
|
|
394
|
+
nodes.push({
|
|
395
|
+
type: "footnoteDef",
|
|
396
|
+
footnoteId: fnId,
|
|
397
|
+
text: fnText,
|
|
398
|
+
inlines
|
|
399
|
+
});
|
|
400
|
+
i++;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
359
403
|
const calloutMatch = line.match(/^>\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*$/i);
|
|
360
404
|
if (calloutMatch) {
|
|
361
405
|
const calloutType = calloutMatch[1].toUpperCase();
|
|
@@ -479,7 +523,7 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
479
523
|
continue;
|
|
480
524
|
}
|
|
481
525
|
const paraLines = [];
|
|
482
|
-
while (i < lines.length && lines[i].trim() && !lines[i].match(/^#{1,6}\s+/) && !lines[i].startsWith("```") && !lines[i].startsWith(">") && !lines[i].trim().startsWith("|") && !lines[i].match(/^(\s*)([-*+]|\d+\.)\s+/)) {
|
|
526
|
+
while (i < lines.length && lines[i].trim() && !lines[i].match(/^#{1,6}\s+/) && !lines[i].startsWith("```") && !lines[i].startsWith("$$") && !lines[i].startsWith(">") && !lines[i].trim().startsWith("|") && !lines[i].match(/^:::columns/) && !lines[i].match(/^\[\^[\w-]+\]:\s+/) && !lines[i].match(/^(\s*)([-*+]|\d+\.)\s+/)) {
|
|
483
527
|
paraLines.push(lines[i]);
|
|
484
528
|
i++;
|
|
485
529
|
}
|
|
@@ -490,39 +534,25 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
490
534
|
inlines: parseInlineSpans(paraText)
|
|
491
535
|
});
|
|
492
536
|
}
|
|
537
|
+
if (metadata.numberHeadings) {
|
|
538
|
+
const opts = typeof metadata.numberHeadings === "boolean" ? { enabled: metadata.numberHeadings } : metadata.numberHeadings;
|
|
539
|
+
if (opts.enabled !== false) {
|
|
540
|
+
applyHeadingNumbering(nodes, tocEntries, opts);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
493
543
|
return {
|
|
494
544
|
metadata,
|
|
495
545
|
content: cleanContent,
|
|
496
546
|
nodes,
|
|
497
547
|
tocEntries,
|
|
498
|
-
inlinedStyles
|
|
548
|
+
inlinedStyles,
|
|
549
|
+
footnoteDefs
|
|
499
550
|
};
|
|
500
551
|
}
|
|
501
552
|
|
|
502
|
-
// src/core/
|
|
503
|
-
import
|
|
504
|
-
|
|
505
|
-
Paragraph,
|
|
506
|
-
TextRun,
|
|
507
|
-
HeadingLevel,
|
|
508
|
-
Table,
|
|
509
|
-
TableRow,
|
|
510
|
-
TableCell,
|
|
511
|
-
WidthType,
|
|
512
|
-
BorderStyle,
|
|
513
|
-
AlignmentType,
|
|
514
|
-
ImageRun,
|
|
515
|
-
Header as Header2,
|
|
516
|
-
Footer,
|
|
517
|
-
PageNumber,
|
|
518
|
-
Packer,
|
|
519
|
-
PageOrientation,
|
|
520
|
-
convertInchesToTwip,
|
|
521
|
-
convertMillimetersToTwip,
|
|
522
|
-
ShadingType,
|
|
523
|
-
ExternalHyperlink,
|
|
524
|
-
TabStopType
|
|
525
|
-
} from "docx";
|
|
553
|
+
// src/core/html/htmlBuilder.ts
|
|
554
|
+
import * as fs2 from "fs";
|
|
555
|
+
import * as path2 from "path";
|
|
526
556
|
|
|
527
557
|
// src/core/imageResolver.ts
|
|
528
558
|
import * as fs from "fs";
|
|
@@ -583,9 +613,14 @@ async function resolveImage(src, baseDir = process.cwd()) {
|
|
|
583
613
|
memoryImageCache.set(cacheKey, resolved2);
|
|
584
614
|
return resolved2;
|
|
585
615
|
}
|
|
586
|
-
|
|
616
|
+
let localPath = path.isAbsolute(src) ? src : path.resolve(baseDir, src);
|
|
587
617
|
if (!fs.existsSync(localPath)) {
|
|
588
|
-
|
|
618
|
+
const cwdPath = path.resolve(process.cwd(), src);
|
|
619
|
+
if (fs.existsSync(cwdPath)) {
|
|
620
|
+
localPath = cwdPath;
|
|
621
|
+
} else {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
589
624
|
}
|
|
590
625
|
const buffer = fs.readFileSync(localPath);
|
|
591
626
|
const mimeType = getMimeType(localPath);
|
|
@@ -605,6 +640,164 @@ async function resolveImage(src, baseDir = process.cwd()) {
|
|
|
605
640
|
}
|
|
606
641
|
}
|
|
607
642
|
|
|
643
|
+
// src/core/html/htmlThemes.ts
|
|
644
|
+
var THEME_COMPONENTS = `
|
|
645
|
+
/* Fallback CSS variables \u2014 overridden by each named theme's :root block */
|
|
646
|
+
:root {
|
|
647
|
+
--mf-bg: #ffffff;
|
|
648
|
+
--mf-text: #0f172a;
|
|
649
|
+
--mf-text-muted: #64748b;
|
|
650
|
+
--mf-primary: #33CDCF;
|
|
651
|
+
--mf-primary-dark: #009DA0;
|
|
652
|
+
--mf-primary-light: #ECFDFD;
|
|
653
|
+
--mf-border: #e2e8f0;
|
|
654
|
+
--mf-card-bg: #f8fafc;
|
|
655
|
+
--mf-code-bg: #0f172a;
|
|
656
|
+
--mf-code-text: #f8fafc;
|
|
657
|
+
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
658
|
+
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/* Document header */
|
|
662
|
+
.document-header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 2px solid var(--mf-border); }
|
|
663
|
+
.document-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 0.5rem 0; }
|
|
664
|
+
.document-subtitle { font-size: 1.25rem; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
665
|
+
.document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
|
|
666
|
+
|
|
667
|
+
/* Table of Contents */
|
|
668
|
+
.table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; }
|
|
669
|
+
.table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
670
|
+
.table-of-contents ul { list-style: none; padding: 0; margin: 0; }
|
|
671
|
+
.table-of-contents li { padding: 0.25rem 0; }
|
|
672
|
+
.table-of-contents a { color: var(--mf-primary-dark); text-decoration: none; }
|
|
673
|
+
.table-of-contents a:hover { text-decoration: underline; }
|
|
674
|
+
|
|
675
|
+
/* Links */
|
|
676
|
+
a { color: var(--mf-primary-dark); font-weight: 600; text-decoration: none; }
|
|
677
|
+
a:hover { text-decoration: underline; }
|
|
678
|
+
|
|
679
|
+
/* Blockquote */
|
|
680
|
+
blockquote { border-left: 4px solid var(--mf-primary); background-color: var(--mf-card-bg); margin: 1.2rem 0; padding: 0.8rem 1.2rem; border-radius: 0 8px 8px 0; color: #334155; font-style: italic; }
|
|
681
|
+
|
|
682
|
+
/* Callout / Alert Boxes */
|
|
683
|
+
.callout { border-left: 4px solid var(--mf-primary); background: var(--mf-card-bg); border-radius: 6px; padding: 1rem 1.2rem; margin: 1.2rem 0; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
684
|
+
.callout-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
|
|
685
|
+
.callout-NOTE { border-color: #33CDCF; background: #ECFDFD; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
686
|
+
.callout-NOTE .callout-title { color: #009DA0; }
|
|
687
|
+
.callout-TIP { border-color: #10b981; background: #ecfdf5; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
688
|
+
.callout-TIP .callout-title { color: #10b981; }
|
|
689
|
+
.callout-WARNING { border-color: #f59e0b; background: #fffbeb; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
690
|
+
.callout-WARNING .callout-title { color: #f59e0b; }
|
|
691
|
+
.callout-CAUTION { border-color: #ef4444; background: #fef2f2; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
692
|
+
.callout-CAUTION .callout-title { color: #ef4444; }
|
|
693
|
+
.callout-IMPORTANT { border-color: #8b5cf6; background: #f5f3ff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
694
|
+
.callout-IMPORTANT .callout-title { color: #8b5cf6; }
|
|
695
|
+
|
|
696
|
+
/* Inline Code */
|
|
697
|
+
code { font-family: var(--mf-font-mono); font-size: 0.88em; background-color: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; color: #0f172a; }
|
|
698
|
+
|
|
699
|
+
/* Code Blocks */
|
|
700
|
+
pre { background-color: var(--mf-code-bg); color: var(--mf-code-text); padding: 1.2rem; border-radius: 8px; overflow-x: auto; font-family: var(--mf-font-mono); font-size: 0.9rem; line-height: 1.5; margin: 1.2rem 0; }
|
|
701
|
+
pre code { background-color: transparent; color: inherit; padding: 0; }
|
|
702
|
+
|
|
703
|
+
/* Tables */
|
|
704
|
+
table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
|
|
705
|
+
th, td { border: 1px solid var(--mf-border); padding: 0.75rem 1rem; text-align: left; }
|
|
706
|
+
th { background-color: var(--mf-card-bg); font-weight: 600; color: #0f172a; }
|
|
707
|
+
tr:nth-child(even) { background-color: var(--mf-card-bg); }
|
|
708
|
+
|
|
709
|
+
/* Images */
|
|
710
|
+
img { max-width: 100%; height: auto; border-radius: 6px; margin: 1rem 0; }
|
|
711
|
+
|
|
712
|
+
/* Dividers */
|
|
713
|
+
hr { border: none; border-top: 1px solid var(--mf-border); margin: 2rem 0; }
|
|
714
|
+
|
|
715
|
+
/* Print / PDF */
|
|
716
|
+
@media print {
|
|
717
|
+
body { padding: 0; }
|
|
718
|
+
.document-container { max-width: 100%; }
|
|
719
|
+
pre, table, blockquote, .callout { break-inside: avoid; }
|
|
720
|
+
/* Remove scrollbars \u2014 PDF has no scrolling */
|
|
721
|
+
pre { overflow: visible; white-space: pre-wrap; word-break: break-all; }
|
|
722
|
+
}
|
|
723
|
+
`;
|
|
724
|
+
var THEME_CORPORATE = `
|
|
725
|
+
:root {
|
|
726
|
+
--mf-bg: #ffffff;
|
|
727
|
+
--mf-text: #0f172a;
|
|
728
|
+
--mf-text-muted: #64748b;
|
|
729
|
+
--mf-primary: #33CDCF;
|
|
730
|
+
--mf-primary-dark: #009DA0;
|
|
731
|
+
--mf-primary-light: #ECFDFD;
|
|
732
|
+
--mf-border: #e2e8f0;
|
|
733
|
+
--mf-card-bg: #f8fafc;
|
|
734
|
+
--mf-code-bg: #0f172a;
|
|
735
|
+
--mf-code-text: #f8fafc;
|
|
736
|
+
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
737
|
+
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
738
|
+
}
|
|
739
|
+
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
740
|
+
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
741
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
742
|
+
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
743
|
+
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
|
|
744
|
+
h3 { font-size: 1.3rem; }
|
|
745
|
+
h4 { font-size: 1.1rem; }
|
|
746
|
+
p { margin: 0.8rem 0; }
|
|
747
|
+
`;
|
|
748
|
+
var THEMES = {
|
|
749
|
+
corporate: THEME_CORPORATE,
|
|
750
|
+
default: THEME_CORPORATE
|
|
751
|
+
};
|
|
752
|
+
function generateThemeCss(theme) {
|
|
753
|
+
if (!theme || theme === "corporate" || theme === "default" || theme === "corporate" /* CORPORATE */) {
|
|
754
|
+
return THEME_CORPORATE;
|
|
755
|
+
}
|
|
756
|
+
if (typeof theme === "object") {
|
|
757
|
+
const bg = theme.backgroundColor || "#ffffff";
|
|
758
|
+
const text = theme.textColor || "#0f172a";
|
|
759
|
+
const textMuted = theme.textMuted || "#64748b";
|
|
760
|
+
const primary = theme.primaryColor || "#33CDCF";
|
|
761
|
+
const primaryDark = theme.primaryDark || primary;
|
|
762
|
+
const primaryLight = theme.primaryLight || "#ECFDFD";
|
|
763
|
+
const border = theme.borderColor || "#e2e8f0";
|
|
764
|
+
const cardBg = theme.cardBackground || "#f8fafc";
|
|
765
|
+
const codeBg = theme.codeBackground || "#0f172a";
|
|
766
|
+
const codeText = theme.codeText || "#f8fafc";
|
|
767
|
+
const font = theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
768
|
+
const fontMono = theme.fontMono || "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
|
|
769
|
+
return `
|
|
770
|
+
:root {
|
|
771
|
+
--mf-bg: ${bg};
|
|
772
|
+
--mf-text: ${text};
|
|
773
|
+
--mf-text-muted: ${textMuted};
|
|
774
|
+
--mf-primary: ${primary};
|
|
775
|
+
--mf-primary-dark: ${primaryDark};
|
|
776
|
+
--mf-primary-light: ${primaryLight};
|
|
777
|
+
--mf-border: ${border};
|
|
778
|
+
--mf-card-bg: ${cardBg};
|
|
779
|
+
--mf-code-bg: ${codeBg};
|
|
780
|
+
--mf-code-text: ${codeText};
|
|
781
|
+
--mf-font-family: ${font};
|
|
782
|
+
--mf-font-mono: ${fontMono};
|
|
783
|
+
}
|
|
784
|
+
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
785
|
+
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
786
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
787
|
+
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
788
|
+
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
|
|
789
|
+
h3 { font-size: 1.3rem; }
|
|
790
|
+
h4 { font-size: 1.1rem; }
|
|
791
|
+
p { margin: 0.8rem 0; }
|
|
792
|
+
${theme.customCss || ""}
|
|
793
|
+
`;
|
|
794
|
+
}
|
|
795
|
+
if (typeof theme === "string" && THEMES[theme]) {
|
|
796
|
+
return THEMES[theme];
|
|
797
|
+
}
|
|
798
|
+
return THEME_CORPORATE;
|
|
799
|
+
}
|
|
800
|
+
|
|
608
801
|
// src/core/syntax/syntaxHighlighter.ts
|
|
609
802
|
var SYNTAX_COLORS = {
|
|
610
803
|
keyword: "FF7B72",
|
|
@@ -960,182 +1153,6 @@ function highlightCodeToHtml(code, lang = "", theme = "github-dark") {
|
|
|
960
1153
|
return htmlLines.join("\n");
|
|
961
1154
|
}
|
|
962
1155
|
|
|
963
|
-
// src/core/mermaid/mermaidRenderer.ts
|
|
964
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
965
|
-
import * as fs4 from "fs";
|
|
966
|
-
import * as os2 from "os";
|
|
967
|
-
import * as path4 from "path";
|
|
968
|
-
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
969
|
-
|
|
970
|
-
// src/core/pdf/pdfBuilder.ts
|
|
971
|
-
import * as fs3 from "fs";
|
|
972
|
-
import * as path3 from "path";
|
|
973
|
-
import * as os from "os";
|
|
974
|
-
import { pathToFileURL } from "url";
|
|
975
|
-
import { spawnSync } from "child_process";
|
|
976
|
-
|
|
977
|
-
// src/core/html/htmlBuilder.ts
|
|
978
|
-
import * as fs2 from "fs";
|
|
979
|
-
import * as path2 from "path";
|
|
980
|
-
|
|
981
|
-
// src/core/html/htmlThemes.ts
|
|
982
|
-
var THEME_COMPONENTS = `
|
|
983
|
-
/* Fallback CSS variables \u2014 overridden by each named theme's :root block */
|
|
984
|
-
:root {
|
|
985
|
-
--mf-bg: #ffffff;
|
|
986
|
-
--mf-text: #0f172a;
|
|
987
|
-
--mf-text-muted: #64748b;
|
|
988
|
-
--mf-primary: #33CDCF;
|
|
989
|
-
--mf-primary-dark: #009DA0;
|
|
990
|
-
--mf-primary-light: #ECFDFD;
|
|
991
|
-
--mf-border: #e2e8f0;
|
|
992
|
-
--mf-card-bg: #f8fafc;
|
|
993
|
-
--mf-code-bg: #0f172a;
|
|
994
|
-
--mf-code-text: #f8fafc;
|
|
995
|
-
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
996
|
-
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
/* Document header */
|
|
1000
|
-
.document-header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 2px solid var(--mf-border); }
|
|
1001
|
-
.document-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 0.5rem 0; }
|
|
1002
|
-
.document-subtitle { font-size: 1.25rem; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
1003
|
-
.document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
|
|
1004
|
-
|
|
1005
|
-
/* Table of Contents */
|
|
1006
|
-
.table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; }
|
|
1007
|
-
.table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
1008
|
-
.table-of-contents ul { list-style: none; padding: 0; margin: 0; }
|
|
1009
|
-
.table-of-contents li { padding: 0.25rem 0; }
|
|
1010
|
-
.table-of-contents a { color: var(--mf-primary-dark); text-decoration: none; }
|
|
1011
|
-
.table-of-contents a:hover { text-decoration: underline; }
|
|
1012
|
-
|
|
1013
|
-
/* Links */
|
|
1014
|
-
a { color: var(--mf-primary-dark); font-weight: 600; text-decoration: none; }
|
|
1015
|
-
a:hover { text-decoration: underline; }
|
|
1016
|
-
|
|
1017
|
-
/* Blockquote */
|
|
1018
|
-
blockquote { border-left: 4px solid var(--mf-primary); background-color: var(--mf-card-bg); margin: 1.2rem 0; padding: 0.8rem 1.2rem; border-radius: 0 8px 8px 0; color: #334155; font-style: italic; }
|
|
1019
|
-
|
|
1020
|
-
/* Callout / Alert Boxes */
|
|
1021
|
-
.callout { border-left: 4px solid var(--mf-primary); background: var(--mf-card-bg); border-radius: 6px; padding: 1rem 1.2rem; margin: 1.2rem 0; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1022
|
-
.callout-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
|
|
1023
|
-
.callout-NOTE { border-color: #33CDCF; background: #ECFDFD; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1024
|
-
.callout-NOTE .callout-title { color: #009DA0; }
|
|
1025
|
-
.callout-TIP { border-color: #10b981; background: #ecfdf5; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1026
|
-
.callout-TIP .callout-title { color: #10b981; }
|
|
1027
|
-
.callout-WARNING { border-color: #f59e0b; background: #fffbeb; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1028
|
-
.callout-WARNING .callout-title { color: #f59e0b; }
|
|
1029
|
-
.callout-CAUTION { border-color: #ef4444; background: #fef2f2; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1030
|
-
.callout-CAUTION .callout-title { color: #ef4444; }
|
|
1031
|
-
.callout-IMPORTANT { border-color: #8b5cf6; background: #f5f3ff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1032
|
-
.callout-IMPORTANT .callout-title { color: #8b5cf6; }
|
|
1033
|
-
|
|
1034
|
-
/* Inline Code */
|
|
1035
|
-
code { font-family: var(--mf-font-mono); font-size: 0.88em; background-color: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; color: #0f172a; }
|
|
1036
|
-
|
|
1037
|
-
/* Code Blocks */
|
|
1038
|
-
pre { background-color: var(--mf-code-bg); color: var(--mf-code-text); padding: 1.2rem; border-radius: 8px; overflow-x: auto; font-family: var(--mf-font-mono); font-size: 0.9rem; line-height: 1.5; margin: 1.2rem 0; }
|
|
1039
|
-
pre code { background-color: transparent; color: inherit; padding: 0; }
|
|
1040
|
-
|
|
1041
|
-
/* Tables */
|
|
1042
|
-
table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
|
|
1043
|
-
th, td { border: 1px solid var(--mf-border); padding: 0.75rem 1rem; text-align: left; }
|
|
1044
|
-
th { background-color: var(--mf-card-bg); font-weight: 600; color: #0f172a; }
|
|
1045
|
-
tr:nth-child(even) { background-color: var(--mf-card-bg); }
|
|
1046
|
-
|
|
1047
|
-
/* Images */
|
|
1048
|
-
img { max-width: 100%; height: auto; border-radius: 6px; margin: 1rem 0; }
|
|
1049
|
-
|
|
1050
|
-
/* Dividers */
|
|
1051
|
-
hr { border: none; border-top: 1px solid var(--mf-border); margin: 2rem 0; }
|
|
1052
|
-
|
|
1053
|
-
/* Print / PDF */
|
|
1054
|
-
@media print {
|
|
1055
|
-
body { padding: 0; }
|
|
1056
|
-
.document-container { max-width: 100%; }
|
|
1057
|
-
pre, table, blockquote, .callout { break-inside: avoid; }
|
|
1058
|
-
/* Remove scrollbars \u2014 PDF has no scrolling */
|
|
1059
|
-
pre { overflow: visible; white-space: pre-wrap; word-break: break-all; }
|
|
1060
|
-
}
|
|
1061
|
-
`;
|
|
1062
|
-
var THEME_CORPORATE = `
|
|
1063
|
-
:root {
|
|
1064
|
-
--mf-bg: #ffffff;
|
|
1065
|
-
--mf-text: #0f172a;
|
|
1066
|
-
--mf-text-muted: #64748b;
|
|
1067
|
-
--mf-primary: #33CDCF;
|
|
1068
|
-
--mf-primary-dark: #009DA0;
|
|
1069
|
-
--mf-primary-light: #ECFDFD;
|
|
1070
|
-
--mf-border: #e2e8f0;
|
|
1071
|
-
--mf-card-bg: #f8fafc;
|
|
1072
|
-
--mf-code-bg: #0f172a;
|
|
1073
|
-
--mf-code-text: #f8fafc;
|
|
1074
|
-
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1075
|
-
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
1076
|
-
}
|
|
1077
|
-
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
1078
|
-
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
1079
|
-
h1, h2, h3, h4, h5, h6 { color: var(--mf-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
1080
|
-
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
1081
|
-
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
|
|
1082
|
-
h3 { font-size: 1.3rem; }
|
|
1083
|
-
h4 { font-size: 1.1rem; }
|
|
1084
|
-
p { margin: 0.8rem 0; }
|
|
1085
|
-
`;
|
|
1086
|
-
var THEMES = {
|
|
1087
|
-
corporate: THEME_CORPORATE,
|
|
1088
|
-
default: THEME_CORPORATE
|
|
1089
|
-
};
|
|
1090
|
-
function generateThemeCss(theme) {
|
|
1091
|
-
if (!theme || theme === "corporate" || theme === "default" || theme === "corporate" /* CORPORATE */) {
|
|
1092
|
-
return THEME_CORPORATE;
|
|
1093
|
-
}
|
|
1094
|
-
if (typeof theme === "object") {
|
|
1095
|
-
const bg = theme.backgroundColor || "#ffffff";
|
|
1096
|
-
const text = theme.textColor || "#0f172a";
|
|
1097
|
-
const textMuted = theme.textMuted || "#64748b";
|
|
1098
|
-
const primary = theme.primaryColor || "#33CDCF";
|
|
1099
|
-
const primaryDark = theme.primaryDark || primary;
|
|
1100
|
-
const primaryLight = theme.primaryLight || "#ECFDFD";
|
|
1101
|
-
const border = theme.borderColor || "#e2e8f0";
|
|
1102
|
-
const cardBg = theme.cardBackground || "#f8fafc";
|
|
1103
|
-
const codeBg = theme.codeBackground || "#0f172a";
|
|
1104
|
-
const codeText = theme.codeText || "#f8fafc";
|
|
1105
|
-
const font = theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
1106
|
-
const fontMono = theme.fontMono || "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
|
|
1107
|
-
return `
|
|
1108
|
-
:root {
|
|
1109
|
-
--mf-bg: ${bg};
|
|
1110
|
-
--mf-text: ${text};
|
|
1111
|
-
--mf-text-muted: ${textMuted};
|
|
1112
|
-
--mf-primary: ${primary};
|
|
1113
|
-
--mf-primary-dark: ${primaryDark};
|
|
1114
|
-
--mf-primary-light: ${primaryLight};
|
|
1115
|
-
--mf-border: ${border};
|
|
1116
|
-
--mf-card-bg: ${cardBg};
|
|
1117
|
-
--mf-code-bg: ${codeBg};
|
|
1118
|
-
--mf-code-text: ${codeText};
|
|
1119
|
-
--mf-font-family: ${font};
|
|
1120
|
-
--mf-font-mono: ${fontMono};
|
|
1121
|
-
}
|
|
1122
|
-
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
1123
|
-
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
1124
|
-
h1, h2, h3, h4, h5, h6 { color: var(--mf-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
1125
|
-
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
1126
|
-
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
|
|
1127
|
-
h3 { font-size: 1.3rem; }
|
|
1128
|
-
h4 { font-size: 1.1rem; }
|
|
1129
|
-
p { margin: 0.8rem 0; }
|
|
1130
|
-
${theme.customCss || ""}
|
|
1131
|
-
`;
|
|
1132
|
-
}
|
|
1133
|
-
if (typeof theme === "string" && THEMES[theme]) {
|
|
1134
|
-
return THEMES[theme];
|
|
1135
|
-
}
|
|
1136
|
-
return THEME_CORPORATE;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
1156
|
// src/config/resolveConfig.ts
|
|
1140
1157
|
var PAPER_DIMENSIONS_TWIP = {
|
|
1141
1158
|
A4: { width: 11906, height: 16838 },
|
|
@@ -1181,7 +1198,8 @@ function formatMarginCss(margin, defaultCss = "2.5cm") {
|
|
|
1181
1198
|
return str;
|
|
1182
1199
|
}
|
|
1183
1200
|
function replaceDocumentTokens(template = "", meta) {
|
|
1184
|
-
|
|
1201
|
+
const currentYear = meta.year || (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1202
|
+
return template.replace(/\{title\}/gi, meta.title || "").replace(/\{subtitle\}/gi, meta.subtitle || "").replace(/\{author\}/gi, meta.author || "").replace(/\{version\}/gi, meta.version || "").replace(/\{date\}/gi, meta.date || "").replace(/\{year\}/gi, currentYear).replace(/\{company\}/gi, meta.company || "");
|
|
1185
1203
|
}
|
|
1186
1204
|
function normalizeWatermark(rawWatermark) {
|
|
1187
1205
|
if (!rawWatermark) {
|
|
@@ -1257,6 +1275,190 @@ function normalizeHeaderFooter(raw, meta) {
|
|
|
1257
1275
|
dividerColor: raw.dividerColor || "#E2E8F0"
|
|
1258
1276
|
};
|
|
1259
1277
|
}
|
|
1278
|
+
function normalizeSignatures(raw, meta = {}) {
|
|
1279
|
+
if (!raw) return void 0;
|
|
1280
|
+
let rawItems = [];
|
|
1281
|
+
let rawConfig = {};
|
|
1282
|
+
if (Array.isArray(raw)) {
|
|
1283
|
+
rawItems = raw;
|
|
1284
|
+
} else if (typeof raw === "object" && Array.isArray(raw.items)) {
|
|
1285
|
+
rawItems = raw.items;
|
|
1286
|
+
rawConfig = raw;
|
|
1287
|
+
}
|
|
1288
|
+
if (rawItems.length === 0) return void 0;
|
|
1289
|
+
const cappedItems = rawItems.slice(0, 4);
|
|
1290
|
+
const items = cappedItems.map((item) => {
|
|
1291
|
+
const tokenCtx = meta;
|
|
1292
|
+
const rawName = typeof item.name === "string" ? item.name : "";
|
|
1293
|
+
const name = replaceDocumentTokens(rawName, tokenCtx).trim();
|
|
1294
|
+
const title = item.title ? replaceDocumentTokens(item.title, tokenCtx).trim() : void 0;
|
|
1295
|
+
const role = item.role ? replaceDocumentTokens(item.role, tokenCtx).trim() : void 0;
|
|
1296
|
+
let dateStr;
|
|
1297
|
+
if (typeof item.date === "string") {
|
|
1298
|
+
dateStr = replaceDocumentTokens(item.date, tokenCtx).trim();
|
|
1299
|
+
} else if (item.date === true) {
|
|
1300
|
+
dateStr = meta.date || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1301
|
+
}
|
|
1302
|
+
let signatureHeight = 60;
|
|
1303
|
+
if (typeof item.signatureHeight === "number") {
|
|
1304
|
+
signatureHeight = item.signatureHeight;
|
|
1305
|
+
} else if (typeof item.signatureHeight === "string") {
|
|
1306
|
+
const parsed = parseFloat(item.signatureHeight);
|
|
1307
|
+
if (!isNaN(parsed)) signatureHeight = parsed;
|
|
1308
|
+
}
|
|
1309
|
+
return {
|
|
1310
|
+
title,
|
|
1311
|
+
name: name || "Authorized Signatory",
|
|
1312
|
+
role,
|
|
1313
|
+
date: dateStr,
|
|
1314
|
+
image: item.image,
|
|
1315
|
+
signatureHeight
|
|
1316
|
+
};
|
|
1317
|
+
});
|
|
1318
|
+
const align = rawConfig.align || (items.length === 1 ? "right" : "space-between");
|
|
1319
|
+
const style = rawConfig.style || "line";
|
|
1320
|
+
const borderColor = rawConfig.borderColor || "#CBD5E1";
|
|
1321
|
+
const titleColor = rawConfig.titleColor || "#64748B";
|
|
1322
|
+
const nameColor = rawConfig.nameColor || "#0F172A";
|
|
1323
|
+
const roleColor = rawConfig.roleColor || "#64748B";
|
|
1324
|
+
const spacingBeforeRaw = rawConfig.spacingBefore ?? "2.5rem";
|
|
1325
|
+
const spacingBefore = formatMarginCss(spacingBeforeRaw, "2.5rem");
|
|
1326
|
+
const spacingBeforeTwip = parseMarginToTwip(spacingBeforeRaw, 600);
|
|
1327
|
+
return {
|
|
1328
|
+
items,
|
|
1329
|
+
align,
|
|
1330
|
+
style,
|
|
1331
|
+
borderColor,
|
|
1332
|
+
titleColor,
|
|
1333
|
+
nameColor,
|
|
1334
|
+
roleColor,
|
|
1335
|
+
spacingBefore,
|
|
1336
|
+
spacingBeforeTwip
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
function normalizeCoverPage(rawCover, tokenCtx = {}) {
|
|
1340
|
+
if (!rawCover) return void 0;
|
|
1341
|
+
const cfg = typeof rawCover === "object" ? rawCover : {};
|
|
1342
|
+
if (cfg.enabled === false) return void 0;
|
|
1343
|
+
const preset = cfg.preset || "modern";
|
|
1344
|
+
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : tokenCtx.title || "Document Title";
|
|
1345
|
+
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : tokenCtx.subtitle;
|
|
1346
|
+
const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author;
|
|
1347
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
|
|
1348
|
+
const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version;
|
|
1349
|
+
let dateStr;
|
|
1350
|
+
if (typeof cfg.date === "string") {
|
|
1351
|
+
dateStr = replaceDocumentTokens(cfg.date, tokenCtx);
|
|
1352
|
+
} else if (cfg.date === true) {
|
|
1353
|
+
dateStr = tokenCtx.date || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1354
|
+
} else {
|
|
1355
|
+
dateStr = tokenCtx.date;
|
|
1356
|
+
}
|
|
1357
|
+
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1358
|
+
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1359
|
+
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1360
|
+
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1361
|
+
const logoWidth = cfg.logoWidth;
|
|
1362
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
|
|
1363
|
+
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1364
|
+
const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
|
|
1365
|
+
return {
|
|
1366
|
+
enabled: true,
|
|
1367
|
+
preset,
|
|
1368
|
+
title,
|
|
1369
|
+
subtitle,
|
|
1370
|
+
author,
|
|
1371
|
+
company,
|
|
1372
|
+
version,
|
|
1373
|
+
date: dateStr,
|
|
1374
|
+
badge,
|
|
1375
|
+
badgeColor,
|
|
1376
|
+
badgeTextColor,
|
|
1377
|
+
logo,
|
|
1378
|
+
logoWidth,
|
|
1379
|
+
bgGradient,
|
|
1380
|
+
textColor,
|
|
1381
|
+
footerText
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
function normalizeBackCover(rawBack, tokenCtx = {}) {
|
|
1385
|
+
if (!rawBack) return void 0;
|
|
1386
|
+
const cfg = typeof rawBack === "object" ? rawBack : {};
|
|
1387
|
+
if (cfg.enabled === false) return void 0;
|
|
1388
|
+
const preset = cfg.preset || "modern";
|
|
1389
|
+
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : "Thank You";
|
|
1390
|
+
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : void 0;
|
|
1391
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
|
|
1392
|
+
const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
|
|
1393
|
+
const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
|
|
1394
|
+
const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
|
|
1395
|
+
const website = cfg.website ? replaceDocumentTokens(String(cfg.website), tokenCtx) : void 0;
|
|
1396
|
+
let socialMap;
|
|
1397
|
+
if (cfg.social && typeof cfg.social === "object") {
|
|
1398
|
+
socialMap = {};
|
|
1399
|
+
for (const [k, v] of Object.entries(cfg.social)) {
|
|
1400
|
+
if (typeof v === "string") {
|
|
1401
|
+
socialMap[k] = replaceDocumentTokens(v, tokenCtx);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1406
|
+
const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : company ? `Copyright (c) ${currentYear} ${company}. All Rights Reserved.` : void 0;
|
|
1407
|
+
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1408
|
+
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1409
|
+
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1410
|
+
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1411
|
+
const logoWidth = cfg.logoWidth;
|
|
1412
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
|
|
1413
|
+
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1414
|
+
return {
|
|
1415
|
+
enabled: true,
|
|
1416
|
+
preset,
|
|
1417
|
+
title,
|
|
1418
|
+
subtitle,
|
|
1419
|
+
company,
|
|
1420
|
+
address,
|
|
1421
|
+
email,
|
|
1422
|
+
phone,
|
|
1423
|
+
website,
|
|
1424
|
+
social: socialMap,
|
|
1425
|
+
copyright,
|
|
1426
|
+
badge,
|
|
1427
|
+
badgeColor,
|
|
1428
|
+
badgeTextColor,
|
|
1429
|
+
logo,
|
|
1430
|
+
logoWidth,
|
|
1431
|
+
bgGradient,
|
|
1432
|
+
textColor
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
function normalizeNumberHeadings(raw) {
|
|
1436
|
+
if (raw === void 0 || raw === false) return void 0;
|
|
1437
|
+
if (raw === true) {
|
|
1438
|
+
return { enabled: true, depth: 3, skipH1: false, prefix: "" };
|
|
1439
|
+
}
|
|
1440
|
+
if (typeof raw === "object") {
|
|
1441
|
+
const obj = raw;
|
|
1442
|
+
if (obj.enabled === false) return void 0;
|
|
1443
|
+
return {
|
|
1444
|
+
enabled: true,
|
|
1445
|
+
depth: obj.depth ?? 3,
|
|
1446
|
+
skipH1: obj.skipH1 ?? false,
|
|
1447
|
+
prefix: obj.prefix ?? ""
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
return void 0;
|
|
1451
|
+
}
|
|
1452
|
+
function normalizeSecurity(raw) {
|
|
1453
|
+
if (!raw) return void 0;
|
|
1454
|
+
const sec = raw;
|
|
1455
|
+
if (!sec.userPassword && !sec.ownerPassword && !sec.permissions) return void 0;
|
|
1456
|
+
return {
|
|
1457
|
+
userPassword: sec.userPassword,
|
|
1458
|
+
ownerPassword: sec.ownerPassword,
|
|
1459
|
+
permissions: sec.permissions
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1260
1462
|
function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
1261
1463
|
const configMeta = userConfig.metadata || {};
|
|
1262
1464
|
const mergedMeta = { ...configMeta, ...frontmatter };
|
|
@@ -1297,6 +1499,17 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1297
1499
|
const toc = typeof mergedMeta.toc === "boolean" ? mergedMeta.toc : typeof userConfig.toc === "boolean" ? userConfig.toc : DEFAULT_CONFIG.toc;
|
|
1298
1500
|
const rawWatermark = mergedMeta.watermark !== void 0 ? mergedMeta.watermark : userConfig.watermark !== void 0 ? userConfig.watermark : DEFAULT_CONFIG.watermark;
|
|
1299
1501
|
const watermark = normalizeWatermark(rawWatermark);
|
|
1502
|
+
const rawSignatures = mergedMeta.signatures || userConfig.signatures;
|
|
1503
|
+
const signatures = normalizeSignatures(rawSignatures, tokenContext);
|
|
1504
|
+
const rawCover = mergedMeta.coverPage !== void 0 ? mergedMeta.coverPage : userConfig.coverPage;
|
|
1505
|
+
const coverPage = normalizeCoverPage(rawCover, tokenContext);
|
|
1506
|
+
const rawBack = mergedMeta.backCover !== void 0 ? mergedMeta.backCover : userConfig.backCover;
|
|
1507
|
+
const backCover = normalizeBackCover(rawBack, tokenContext);
|
|
1508
|
+
const rawNumberHeadings = mergedMeta.numberHeadings !== void 0 ? mergedMeta.numberHeadings : userConfig.numberHeadings;
|
|
1509
|
+
const numberHeadings = normalizeNumberHeadings(rawNumberHeadings);
|
|
1510
|
+
const rawSecurity = mergedMeta.security || userConfig.security;
|
|
1511
|
+
const security = normalizeSecurity(rawSecurity);
|
|
1512
|
+
const math = mergedMeta.math !== false && userConfig.math !== false;
|
|
1300
1513
|
const cssList = [];
|
|
1301
1514
|
const addCss = (item) => {
|
|
1302
1515
|
if (!item) return;
|
|
@@ -1324,7 +1537,13 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1324
1537
|
header,
|
|
1325
1538
|
footer,
|
|
1326
1539
|
toc,
|
|
1540
|
+
signatures,
|
|
1327
1541
|
watermark,
|
|
1542
|
+
coverPage,
|
|
1543
|
+
backCover,
|
|
1544
|
+
numberHeadings,
|
|
1545
|
+
security,
|
|
1546
|
+
math,
|
|
1328
1547
|
css: cssList,
|
|
1329
1548
|
embedImages,
|
|
1330
1549
|
bundleHtml,
|
|
@@ -1332,6 +1551,45 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1332
1551
|
};
|
|
1333
1552
|
}
|
|
1334
1553
|
|
|
1554
|
+
// src/core/math/mathRenderer.ts
|
|
1555
|
+
import katex from "katex";
|
|
1556
|
+
function renderMathToHtml(latex, displayMode = false) {
|
|
1557
|
+
try {
|
|
1558
|
+
return katex.renderToString(latex.trim(), {
|
|
1559
|
+
displayMode,
|
|
1560
|
+
throwOnError: false,
|
|
1561
|
+
output: "htmlAndMathml",
|
|
1562
|
+
strict: false
|
|
1563
|
+
});
|
|
1564
|
+
} catch {
|
|
1565
|
+
return `<span class="katex-fallback">${latex}</span>`;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
var KATEX_INLINE_CSS = `
|
|
1569
|
+
.katex { font: normal 1.21em KaTeX_Main, Times New Roman, serif; line-height: 1.2; text-indent: 0; text-rendering: auto; border-color: currentColor; }
|
|
1570
|
+
.katex * { -ms-high-contrast-adjust: none !important; }
|
|
1571
|
+
.katex .katex-html { display: inline-block; }
|
|
1572
|
+
.katex .katex-mathml { clip: rect(1px, 1px, 1px, 1px); border: 0; height: 1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
|
|
1573
|
+
.katex-display { display: block; margin: 1em 0; text-align: center; }
|
|
1574
|
+
.katex-display > .katex { display: inline-block; text-align: initial; }
|
|
1575
|
+
.katex .base { position: relative; white-space: nowrap; width: min-content; }
|
|
1576
|
+
.katex .strut { display: inline-block; }
|
|
1577
|
+
.katex .mord { display: inline-block; }
|
|
1578
|
+
.katex .mbin { display: inline-block; }
|
|
1579
|
+
.katex .mrel { display: inline-block; }
|
|
1580
|
+
.katex .mopen { display: inline-block; }
|
|
1581
|
+
.katex .mclose { display: inline-block; }
|
|
1582
|
+
.katex .mpunct { display: inline-block; }
|
|
1583
|
+
.katex .minner { display: inline-block; }
|
|
1584
|
+
.katex .mop { display: inline-block; }
|
|
1585
|
+
.katex .frac-line { width: 100%; border-bottom-style: solid; }
|
|
1586
|
+
.katex .vlist-t { display: inline-table; table-layout: fixed; }
|
|
1587
|
+
.katex .vlist-r { display: table-row; }
|
|
1588
|
+
.katex .vlist { display: table-cell; vertical-align: bottom; position: relative; }
|
|
1589
|
+
.katex .msupsub { text-align: left; }
|
|
1590
|
+
.katex .sqrt > .root { margin-left: 0.27777778em; margin-right: -0.55555556em; }
|
|
1591
|
+
`;
|
|
1592
|
+
|
|
1335
1593
|
// src/core/html/htmlBuilder.ts
|
|
1336
1594
|
function escapeHtml(str) {
|
|
1337
1595
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -1374,6 +1632,15 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
|
1374
1632
|
result += `<code>${escapeHtml(span.content)}</code>`;
|
|
1375
1633
|
continue;
|
|
1376
1634
|
}
|
|
1635
|
+
if (span.type === "mathInline") {
|
|
1636
|
+
result += renderMathToHtml(span.content, false);
|
|
1637
|
+
continue;
|
|
1638
|
+
}
|
|
1639
|
+
if (span.type === "footnoteRef") {
|
|
1640
|
+
const id = escapeHtml(span.footnoteId || span.content);
|
|
1641
|
+
result += `<sup><a href="#fn-${id}" id="fnref-${id}" class="markforge-fnref">[${escapeHtml(span.content)}]</a></sup>`;
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1377
1644
|
if (span.type === "htmlInline") {
|
|
1378
1645
|
result += span.content;
|
|
1379
1646
|
continue;
|
|
@@ -1382,66 +1649,9 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
|
1382
1649
|
}
|
|
1383
1650
|
return result;
|
|
1384
1651
|
}
|
|
1385
|
-
async function
|
|
1386
|
-
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
1387
|
-
const baseThemeCss = generateThemeCss(resolved.theme);
|
|
1388
|
-
let customCss = "";
|
|
1389
|
-
for (const cssPath of resolved.css) {
|
|
1390
|
-
const fullCssPath = path2.isAbsolute(cssPath) ? cssPath : path2.resolve(baseDir, cssPath);
|
|
1391
|
-
if (fs2.existsSync(fullCssPath)) {
|
|
1392
|
-
customCss += `
|
|
1393
|
-
/* Custom CSS: ${cssPath} */
|
|
1394
|
-
` + fs2.readFileSync(fullCssPath, "utf-8");
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
const inlinedCss = doc.inlinedStyles.join("\n");
|
|
1652
|
+
async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd()) {
|
|
1398
1653
|
let bodyHtml = "";
|
|
1399
|
-
|
|
1400
|
-
bodyHtml += ` <header class="document-header">
|
|
1401
|
-
`;
|
|
1402
|
-
bodyHtml += ` <h1 class="document-title">${escapeHtml(resolved.title)}</h1>
|
|
1403
|
-
`;
|
|
1404
|
-
if (resolved.subtitle) {
|
|
1405
|
-
bodyHtml += ` <div class="document-subtitle">${escapeHtml(resolved.subtitle)}</div>
|
|
1406
|
-
`;
|
|
1407
|
-
}
|
|
1408
|
-
if (resolved.author || resolved.date || resolved.version) {
|
|
1409
|
-
bodyHtml += ` <div class="document-meta">
|
|
1410
|
-
`;
|
|
1411
|
-
if (resolved.author) {
|
|
1412
|
-
bodyHtml += ` <span>Author: ${escapeHtml(resolved.author)}</span>
|
|
1413
|
-
`;
|
|
1414
|
-
}
|
|
1415
|
-
if (resolved.version) {
|
|
1416
|
-
bodyHtml += ` <span>Version: ${escapeHtml(resolved.version)}</span>
|
|
1417
|
-
`;
|
|
1418
|
-
}
|
|
1419
|
-
if (resolved.date) {
|
|
1420
|
-
bodyHtml += ` <span>Date: ${escapeHtml(resolved.date)}</span>
|
|
1421
|
-
`;
|
|
1422
|
-
}
|
|
1423
|
-
bodyHtml += ` </div>
|
|
1424
|
-
`;
|
|
1425
|
-
}
|
|
1426
|
-
bodyHtml += ` </header>
|
|
1427
|
-
`;
|
|
1428
|
-
}
|
|
1429
|
-
if (resolved.toc && doc.tocEntries.length > 0) {
|
|
1430
|
-
bodyHtml += ` <nav class="table-of-contents">
|
|
1431
|
-
`;
|
|
1432
|
-
bodyHtml += ` <h2>Table of Contents</h2>
|
|
1433
|
-
<ul>
|
|
1434
|
-
`;
|
|
1435
|
-
for (const entry of doc.tocEntries) {
|
|
1436
|
-
const indent = " ".repeat(entry.level);
|
|
1437
|
-
bodyHtml += ` ${indent}<li><a href="#${entry.id}">${escapeHtml(entry.text)}</a></li>
|
|
1438
|
-
`;
|
|
1439
|
-
}
|
|
1440
|
-
bodyHtml += ` </ul>
|
|
1441
|
-
</nav>
|
|
1442
|
-
`;
|
|
1443
|
-
}
|
|
1444
|
-
for (const node of doc.nodes) {
|
|
1654
|
+
for (const node of nodes) {
|
|
1445
1655
|
if (node.type === "heading") {
|
|
1446
1656
|
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1447
1657
|
bodyHtml += ` <h${node.level} id="${node.id}">${inner}</h${node.level}>
|
|
@@ -1451,6 +1661,26 @@ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1451
1661
|
if (node.type === "paragraph") {
|
|
1452
1662
|
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1453
1663
|
bodyHtml += ` <p>${inner}</p>
|
|
1664
|
+
`;
|
|
1665
|
+
continue;
|
|
1666
|
+
}
|
|
1667
|
+
if (node.type === "mathBlock") {
|
|
1668
|
+
bodyHtml += ` <div class="math-block">${renderMathToHtml(node.text || "", true)}</div>
|
|
1669
|
+
`;
|
|
1670
|
+
continue;
|
|
1671
|
+
}
|
|
1672
|
+
if (node.type === "columns") {
|
|
1673
|
+
const cols = node.columnsCount || 2;
|
|
1674
|
+
const gap = node.columnGap || "1.5rem";
|
|
1675
|
+
let colChildrenHtml = "";
|
|
1676
|
+
for (const col of node.children || []) {
|
|
1677
|
+
const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir);
|
|
1678
|
+
colChildrenHtml += ` <div class="markforge-col">
|
|
1679
|
+
${colInner} </div>
|
|
1680
|
+
`;
|
|
1681
|
+
}
|
|
1682
|
+
bodyHtml += ` <div class="markforge-columns" style="--cols: ${cols}; --col-gap: ${gap};">
|
|
1683
|
+
${colChildrenHtml} </div>
|
|
1454
1684
|
`;
|
|
1455
1685
|
continue;
|
|
1456
1686
|
}
|
|
@@ -1539,6 +1769,429 @@ ${escapeHtml(node.text || "")}
|
|
|
1539
1769
|
continue;
|
|
1540
1770
|
}
|
|
1541
1771
|
}
|
|
1772
|
+
return bodyHtml;
|
|
1773
|
+
}
|
|
1774
|
+
async function renderCoverPageHtml(cover, baseDir = process.cwd()) {
|
|
1775
|
+
let logoHtml = "";
|
|
1776
|
+
if (cover.logo) {
|
|
1777
|
+
const resolvedLogo = await resolveImage(cover.logo, baseDir);
|
|
1778
|
+
const src = resolvedLogo ? resolvedLogo.dataUri : cover.logo;
|
|
1779
|
+
const widthStyle = cover.logoWidth ? `max-width: ${typeof cover.logoWidth === "number" ? cover.logoWidth + "px" : cover.logoWidth}; max-height: 80px; width: auto; height: auto;` : "max-height: 60px; max-width: 180px; width: auto; height: auto;";
|
|
1780
|
+
logoHtml = `<div class="cover-logo"><img src="${src}" alt="Logo" style="${widthStyle} object-fit: contain;" /></div>`;
|
|
1781
|
+
}
|
|
1782
|
+
const badgeHtml = cover.badge ? `<div class="cover-badge" style="${cover.badgeColor ? `background-color: ${cover.badgeColor};` : ""}${cover.badgeTextColor ? `color: ${cover.badgeTextColor};` : ""}">${escapeHtml(cover.badge)}</div>` : "";
|
|
1783
|
+
const titleHtml = `<h1 class="cover-title">${escapeHtml(cover.title)}</h1>`;
|
|
1784
|
+
const subtitleHtml = cover.subtitle ? `<div class="cover-subtitle">${escapeHtml(cover.subtitle)}</div>` : "";
|
|
1785
|
+
const metaItems = [];
|
|
1786
|
+
if (cover.company) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Organization:</span> <span class="cover-meta-value">${escapeHtml(cover.company)}</span></div>`);
|
|
1787
|
+
if (cover.author) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Author:</span> <span class="cover-meta-value">${escapeHtml(cover.author)}</span></div>`);
|
|
1788
|
+
if (cover.version) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Version:</span> <span class="cover-meta-value">${escapeHtml(cover.version)}</span></div>`);
|
|
1789
|
+
if (cover.date) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Date:</span> <span class="cover-meta-value">${escapeHtml(cover.date)}</span></div>`);
|
|
1790
|
+
const metaHtml = metaItems.length > 0 ? `<div class="cover-meta">${metaItems.join("\n")}</div>` : "";
|
|
1791
|
+
const footerHtml = cover.footerText ? `<div class="cover-footer-text">${escapeHtml(cover.footerText)}</div>` : "";
|
|
1792
|
+
const css = `
|
|
1793
|
+
.markforge-cover {
|
|
1794
|
+
min-height: 100vh;
|
|
1795
|
+
box-sizing: border-box;
|
|
1796
|
+
display: flex;
|
|
1797
|
+
flex-direction: column;
|
|
1798
|
+
justify-content: space-between;
|
|
1799
|
+
padding: 4rem 3.5rem;
|
|
1800
|
+
page-break-after: always;
|
|
1801
|
+
break-after: page;
|
|
1802
|
+
position: relative;
|
|
1803
|
+
z-index: 2;
|
|
1804
|
+
background: ${cover.bgGradient || "#FFFFFF"};
|
|
1805
|
+
-webkit-print-color-adjust: exact;
|
|
1806
|
+
print-color-adjust: exact;
|
|
1807
|
+
color: ${cover.textColor || "#0F172A"};
|
|
1808
|
+
}
|
|
1809
|
+
.markforge-cover.cover-modern {
|
|
1810
|
+
border-top: 8px solid #0D998D;
|
|
1811
|
+
}
|
|
1812
|
+
.markforge-cover.cover-corporate-split {
|
|
1813
|
+
border-left: 12px solid #0D998D;
|
|
1814
|
+
}
|
|
1815
|
+
.markforge-cover.cover-card {
|
|
1816
|
+
background: #F8FAFC;
|
|
1817
|
+
}
|
|
1818
|
+
.cover-top {
|
|
1819
|
+
display: flex;
|
|
1820
|
+
justify-content: space-between;
|
|
1821
|
+
align-items: flex-start;
|
|
1822
|
+
width: 100%;
|
|
1823
|
+
}
|
|
1824
|
+
.cover-badge {
|
|
1825
|
+
display: inline-block;
|
|
1826
|
+
padding: 0.35rem 0.85rem;
|
|
1827
|
+
font-size: 0.78rem;
|
|
1828
|
+
font-weight: 700;
|
|
1829
|
+
letter-spacing: 0.08em;
|
|
1830
|
+
text-transform: uppercase;
|
|
1831
|
+
background-color: #ECFDFD;
|
|
1832
|
+
color: #0D998D;
|
|
1833
|
+
border-radius: 4px;
|
|
1834
|
+
border: 1px solid #33CDCF;
|
|
1835
|
+
}
|
|
1836
|
+
.cover-body {
|
|
1837
|
+
margin: auto 0;
|
|
1838
|
+
}
|
|
1839
|
+
.cover-title {
|
|
1840
|
+
font-size: 2.8rem;
|
|
1841
|
+
font-weight: 800;
|
|
1842
|
+
line-height: 1.15;
|
|
1843
|
+
margin: 0 0 1rem 0;
|
|
1844
|
+
color: inherit;
|
|
1845
|
+
}
|
|
1846
|
+
.cover-subtitle {
|
|
1847
|
+
font-size: 1.35rem;
|
|
1848
|
+
font-weight: 400;
|
|
1849
|
+
color: #64748B;
|
|
1850
|
+
margin: 0 0 2rem 0;
|
|
1851
|
+
line-height: 1.4;
|
|
1852
|
+
}
|
|
1853
|
+
.cover-meta {
|
|
1854
|
+
display: flex;
|
|
1855
|
+
flex-direction: column;
|
|
1856
|
+
gap: 0.5rem;
|
|
1857
|
+
border-top: 1.5px solid #E2E8F0;
|
|
1858
|
+
padding-top: 1.5rem;
|
|
1859
|
+
max-width: 480px;
|
|
1860
|
+
}
|
|
1861
|
+
.cover-meta-item {
|
|
1862
|
+
font-size: 0.92rem;
|
|
1863
|
+
display: flex;
|
|
1864
|
+
gap: 0.75rem;
|
|
1865
|
+
}
|
|
1866
|
+
.cover-meta-label {
|
|
1867
|
+
font-weight: 600;
|
|
1868
|
+
color: #64748B;
|
|
1869
|
+
min-width: 110px;
|
|
1870
|
+
}
|
|
1871
|
+
.cover-meta-value {
|
|
1872
|
+
font-weight: 500;
|
|
1873
|
+
color: #0F172A;
|
|
1874
|
+
}
|
|
1875
|
+
.cover-bottom {
|
|
1876
|
+
display: flex;
|
|
1877
|
+
justify-content: space-between;
|
|
1878
|
+
align-items: flex-end;
|
|
1879
|
+
font-size: 0.82rem;
|
|
1880
|
+
color: #94A3B8;
|
|
1881
|
+
}
|
|
1882
|
+
@media print {
|
|
1883
|
+
.markforge-cover {
|
|
1884
|
+
page-break-after: always;
|
|
1885
|
+
break-after: page;
|
|
1886
|
+
height: 100vh;
|
|
1887
|
+
min-height: 100vh;
|
|
1888
|
+
max-height: 100vh;
|
|
1889
|
+
box-sizing: border-box;
|
|
1890
|
+
overflow: hidden;
|
|
1891
|
+
margin: 0;
|
|
1892
|
+
-webkit-print-color-adjust: exact;
|
|
1893
|
+
print-color-adjust: exact;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
`;
|
|
1897
|
+
const html = ` <section class="markforge-cover cover-${cover.preset}">
|
|
1898
|
+
<div class="cover-top">
|
|
1899
|
+
${logoHtml}
|
|
1900
|
+
${badgeHtml}
|
|
1901
|
+
</div>
|
|
1902
|
+
<div class="cover-body">
|
|
1903
|
+
${titleHtml}
|
|
1904
|
+
${subtitleHtml}
|
|
1905
|
+
${metaHtml}
|
|
1906
|
+
</div>
|
|
1907
|
+
<div class="cover-bottom">
|
|
1908
|
+
${footerHtml}
|
|
1909
|
+
</div>
|
|
1910
|
+
</section>
|
|
1911
|
+
`;
|
|
1912
|
+
return { html, css };
|
|
1913
|
+
}
|
|
1914
|
+
async function renderBackCoverHtml(backCover, baseDir = process.cwd()) {
|
|
1915
|
+
let logoHtml = "";
|
|
1916
|
+
if (backCover.logo) {
|
|
1917
|
+
const resolved = await resolveImage(backCover.logo, baseDir);
|
|
1918
|
+
const src = resolved ? resolved.dataUri : backCover.logo;
|
|
1919
|
+
const widthStyle = backCover.logoWidth ? `style="width: ${typeof backCover.logoWidth === "number" ? `${backCover.logoWidth}px` : backCover.logoWidth}; max-width: 100%;"` : `style="max-width: 160px; height: auto;"`;
|
|
1920
|
+
logoHtml = `<div class="back-logo"><img src="${src}" alt="Brand Logo" ${widthStyle} /></div>`;
|
|
1921
|
+
}
|
|
1922
|
+
const badgeHtml = backCover.badge ? `<div class="back-badge" style="${backCover.badgeColor ? `background-color: ${backCover.badgeColor};` : ""}${backCover.badgeTextColor ? `color: ${backCover.badgeTextColor};` : ""}">${escapeHtml(backCover.badge)}</div>` : "";
|
|
1923
|
+
const titleHtml = `<h1 class="back-title">${escapeHtml(backCover.title)}</h1>`;
|
|
1924
|
+
const subtitleHtml = backCover.subtitle ? `<div class="back-subtitle">${escapeHtml(backCover.subtitle)}</div>` : "";
|
|
1925
|
+
const contactItems = [];
|
|
1926
|
+
if (backCover.company) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Organization:</span> <span class="back-contact-value">${escapeHtml(backCover.company)}</span></div>`);
|
|
1927
|
+
if (backCover.address) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Address:</span> <span class="back-contact-value">${escapeHtml(backCover.address)}</span></div>`);
|
|
1928
|
+
if (backCover.email) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Email:</span> <a href="mailto:${escapeHtml(backCover.email)}" class="back-contact-link">${escapeHtml(backCover.email)}</a></div>`);
|
|
1929
|
+
if (backCover.phone) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Phone:</span> <span class="back-contact-value">${escapeHtml(backCover.phone)}</span></div>`);
|
|
1930
|
+
if (backCover.website) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Website:</span> <a href="${escapeHtml(backCover.website)}" target="_blank" class="back-contact-link">${escapeHtml(backCover.website)}</a></div>`);
|
|
1931
|
+
if (backCover.social) {
|
|
1932
|
+
for (const [network, url] of Object.entries(backCover.social)) {
|
|
1933
|
+
if (url) {
|
|
1934
|
+
contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">${escapeHtml(network.toUpperCase())}:</span> <a href="${escapeHtml(url)}" target="_blank" class="back-contact-link">${escapeHtml(url)}</a></div>`);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
const contactHtml = contactItems.length > 0 ? `<div class="back-contact-grid">${contactItems.join("\n")}</div>` : "";
|
|
1939
|
+
const copyrightHtml = backCover.copyright ? `<div class="back-copyright">${escapeHtml(backCover.copyright)}</div>` : "";
|
|
1940
|
+
const isDark = backCover.preset === "corporate";
|
|
1941
|
+
const css = `
|
|
1942
|
+
.markforge-back-cover {
|
|
1943
|
+
min-height: 100vh;
|
|
1944
|
+
box-sizing: border-box;
|
|
1945
|
+
display: flex;
|
|
1946
|
+
flex-direction: column;
|
|
1947
|
+
justify-content: space-between;
|
|
1948
|
+
padding: 4rem 3.5rem;
|
|
1949
|
+
page-break-before: always;
|
|
1950
|
+
break-before: page;
|
|
1951
|
+
position: relative;
|
|
1952
|
+
z-index: 2;
|
|
1953
|
+
background: ${backCover.bgGradient || (isDark ? "#0F172A" : "#FFFFFF")};
|
|
1954
|
+
color: ${backCover.textColor || (isDark ? "#F8FAFC" : "#0F172A")};
|
|
1955
|
+
}
|
|
1956
|
+
.markforge-back-cover.back-modern {
|
|
1957
|
+
border-bottom: 8px solid #0D998D;
|
|
1958
|
+
}
|
|
1959
|
+
.markforge-back-cover.back-corporate {
|
|
1960
|
+
border-left: 12px solid #33CDCF;
|
|
1961
|
+
}
|
|
1962
|
+
.markforge-back-cover.back-card {
|
|
1963
|
+
background: #F8FAFC;
|
|
1964
|
+
}
|
|
1965
|
+
.back-top {
|
|
1966
|
+
display: flex;
|
|
1967
|
+
justify-content: space-between;
|
|
1968
|
+
align-items: flex-start;
|
|
1969
|
+
width: 100%;
|
|
1970
|
+
}
|
|
1971
|
+
.back-badge {
|
|
1972
|
+
display: inline-block;
|
|
1973
|
+
padding: 0.35rem 0.85rem;
|
|
1974
|
+
font-size: 0.78rem;
|
|
1975
|
+
font-weight: 700;
|
|
1976
|
+
letter-spacing: 0.08em;
|
|
1977
|
+
text-transform: uppercase;
|
|
1978
|
+
background-color: #ECFDFD;
|
|
1979
|
+
color: #0D998D;
|
|
1980
|
+
border-radius: 4px;
|
|
1981
|
+
border: 1px solid #33CDCF;
|
|
1982
|
+
}
|
|
1983
|
+
.back-body {
|
|
1984
|
+
margin: auto 0;
|
|
1985
|
+
}
|
|
1986
|
+
.back-title {
|
|
1987
|
+
font-size: 2.6rem;
|
|
1988
|
+
font-weight: 800;
|
|
1989
|
+
line-height: 1.15;
|
|
1990
|
+
margin: 0 0 0.75rem 0;
|
|
1991
|
+
color: inherit;
|
|
1992
|
+
}
|
|
1993
|
+
.back-subtitle {
|
|
1994
|
+
font-size: 1.25rem;
|
|
1995
|
+
font-weight: 400;
|
|
1996
|
+
color: ${isDark ? "#94A3B8" : "#64748B"};
|
|
1997
|
+
margin: 0 0 2rem 0;
|
|
1998
|
+
line-height: 1.4;
|
|
1999
|
+
}
|
|
2000
|
+
.back-contact-grid {
|
|
2001
|
+
display: flex;
|
|
2002
|
+
flex-direction: column;
|
|
2003
|
+
gap: 0.6rem;
|
|
2004
|
+
border-top: 1.5px solid ${isDark ? "#334155" : "#E2E8F0"};
|
|
2005
|
+
padding-top: 1.5rem;
|
|
2006
|
+
max-width: 540px;
|
|
2007
|
+
}
|
|
2008
|
+
.back-contact-item {
|
|
2009
|
+
font-size: 0.92rem;
|
|
2010
|
+
display: flex;
|
|
2011
|
+
gap: 0.75rem;
|
|
2012
|
+
}
|
|
2013
|
+
.back-contact-label {
|
|
2014
|
+
font-weight: 600;
|
|
2015
|
+
color: ${isDark ? "#94A3B8" : "#64748B"};
|
|
2016
|
+
min-width: 110px;
|
|
2017
|
+
}
|
|
2018
|
+
.back-contact-link {
|
|
2019
|
+
color: #0D998D;
|
|
2020
|
+
text-decoration: none;
|
|
2021
|
+
font-weight: 600;
|
|
2022
|
+
}
|
|
2023
|
+
.back-contact-link:hover {
|
|
2024
|
+
text-decoration: underline;
|
|
2025
|
+
}
|
|
2026
|
+
.back-copyright {
|
|
2027
|
+
font-size: 0.82rem;
|
|
2028
|
+
color: ${isDark ? "#64748B" : "#94A3B8"};
|
|
2029
|
+
border-top: 1px solid ${isDark ? "#1E293B" : "#F1F5F9"};
|
|
2030
|
+
padding-top: 1rem;
|
|
2031
|
+
margin-top: 2rem;
|
|
2032
|
+
}
|
|
2033
|
+
@media print {
|
|
2034
|
+
.markforge-back-cover {
|
|
2035
|
+
page: back-cover-page;
|
|
2036
|
+
page-break-before: always;
|
|
2037
|
+
break-before: page;
|
|
2038
|
+
page-break-after: avoid;
|
|
2039
|
+
break-after: avoid;
|
|
2040
|
+
min-height: 100vh;
|
|
2041
|
+
height: 100vh;
|
|
2042
|
+
max-height: 100vh;
|
|
2043
|
+
margin: 0;
|
|
2044
|
+
box-sizing: border-box;
|
|
2045
|
+
overflow: hidden;
|
|
2046
|
+
-webkit-print-color-adjust: exact;
|
|
2047
|
+
print-color-adjust: exact;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
`;
|
|
2051
|
+
const html = ` <section class="markforge-back-cover back-${backCover.preset}">
|
|
2052
|
+
<div class="back-top">
|
|
2053
|
+
${logoHtml}
|
|
2054
|
+
${badgeHtml}
|
|
2055
|
+
</div>
|
|
2056
|
+
<div class="back-body">
|
|
2057
|
+
${titleHtml}
|
|
2058
|
+
${subtitleHtml}
|
|
2059
|
+
${contactHtml}
|
|
2060
|
+
</div>
|
|
2061
|
+
${copyrightHtml}
|
|
2062
|
+
</section>
|
|
2063
|
+
`;
|
|
2064
|
+
return { html, css };
|
|
2065
|
+
}
|
|
2066
|
+
async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
2067
|
+
var _a;
|
|
2068
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2069
|
+
const baseThemeCss = generateThemeCss(resolved.theme);
|
|
2070
|
+
let customCss = "";
|
|
2071
|
+
for (const cssPath of resolved.css) {
|
|
2072
|
+
const fullCssPath = path2.isAbsolute(cssPath) ? cssPath : path2.resolve(baseDir, cssPath);
|
|
2073
|
+
if (fs2.existsSync(fullCssPath)) {
|
|
2074
|
+
customCss += `
|
|
2075
|
+
/* Custom CSS: ${cssPath} */
|
|
2076
|
+
` + fs2.readFileSync(fullCssPath, "utf-8");
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
const inlinedCss = doc.inlinedStyles.join("\n");
|
|
2080
|
+
const extraCss = `
|
|
2081
|
+
.markforge-columns {
|
|
2082
|
+
display: grid;
|
|
2083
|
+
grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
|
|
2084
|
+
gap: var(--col-gap, 1.5rem);
|
|
2085
|
+
margin: 1.5rem 0;
|
|
2086
|
+
}
|
|
2087
|
+
.markforge-col {
|
|
2088
|
+
min-width: 0;
|
|
2089
|
+
}
|
|
2090
|
+
.markforge-fnref {
|
|
2091
|
+
text-decoration: none;
|
|
2092
|
+
font-size: 0.8em;
|
|
2093
|
+
vertical-align: super;
|
|
2094
|
+
color: #0D998D;
|
|
2095
|
+
font-weight: 700;
|
|
2096
|
+
}
|
|
2097
|
+
.markforge-footnotes {
|
|
2098
|
+
margin-top: 3rem;
|
|
2099
|
+
padding-top: 1rem;
|
|
2100
|
+
font-size: 0.88rem;
|
|
2101
|
+
color: #64748B;
|
|
2102
|
+
}
|
|
2103
|
+
.markforge-footnotes hr {
|
|
2104
|
+
border: 0;
|
|
2105
|
+
border-top: 1px solid #E2E8F0;
|
|
2106
|
+
margin-bottom: 1rem;
|
|
2107
|
+
}
|
|
2108
|
+
.markforge-fn-return {
|
|
2109
|
+
text-decoration: none;
|
|
2110
|
+
color: #0D998D;
|
|
2111
|
+
}
|
|
2112
|
+
.math-block {
|
|
2113
|
+
margin: 1.5rem 0;
|
|
2114
|
+
text-align: center;
|
|
2115
|
+
overflow-x: auto;
|
|
2116
|
+
}
|
|
2117
|
+
`;
|
|
2118
|
+
let coverHtml = "";
|
|
2119
|
+
let coverCss = "";
|
|
2120
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
2121
|
+
const coverRes = await renderCoverPageHtml(resolved.coverPage, baseDir);
|
|
2122
|
+
coverHtml = coverRes.html;
|
|
2123
|
+
coverCss = coverRes.css;
|
|
2124
|
+
}
|
|
2125
|
+
let backHtml = "";
|
|
2126
|
+
let backCss = "";
|
|
2127
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
2128
|
+
const backRes = await renderBackCoverHtml(resolved.backCover, baseDir);
|
|
2129
|
+
backHtml = backRes.html;
|
|
2130
|
+
backCss = backRes.css;
|
|
2131
|
+
}
|
|
2132
|
+
let bodyHtml = "";
|
|
2133
|
+
if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
|
|
2134
|
+
bodyHtml += ` <header class="document-header">
|
|
2135
|
+
`;
|
|
2136
|
+
bodyHtml += ` <h1 class="document-title">${escapeHtml(resolved.title)}</h1>
|
|
2137
|
+
`;
|
|
2138
|
+
if (resolved.subtitle) {
|
|
2139
|
+
bodyHtml += ` <div class="document-subtitle">${escapeHtml(resolved.subtitle)}</div>
|
|
2140
|
+
`;
|
|
2141
|
+
}
|
|
2142
|
+
if (resolved.author || resolved.date || resolved.version) {
|
|
2143
|
+
bodyHtml += ` <div class="document-meta">
|
|
2144
|
+
`;
|
|
2145
|
+
if (resolved.author) {
|
|
2146
|
+
bodyHtml += ` <span>Author: ${escapeHtml(resolved.author)}</span>
|
|
2147
|
+
`;
|
|
2148
|
+
}
|
|
2149
|
+
if (resolved.version) {
|
|
2150
|
+
bodyHtml += ` <span>Version: ${escapeHtml(resolved.version)}</span>
|
|
2151
|
+
`;
|
|
2152
|
+
}
|
|
2153
|
+
if (resolved.date) {
|
|
2154
|
+
bodyHtml += ` <span>Date: ${escapeHtml(resolved.date)}</span>
|
|
2155
|
+
`;
|
|
2156
|
+
}
|
|
2157
|
+
bodyHtml += ` </div>
|
|
2158
|
+
`;
|
|
2159
|
+
}
|
|
2160
|
+
bodyHtml += ` </header>
|
|
2161
|
+
`;
|
|
2162
|
+
}
|
|
2163
|
+
if (resolved.toc && doc.tocEntries.length > 0) {
|
|
2164
|
+
bodyHtml += ` <nav class="table-of-contents">
|
|
2165
|
+
`;
|
|
2166
|
+
bodyHtml += ` <h2>Table of Contents</h2>
|
|
2167
|
+
<ul>
|
|
2168
|
+
`;
|
|
2169
|
+
for (const entry of doc.tocEntries) {
|
|
2170
|
+
const indent = " ".repeat(entry.level);
|
|
2171
|
+
bodyHtml += ` ${indent}<li><a href="#${entry.id}">${escapeHtml(entry.text)}</a></li>
|
|
2172
|
+
`;
|
|
2173
|
+
}
|
|
2174
|
+
bodyHtml += ` </ul>
|
|
2175
|
+
</nav>
|
|
2176
|
+
`;
|
|
2177
|
+
}
|
|
2178
|
+
bodyHtml += await renderNodesToHtml(doc.nodes, resolved, baseDir);
|
|
2179
|
+
let footnotesHtml = "";
|
|
2180
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
2181
|
+
let fnListHtml = "";
|
|
2182
|
+
for (const def of doc.footnoteDefs) {
|
|
2183
|
+
const defInner = await renderInlinesToHtml(def.inlines, baseDir);
|
|
2184
|
+
fnListHtml += ` <li id="fn-${escapeHtml(def.id)}">${defInner} <a href="#fnref-${escapeHtml(def.id)}" class="markforge-fn-return">↩</a></li>
|
|
2185
|
+
`;
|
|
2186
|
+
}
|
|
2187
|
+
footnotesHtml = `
|
|
2188
|
+
<footer class="markforge-footnotes">
|
|
2189
|
+
<hr />
|
|
2190
|
+
<ol>
|
|
2191
|
+
${fnListHtml} </ol>
|
|
2192
|
+
</footer>
|
|
2193
|
+
`;
|
|
2194
|
+
}
|
|
1542
2195
|
let watermarkCss = "";
|
|
1543
2196
|
let watermarkHtml = "";
|
|
1544
2197
|
if (resolved.watermark) {
|
|
@@ -1546,26 +2199,164 @@ ${escapeHtml(node.text || "")}
|
|
|
1546
2199
|
watermarkCss = `
|
|
1547
2200
|
.document-watermark {
|
|
1548
2201
|
position: fixed;
|
|
1549
|
-
top:
|
|
1550
|
-
left:
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
opacity: ${wm.opacity};
|
|
2202
|
+
top: 0;
|
|
2203
|
+
left: 0;
|
|
2204
|
+
right: 0;
|
|
2205
|
+
bottom: 0;
|
|
2206
|
+
width: 100%;
|
|
2207
|
+
height: 100%;
|
|
1556
2208
|
pointer-events: none;
|
|
1557
2209
|
z-index: 0;
|
|
1558
2210
|
user-select: none;
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
2211
|
+
-webkit-user-select: none;
|
|
2212
|
+
-webkit-print-color-adjust: exact;
|
|
2213
|
+
print-color-adjust: exact;
|
|
1562
2214
|
}
|
|
1563
2215
|
.document-container {
|
|
1564
2216
|
position: relative;
|
|
1565
2217
|
z-index: 1;
|
|
1566
2218
|
}
|
|
2219
|
+
@media print {
|
|
2220
|
+
.document-watermark {
|
|
2221
|
+
position: fixed;
|
|
2222
|
+
top: 0;
|
|
2223
|
+
left: 0;
|
|
2224
|
+
right: 0;
|
|
2225
|
+
bottom: 0;
|
|
2226
|
+
width: 100vw;
|
|
2227
|
+
height: 100vh;
|
|
2228
|
+
pointer-events: none;
|
|
2229
|
+
z-index: 0;
|
|
2230
|
+
-webkit-print-color-adjust: exact;
|
|
2231
|
+
print-color-adjust: exact;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
`;
|
|
2235
|
+
watermarkHtml = ` <div id="markforge-watermark" class="document-watermark" aria-hidden="true"></div>
|
|
2236
|
+
<script>
|
|
2237
|
+
(function() {
|
|
2238
|
+
try {
|
|
2239
|
+
var canvas = document.createElement('canvas');
|
|
2240
|
+
var dpr = 2;
|
|
2241
|
+
var width = 1200;
|
|
2242
|
+
var height = 1600;
|
|
2243
|
+
canvas.width = width * dpr;
|
|
2244
|
+
canvas.height = height * dpr;
|
|
2245
|
+
var ctx = canvas.getContext('2d');
|
|
2246
|
+
if (ctx) {
|
|
2247
|
+
ctx.scale(dpr, dpr);
|
|
2248
|
+
ctx.translate(width / 2, height / 2);
|
|
2249
|
+
ctx.rotate((-Math.abs(${wm.rotate || 45}) * Math.PI) / 180);
|
|
2250
|
+
ctx.textAlign = 'center';
|
|
2251
|
+
ctx.textBaseline = 'middle';
|
|
2252
|
+
ctx.font = '900 ${wm.fontSize * 1.5}px system-ui, -apple-system, sans-serif';
|
|
2253
|
+
ctx.fillStyle = '${wm.color}';
|
|
2254
|
+
ctx.globalAlpha = ${wm.opacity};
|
|
2255
|
+
try { ctx.letterSpacing = '0.15em'; } catch(e) {}
|
|
2256
|
+
ctx.fillText(${JSON.stringify(wm.text.toUpperCase())}, 0, 0);
|
|
2257
|
+
var dataUrl = canvas.toDataURL('image/png');
|
|
2258
|
+
var wmEl = document.getElementById('markforge-watermark');
|
|
2259
|
+
if (wmEl) {
|
|
2260
|
+
wmEl.style.backgroundImage = 'url("' + dataUrl + '")';
|
|
2261
|
+
wmEl.style.backgroundRepeat = 'no-repeat';
|
|
2262
|
+
wmEl.style.backgroundPosition = 'center center';
|
|
2263
|
+
wmEl.style.backgroundSize = 'contain';
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
} catch(err) {}
|
|
2267
|
+
})();
|
|
2268
|
+
</script>
|
|
2269
|
+
`;
|
|
2270
|
+
}
|
|
2271
|
+
let signaturesHtml = "";
|
|
2272
|
+
let signaturesCss = "";
|
|
2273
|
+
if (resolved.signatures && resolved.signatures.items.length > 0) {
|
|
2274
|
+
const sig = resolved.signatures;
|
|
2275
|
+
const numItems = sig.items.length;
|
|
2276
|
+
signaturesCss = `
|
|
2277
|
+
.markforge-signatures {
|
|
2278
|
+
margin-top: ${sig.spacingBefore};
|
|
2279
|
+
display: grid;
|
|
2280
|
+
grid-template-columns: ${numItems === 1 ? sig.align === "left" ? "minmax(200px, 280px) 1fr" : sig.align === "center" ? "1fr minmax(200px, 280px) 1fr" : "1fr minmax(200px, 280px)" : `repeat(${numItems}, minmax(0, 1fr))`};
|
|
2281
|
+
gap: 2rem;
|
|
2282
|
+
page-break-inside: avoid;
|
|
2283
|
+
break-inside: avoid;
|
|
2284
|
+
}
|
|
2285
|
+
.markforge-signature-card {
|
|
2286
|
+
${numItems === 1 && sig.align === "center" ? "grid-column: 2;" : ""}
|
|
2287
|
+
${numItems === 1 && sig.align === "right" ? "grid-column: 2;" : ""}
|
|
2288
|
+
display: flex;
|
|
2289
|
+
flex-direction: column;
|
|
2290
|
+
${sig.style === "box" ? `border: 1px solid ${sig.borderColor}; border-radius: 6px; padding: 14px 18px; background-color: var(--mf-card-bg, #F8FAFC);` : ""}
|
|
2291
|
+
}
|
|
2292
|
+
.markforge-sig-title {
|
|
2293
|
+
font-size: 0.85rem;
|
|
2294
|
+
color: ${sig.titleColor};
|
|
2295
|
+
font-weight: 600;
|
|
2296
|
+
margin-bottom: 6px;
|
|
2297
|
+
}
|
|
2298
|
+
.markforge-sig-space {
|
|
2299
|
+
height: var(--sig-height, 60px);
|
|
2300
|
+
display: flex;
|
|
2301
|
+
align-items: center;
|
|
2302
|
+
justify-content: center;
|
|
2303
|
+
margin-bottom: 6px;
|
|
2304
|
+
}
|
|
2305
|
+
.markforge-sig-space img {
|
|
2306
|
+
max-height: 100%;
|
|
2307
|
+
max-width: 100%;
|
|
2308
|
+
object-fit: contain;
|
|
2309
|
+
}
|
|
2310
|
+
.markforge-sig-line {
|
|
2311
|
+
${sig.style === "line" ? `border-bottom: 1.5px solid ${sig.borderColor}; margin-bottom: 8px;` : ""}
|
|
2312
|
+
}
|
|
2313
|
+
.markforge-sig-name {
|
|
2314
|
+
font-size: 0.95rem;
|
|
2315
|
+
font-weight: 700;
|
|
2316
|
+
color: ${sig.nameColor};
|
|
2317
|
+
}
|
|
2318
|
+
.markforge-sig-role {
|
|
2319
|
+
font-size: 0.82rem;
|
|
2320
|
+
color: ${sig.roleColor};
|
|
2321
|
+
margin-top: 2px;
|
|
2322
|
+
}
|
|
2323
|
+
.markforge-sig-date {
|
|
2324
|
+
font-size: 0.78rem;
|
|
2325
|
+
color: ${sig.roleColor};
|
|
2326
|
+
margin-top: 2px;
|
|
2327
|
+
}
|
|
2328
|
+
@media print {
|
|
2329
|
+
.markforge-signatures {
|
|
2330
|
+
page-break-inside: avoid;
|
|
2331
|
+
break-inside: avoid;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
1567
2334
|
`;
|
|
1568
|
-
|
|
2335
|
+
const itemCards = sig.items.map((item) => {
|
|
2336
|
+
const titleHtml = item.title ? `<div class="markforge-sig-title">${escapeHtml(item.title)}</div>` : "";
|
|
2337
|
+
let signSpaceHtml = "";
|
|
2338
|
+
if (item.image) {
|
|
2339
|
+
signSpaceHtml = `<div class="markforge-sig-space" style="--sig-height: ${item.signatureHeight}px;"><img src="${escapeHtml(item.image)}" alt="Signature" /></div>`;
|
|
2340
|
+
} else {
|
|
2341
|
+
signSpaceHtml = `<div class="markforge-sig-space" style="--sig-height: ${item.signatureHeight}px;"></div>`;
|
|
2342
|
+
}
|
|
2343
|
+
const lineHtml = sig.style === "line" ? `<div class="markforge-sig-line"></div>` : "";
|
|
2344
|
+
const nameHtml = `<div class="markforge-sig-name">${escapeHtml(item.name)}</div>`;
|
|
2345
|
+
const roleHtml = item.role ? `<div class="markforge-sig-role">${escapeHtml(item.role)}</div>` : "";
|
|
2346
|
+
const dateHtml = item.date ? `<div class="markforge-sig-date">Date: ${escapeHtml(item.date)}</div>` : "";
|
|
2347
|
+
return ` <div class="markforge-signature-card">
|
|
2348
|
+
${titleHtml}
|
|
2349
|
+
${signSpaceHtml}
|
|
2350
|
+
${lineHtml}
|
|
2351
|
+
${nameHtml}
|
|
2352
|
+
${roleHtml}
|
|
2353
|
+
${dateHtml}
|
|
2354
|
+
</div>`;
|
|
2355
|
+
}).join("\n");
|
|
2356
|
+
signaturesHtml = `
|
|
2357
|
+
<div class="markforge-signatures">
|
|
2358
|
+
${itemCards}
|
|
2359
|
+
</div>
|
|
1569
2360
|
`;
|
|
1570
2361
|
}
|
|
1571
2362
|
const hasMermaid = doc.nodes.some((n) => n.type === "mermaid");
|
|
@@ -1593,20 +2384,113 @@ ${escapeHtml(node.text || "")}
|
|
|
1593
2384
|
<style>
|
|
1594
2385
|
${THEME_COMPONENTS}
|
|
1595
2386
|
${baseThemeCss}
|
|
2387
|
+
${KATEX_INLINE_CSS}
|
|
2388
|
+
${extraCss}
|
|
2389
|
+
${coverCss}
|
|
2390
|
+
${backCss}
|
|
1596
2391
|
${customCss}
|
|
1597
2392
|
${inlinedCss}
|
|
1598
2393
|
${watermarkCss}
|
|
2394
|
+
${signaturesCss}
|
|
1599
2395
|
</style>
|
|
1600
2396
|
</head>
|
|
1601
2397
|
<body>
|
|
1602
|
-
${watermarkHtml} <div class="document-container">
|
|
1603
|
-
${bodyHtml} </div>
|
|
2398
|
+
${watermarkHtml}${coverHtml} <div class="document-container">
|
|
2399
|
+
${bodyHtml}${footnotesHtml}${signaturesHtml} </div>
|
|
1604
2400
|
${mermaidScript}
|
|
1605
|
-
</body>
|
|
2401
|
+
${backHtml}</body>
|
|
1606
2402
|
</html>`;
|
|
1607
2403
|
}
|
|
1608
2404
|
|
|
1609
2405
|
// src/core/pdf/pdfBuilder.ts
|
|
2406
|
+
import * as fs3 from "fs";
|
|
2407
|
+
import * as path3 from "path";
|
|
2408
|
+
import * as os from "os";
|
|
2409
|
+
import { pathToFileURL } from "url";
|
|
2410
|
+
import { spawnSync } from "child_process";
|
|
2411
|
+
import { PDFDocument } from "pdf-lib";
|
|
2412
|
+
import { encryptPDF } from "@pdfsmaller/pdf-encrypt";
|
|
2413
|
+
function escapeXml(str) {
|
|
2414
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2415
|
+
}
|
|
2416
|
+
function generateWatermarkPngBuffer(chromePath, wm) {
|
|
2417
|
+
const tmpHtml = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.html`);
|
|
2418
|
+
const tmpPng = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
|
|
2419
|
+
try {
|
|
2420
|
+
const text = escapeXml(wm.text.toUpperCase());
|
|
2421
|
+
const fontSize = (wm.fontSize || 52) * 1.5;
|
|
2422
|
+
const color = wm.color || "#E11D48";
|
|
2423
|
+
const opacity = wm.opacity !== void 0 ? wm.opacity : 0.12;
|
|
2424
|
+
const rotate = wm.rotate !== void 0 ? wm.rotate : -45;
|
|
2425
|
+
const html = `<!DOCTYPE html>
|
|
2426
|
+
<html>
|
|
2427
|
+
<head>
|
|
2428
|
+
<meta charset="utf-8">
|
|
2429
|
+
<style>
|
|
2430
|
+
html, body {
|
|
2431
|
+
margin: 0;
|
|
2432
|
+
padding: 0;
|
|
2433
|
+
width: 1200px;
|
|
2434
|
+
height: 1600px;
|
|
2435
|
+
background: transparent;
|
|
2436
|
+
overflow: hidden;
|
|
2437
|
+
}
|
|
2438
|
+
.wm-box {
|
|
2439
|
+
width: 1200px;
|
|
2440
|
+
height: 1600px;
|
|
2441
|
+
display: flex;
|
|
2442
|
+
align-items: center;
|
|
2443
|
+
justify-content: center;
|
|
2444
|
+
transform: rotate(${rotate}deg);
|
|
2445
|
+
}
|
|
2446
|
+
.wm-text {
|
|
2447
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
2448
|
+
font-weight: 900;
|
|
2449
|
+
font-size: ${fontSize}px;
|
|
2450
|
+
color: ${color};
|
|
2451
|
+
opacity: ${opacity};
|
|
2452
|
+
letter-spacing: 0.15em;
|
|
2453
|
+
text-transform: uppercase;
|
|
2454
|
+
white-space: nowrap;
|
|
2455
|
+
}
|
|
2456
|
+
</style>
|
|
2457
|
+
</head>
|
|
2458
|
+
<body>
|
|
2459
|
+
<div class="wm-box"><span class="wm-text">${text}</span></div>
|
|
2460
|
+
</body>
|
|
2461
|
+
</html>`;
|
|
2462
|
+
fs3.writeFileSync(tmpHtml, html, "utf8");
|
|
2463
|
+
const fileUrl = pathToFileURL(tmpHtml).href;
|
|
2464
|
+
const isWin = process.platform === "win32";
|
|
2465
|
+
spawnSync(
|
|
2466
|
+
chromePath,
|
|
2467
|
+
[
|
|
2468
|
+
"--headless=new",
|
|
2469
|
+
"--disable-gpu",
|
|
2470
|
+
"--disable-sync",
|
|
2471
|
+
"--disable-extensions",
|
|
2472
|
+
...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
2473
|
+
`--screenshot=${tmpPng}`,
|
|
2474
|
+
"--window-size=1200,1600",
|
|
2475
|
+
"--default-background-color=00000000",
|
|
2476
|
+
fileUrl
|
|
2477
|
+
],
|
|
2478
|
+
{ timeout: 15e3, windowsHide: true }
|
|
2479
|
+
);
|
|
2480
|
+
if (fs3.existsSync(tmpPng) && fs3.statSync(tmpPng).size > 0) {
|
|
2481
|
+
return fs3.readFileSync(tmpPng);
|
|
2482
|
+
}
|
|
2483
|
+
return null;
|
|
2484
|
+
} catch {
|
|
2485
|
+
return null;
|
|
2486
|
+
} finally {
|
|
2487
|
+
try {
|
|
2488
|
+
if (fs3.existsSync(tmpHtml)) fs3.unlinkSync(tmpHtml);
|
|
2489
|
+
if (fs3.existsSync(tmpPng)) fs3.unlinkSync(tmpPng);
|
|
2490
|
+
} catch {
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
1610
2494
|
function findChromeExecutable() {
|
|
1611
2495
|
if (process.env.CHROME_PATH && fs3.existsSync(process.env.CHROME_PATH)) {
|
|
1612
2496
|
return process.env.CHROME_PATH;
|
|
@@ -1671,7 +2555,7 @@ function findChromeExecutable() {
|
|
|
1671
2555
|
return null;
|
|
1672
2556
|
}
|
|
1673
2557
|
function injectPagedMediaStyles(html, config, metadata) {
|
|
1674
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2558
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1675
2559
|
const resolved = resolveDocumentConfig(metadata || {}, config);
|
|
1676
2560
|
const size = resolved.paperSize;
|
|
1677
2561
|
const orientation = resolved.orientation;
|
|
@@ -1715,6 +2599,38 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
1715
2599
|
${fontStyle}
|
|
1716
2600
|
}`;
|
|
1717
2601
|
};
|
|
2602
|
+
const coverPageCss = ((_a = resolved.coverPage) == null ? void 0 : _a.enabled) ? `
|
|
2603
|
+
@page :first {
|
|
2604
|
+
margin-top: 0;
|
|
2605
|
+
margin-bottom: 0;
|
|
2606
|
+
margin-left: 0;
|
|
2607
|
+
margin-right: 0;
|
|
2608
|
+
background-image: none !important;
|
|
2609
|
+
@top-left { content: none; }
|
|
2610
|
+
@top-center { content: none; }
|
|
2611
|
+
@top-right { content: none; }
|
|
2612
|
+
@bottom-left { content: none; }
|
|
2613
|
+
@bottom-center { content: none; }
|
|
2614
|
+
@bottom-right { content: none; }
|
|
2615
|
+
}` : "";
|
|
2616
|
+
const backCoverCss = ((_b = resolved.backCover) == null ? void 0 : _b.enabled) ? `
|
|
2617
|
+
@page back-cover-page {
|
|
2618
|
+
size: ${size} ${orientation};
|
|
2619
|
+
margin: 0;
|
|
2620
|
+
background-image: none !important;
|
|
2621
|
+
@top-left { content: none; }
|
|
2622
|
+
@top-center { content: none; }
|
|
2623
|
+
@top-right { content: none; }
|
|
2624
|
+
@bottom-left { content: none; }
|
|
2625
|
+
@bottom-center { content: none; }
|
|
2626
|
+
@bottom-right { content: none; }
|
|
2627
|
+
}
|
|
2628
|
+
.markforge-back-cover {
|
|
2629
|
+
page: back-cover-page;
|
|
2630
|
+
min-height: 100vh;
|
|
2631
|
+
height: 100vh;
|
|
2632
|
+
box-sizing: border-box;
|
|
2633
|
+
}` : "";
|
|
1718
2634
|
const pagedCss = `
|
|
1719
2635
|
@page {
|
|
1720
2636
|
size: ${size} ${orientation};
|
|
@@ -1722,15 +2638,18 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
1722
2638
|
margin-bottom: ${bottom};
|
|
1723
2639
|
margin-left: ${left};
|
|
1724
2640
|
margin-right: ${right};
|
|
1725
|
-
${buildZoneCss("top-left", (
|
|
1726
|
-
${buildZoneCss("top-center", (
|
|
1727
|
-
${buildZoneCss("top-right", (
|
|
1728
|
-
${buildZoneCss("bottom-left", (
|
|
1729
|
-
${buildZoneCss("bottom-center", (
|
|
1730
|
-
${buildZoneCss("bottom-right", (
|
|
2641
|
+
${buildZoneCss("top-left", (_c = resolved.header) == null ? void 0 : _c.left)}
|
|
2642
|
+
${buildZoneCss("top-center", (_d = resolved.header) == null ? void 0 : _d.center)}
|
|
2643
|
+
${buildZoneCss("top-right", (_e = resolved.header) == null ? void 0 : _e.right)}
|
|
2644
|
+
${buildZoneCss("bottom-left", (_f = resolved.footer) == null ? void 0 : _f.left)}
|
|
2645
|
+
${buildZoneCss("bottom-center", (_g = resolved.footer) == null ? void 0 : _g.center)}
|
|
2646
|
+
${buildZoneCss("bottom-right", (_h = resolved.footer) == null ? void 0 : _h.right, true)}
|
|
1731
2647
|
}
|
|
2648
|
+
${coverPageCss}
|
|
2649
|
+
${backCoverCss}
|
|
1732
2650
|
@media print {
|
|
1733
2651
|
body { padding: 0; }
|
|
2652
|
+
.document-watermark { display: none !important; }
|
|
1734
2653
|
h1, h2, h3, pre, table, blockquote, .callout {
|
|
1735
2654
|
break-inside: avoid;
|
|
1736
2655
|
}
|
|
@@ -1778,6 +2697,7 @@ startxref
|
|
|
1778
2697
|
return Buffer.from(pdfBody, "utf-8");
|
|
1779
2698
|
}
|
|
1780
2699
|
async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
2700
|
+
var _a, _b, _c;
|
|
1781
2701
|
const baseHtml = await buildHtmlDocument(doc, config, baseDir);
|
|
1782
2702
|
const pagedHtml = injectPagedMediaStyles(baseHtml, config, doc.metadata);
|
|
1783
2703
|
const chromePath = findChromeExecutable();
|
|
@@ -1787,6 +2707,7 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1787
2707
|
const tmpHtml = path3.join(tmpDir, `markforge_${tmpId}.html`);
|
|
1788
2708
|
const tmpPdf = path3.join(tmpDir, `markforge_${tmpId}.pdf`);
|
|
1789
2709
|
const tmpProfile = path3.join(tmpDir, `markforge_prof_${tmpId}`);
|
|
2710
|
+
const isWin = process.platform === "win32";
|
|
1790
2711
|
const isolatedFlags = [
|
|
1791
2712
|
`--user-data-dir=${tmpProfile}`,
|
|
1792
2713
|
"--no-first-run",
|
|
@@ -1797,7 +2718,6 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1797
2718
|
"--disable-default-apps",
|
|
1798
2719
|
"--disable-extensions",
|
|
1799
2720
|
"--disable-domain-reliability",
|
|
1800
|
-
"--disable-client-side-phishing-detection",
|
|
1801
2721
|
"--disable-breakpad",
|
|
1802
2722
|
"--disable-component-extensions-with-background-pages",
|
|
1803
2723
|
"--disable-features=Translate,OptimizationHints,MediaRouter,DialMediaRouteProvider,CalculatedNewTabPage,ChromeWhatsNewUI,PrivacySandboxSettings4",
|
|
@@ -1806,12 +2726,10 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1806
2726
|
"--mute-audio",
|
|
1807
2727
|
"--no-service-autorun",
|
|
1808
2728
|
"--disable-gpu",
|
|
1809
|
-
"--no-sandbox",
|
|
1810
|
-
"--disable-setuid-sandbox",
|
|
1811
|
-
"--allow-file-access-from-files",
|
|
1812
|
-
"--disable-web-security",
|
|
2729
|
+
...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
1813
2730
|
"--force-color-profile=srgb",
|
|
1814
|
-
"--no-pdf-header-footer"
|
|
2731
|
+
"--no-pdf-header-footer",
|
|
2732
|
+
"--window-size=1200,1600"
|
|
1815
2733
|
];
|
|
1816
2734
|
try {
|
|
1817
2735
|
fs3.writeFileSync(tmpHtml, pagedHtml, "utf-8");
|
|
@@ -1826,7 +2744,7 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1826
2744
|
`--print-to-pdf=${tmpPdf}`,
|
|
1827
2745
|
fileUrl
|
|
1828
2746
|
],
|
|
1829
|
-
{ timeout: 3e4 }
|
|
2747
|
+
{ timeout: 3e4, windowsHide: true }
|
|
1830
2748
|
);
|
|
1831
2749
|
if ((res.status !== 0 || !fs3.existsSync(tmpPdf)) && chromePath) {
|
|
1832
2750
|
res = spawnSync(
|
|
@@ -1837,12 +2755,78 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1837
2755
|
`--print-to-pdf=${tmpPdf}`,
|
|
1838
2756
|
fileUrl
|
|
1839
2757
|
],
|
|
1840
|
-
{ timeout: 3e4 }
|
|
2758
|
+
{ timeout: 3e4, windowsHide: true }
|
|
1841
2759
|
);
|
|
1842
2760
|
}
|
|
1843
2761
|
if (fs3.existsSync(tmpPdf) && fs3.statSync(tmpPdf).size > 0) {
|
|
1844
2762
|
const pdfBuffer = fs3.readFileSync(tmpPdf);
|
|
1845
|
-
|
|
2763
|
+
try {
|
|
2764
|
+
const pdfDoc = await PDFDocument.load(pdfBuffer);
|
|
2765
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2766
|
+
if (resolved.title) pdfDoc.setTitle(resolved.title);
|
|
2767
|
+
if (resolved.author) pdfDoc.setAuthor(resolved.author);
|
|
2768
|
+
if (resolved.subtitle) pdfDoc.setSubject(resolved.subtitle);
|
|
2769
|
+
pdfDoc.setCreator("MarkForge Enterprise Document Generator");
|
|
2770
|
+
pdfDoc.setProducer("MarkForge (by Ma'sum)");
|
|
2771
|
+
pdfDoc.setModificationDate(/* @__PURE__ */ new Date());
|
|
2772
|
+
if (((_a = resolved.backCover) == null ? void 0 : _a.enabled) && pdfDoc.getPageCount() > 2) {
|
|
2773
|
+
pdfDoc.removePage(pdfDoc.getPageCount() - 1);
|
|
2774
|
+
}
|
|
2775
|
+
if (resolved.watermark) {
|
|
2776
|
+
const wmPng = generateWatermarkPngBuffer(chromePath, resolved.watermark);
|
|
2777
|
+
if (wmPng) {
|
|
2778
|
+
const embeddedPng = await pdfDoc.embedPng(wmPng);
|
|
2779
|
+
const pages = pdfDoc.getPages();
|
|
2780
|
+
const startPageIndex = ((_b = resolved.coverPage) == null ? void 0 : _b.enabled) ? 1 : 0;
|
|
2781
|
+
const endPageIndex = ((_c = resolved.backCover) == null ? void 0 : _c.enabled) ? pages.length - 1 : pages.length;
|
|
2782
|
+
for (let i = startPageIndex; i < endPageIndex; i++) {
|
|
2783
|
+
const page = pages[i];
|
|
2784
|
+
const { width, height } = page.getSize();
|
|
2785
|
+
page.drawImage(embeddedPng, {
|
|
2786
|
+
x: 0,
|
|
2787
|
+
y: 0,
|
|
2788
|
+
width,
|
|
2789
|
+
height
|
|
2790
|
+
});
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
const savedBytes = await pdfDoc.save();
|
|
2795
|
+
let finalBuffer = Buffer.from(savedBytes);
|
|
2796
|
+
if (resolved.security) {
|
|
2797
|
+
const sec = resolved.security;
|
|
2798
|
+
const hasUserPassword = typeof sec.userPassword === "string" && sec.userPassword.length > 0;
|
|
2799
|
+
const hasOwnerPassword = typeof sec.ownerPassword === "string" && sec.ownerPassword.length > 0;
|
|
2800
|
+
if (hasUserPassword || hasOwnerPassword) {
|
|
2801
|
+
try {
|
|
2802
|
+
const userPass = sec.userPassword ?? "";
|
|
2803
|
+
const ownerPass = sec.ownerPassword ?? userPass;
|
|
2804
|
+
const perms = sec.permissions;
|
|
2805
|
+
const encryptedBytes = await encryptPDF(
|
|
2806
|
+
new Uint8Array(finalBuffer),
|
|
2807
|
+
userPass,
|
|
2808
|
+
{
|
|
2809
|
+
ownerPassword: ownerPass,
|
|
2810
|
+
algorithm: "AES-256",
|
|
2811
|
+
allowPrinting: (perms == null ? void 0 : perms.printing) !== "none",
|
|
2812
|
+
allowHighQualityPrint: (perms == null ? void 0 : perms.printing) === "highResolution",
|
|
2813
|
+
allowModifying: (perms == null ? void 0 : perms.modifying) ?? true,
|
|
2814
|
+
allowCopying: (perms == null ? void 0 : perms.copying) ?? true,
|
|
2815
|
+
allowAnnotating: (perms == null ? void 0 : perms.annotating) ?? true,
|
|
2816
|
+
allowFillingForms: (perms == null ? void 0 : perms.fillingForms) ?? true,
|
|
2817
|
+
allowExtraction: (perms == null ? void 0 : perms.contentAccessibility) ?? true,
|
|
2818
|
+
allowAssembly: (perms == null ? void 0 : perms.documentAssembly) ?? true
|
|
2819
|
+
}
|
|
2820
|
+
);
|
|
2821
|
+
finalBuffer = Buffer.from(encryptedBytes);
|
|
2822
|
+
} catch {
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
return finalBuffer;
|
|
2827
|
+
} catch {
|
|
2828
|
+
return pdfBuffer;
|
|
2829
|
+
}
|
|
1846
2830
|
}
|
|
1847
2831
|
} catch {
|
|
1848
2832
|
} finally {
|
|
@@ -1857,7 +2841,37 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1857
2841
|
return createFallbackPdfBuffer(doc.metadata.title || "MarkForge Document");
|
|
1858
2842
|
}
|
|
1859
2843
|
|
|
2844
|
+
// src/core/docx/docxBuilder.ts
|
|
2845
|
+
import {
|
|
2846
|
+
Document,
|
|
2847
|
+
Paragraph,
|
|
2848
|
+
TextRun,
|
|
2849
|
+
HeadingLevel,
|
|
2850
|
+
Table,
|
|
2851
|
+
TableRow,
|
|
2852
|
+
TableCell,
|
|
2853
|
+
WidthType,
|
|
2854
|
+
BorderStyle,
|
|
2855
|
+
AlignmentType,
|
|
2856
|
+
ImageRun,
|
|
2857
|
+
Header,
|
|
2858
|
+
Footer,
|
|
2859
|
+
PageNumber,
|
|
2860
|
+
Packer,
|
|
2861
|
+
PageOrientation,
|
|
2862
|
+
convertInchesToTwip,
|
|
2863
|
+
convertMillimetersToTwip,
|
|
2864
|
+
ShadingType,
|
|
2865
|
+
ExternalHyperlink,
|
|
2866
|
+
TabStopType
|
|
2867
|
+
} from "docx";
|
|
2868
|
+
|
|
1860
2869
|
// src/core/mermaid/mermaidRenderer.ts
|
|
2870
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
2871
|
+
import * as fs4 from "fs";
|
|
2872
|
+
import * as os2 from "os";
|
|
2873
|
+
import * as path4 from "path";
|
|
2874
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1861
2875
|
async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
|
|
1862
2876
|
const chromePath = findChromeExecutable();
|
|
1863
2877
|
if (!chromePath) {
|
|
@@ -2063,13 +3077,36 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
|
|
|
2063
3077
|
}
|
|
2064
3078
|
runs.push(
|
|
2065
3079
|
new TextRun({
|
|
2066
|
-
text: span.content,
|
|
2067
|
-
color: colorHex,
|
|
2068
|
-
bold: isBold,
|
|
2069
|
-
italics: isItalic,
|
|
2070
|
-
font: options.font,
|
|
2071
|
-
size: options.size,
|
|
2072
|
-
shading: bgHex ? { type: ShadingType.CLEAR, fill: bgHex } : void 0
|
|
3080
|
+
text: span.content,
|
|
3081
|
+
color: colorHex,
|
|
3082
|
+
bold: isBold,
|
|
3083
|
+
italics: isItalic,
|
|
3084
|
+
font: options.font,
|
|
3085
|
+
size: options.size,
|
|
3086
|
+
shading: bgHex ? { type: ShadingType.CLEAR, fill: bgHex } : void 0
|
|
3087
|
+
})
|
|
3088
|
+
);
|
|
3089
|
+
continue;
|
|
3090
|
+
}
|
|
3091
|
+
if (span.type === "mathInline") {
|
|
3092
|
+
runs.push(
|
|
3093
|
+
new TextRun({
|
|
3094
|
+
text: span.content,
|
|
3095
|
+
font: "Cambria Math",
|
|
3096
|
+
italics: true,
|
|
3097
|
+
size: options.size,
|
|
3098
|
+
color: options.color || "0F172A"
|
|
3099
|
+
})
|
|
3100
|
+
);
|
|
3101
|
+
continue;
|
|
3102
|
+
}
|
|
3103
|
+
if (span.type === "footnoteRef") {
|
|
3104
|
+
runs.push(
|
|
3105
|
+
new TextRun({
|
|
3106
|
+
text: `[${span.content}]`,
|
|
3107
|
+
superScript: true,
|
|
3108
|
+
color: "009DA0",
|
|
3109
|
+
bold: true
|
|
2073
3110
|
})
|
|
2074
3111
|
);
|
|
2075
3112
|
continue;
|
|
@@ -2088,7 +3125,7 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
|
|
|
2088
3125
|
return runs;
|
|
2089
3126
|
}
|
|
2090
3127
|
async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
2091
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
3128
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2092
3129
|
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2093
3130
|
const docElements = [];
|
|
2094
3131
|
const themeProps = typeof resolved.theme === "object" ? resolved.theme : {};
|
|
@@ -2099,7 +3136,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2099
3136
|
const borderHex = (themeProps.borderColor || "#E2E8F0").replace("#", "");
|
|
2100
3137
|
const cardBgHex = (themeProps.cardBackground || "#F8FAFC").replace("#", "");
|
|
2101
3138
|
const defaultFont = themeProps.fontFamily ? themeProps.fontFamily.split(",")[0].replace(/['"]/g, "").trim() : "Segoe UI";
|
|
2102
|
-
if (resolved.title) {
|
|
3139
|
+
if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
|
|
2103
3140
|
docElements.push(
|
|
2104
3141
|
new Paragraph({
|
|
2105
3142
|
children: [
|
|
@@ -2515,7 +3552,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2515
3552
|
}
|
|
2516
3553
|
if (node.type === "table" && node.children) {
|
|
2517
3554
|
const tableRows = [];
|
|
2518
|
-
const numCols = ((
|
|
3555
|
+
const numCols = ((_c = (_b = node.children[0]) == null ? void 0 : _b.children) == null ? void 0 : _c.length) || 1;
|
|
2519
3556
|
const colWidth = Math.floor(9e3 / numCols);
|
|
2520
3557
|
for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {
|
|
2521
3558
|
const rowNode = node.children[rowIdx];
|
|
@@ -2525,7 +3562,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2525
3562
|
if (rowNode.children) {
|
|
2526
3563
|
for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {
|
|
2527
3564
|
const cellNode = rowNode.children[colIdx];
|
|
2528
|
-
const align = (
|
|
3565
|
+
const align = (_d = node.align) == null ? void 0 : _d[colIdx];
|
|
2529
3566
|
let alignment = AlignmentType.LEFT;
|
|
2530
3567
|
if (align === "center") alignment = AlignmentType.CENTER;
|
|
2531
3568
|
if (align === "right") alignment = AlignmentType.RIGHT;
|
|
@@ -2664,6 +3701,166 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2664
3701
|
}
|
|
2665
3702
|
continue;
|
|
2666
3703
|
}
|
|
3704
|
+
if (node.type === "mathBlock") {
|
|
3705
|
+
docElements.push(
|
|
3706
|
+
new Paragraph({
|
|
3707
|
+
alignment: AlignmentType.CENTER,
|
|
3708
|
+
children: [
|
|
3709
|
+
new TextRun({
|
|
3710
|
+
text: node.text || "",
|
|
3711
|
+
font: "Cambria Math",
|
|
3712
|
+
italics: true,
|
|
3713
|
+
size: 24,
|
|
3714
|
+
// 12pt
|
|
3715
|
+
color: textHex
|
|
3716
|
+
})
|
|
3717
|
+
],
|
|
3718
|
+
spacing: { before: 180, after: 180 },
|
|
3719
|
+
shading: { fill: cardBgHex, type: ShadingType.CLEAR },
|
|
3720
|
+
border: {
|
|
3721
|
+
top: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3722
|
+
bottom: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3723
|
+
left: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3724
|
+
right: { style: BorderStyle.SINGLE, size: 4, color: borderHex }
|
|
3725
|
+
}
|
|
3726
|
+
})
|
|
3727
|
+
);
|
|
3728
|
+
continue;
|
|
3729
|
+
}
|
|
3730
|
+
if (node.type === "columns") {
|
|
3731
|
+
const cols = node.columnsCount || 2;
|
|
3732
|
+
const contentWidth = Math.max(
|
|
3733
|
+
1e3,
|
|
3734
|
+
resolved.paperDimensions.widthTwip - resolved.margins.leftTwip - resolved.margins.rightTwip
|
|
3735
|
+
);
|
|
3736
|
+
const cellWidthDxa = Math.floor(contentWidth / cols);
|
|
3737
|
+
const cells = [];
|
|
3738
|
+
for (const col of node.children || []) {
|
|
3739
|
+
const colParagraphs = [];
|
|
3740
|
+
for (const childNode of col.children || []) {
|
|
3741
|
+
if (childNode.type === "heading") {
|
|
3742
|
+
const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, bold: true, size: 24, color: primaryDarkHex });
|
|
3743
|
+
colParagraphs.push(new Paragraph({ children: runs, spacing: { before: 120, after: 60 } }));
|
|
3744
|
+
} else if (childNode.type === "paragraph") {
|
|
3745
|
+
const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
|
|
3746
|
+
colParagraphs.push(new Paragraph({ children: runs, spacing: { after: 100 } }));
|
|
3747
|
+
} else if (childNode.type === "list" && childNode.children) {
|
|
3748
|
+
for (const item of childNode.children) {
|
|
3749
|
+
const runs = await convertInlinesToTextRuns(item.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
|
|
3750
|
+
colParagraphs.push(new Paragraph({ children: [new TextRun({ text: "\u2022 ", font: defaultFont, color: primaryHex }), ...runs], spacing: { after: 40 } }));
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
if (colParagraphs.length === 0) colParagraphs.push(new Paragraph({}));
|
|
3755
|
+
cells.push(
|
|
3756
|
+
new TableCell({
|
|
3757
|
+
width: { size: cellWidthDxa, type: WidthType.DXA },
|
|
3758
|
+
borders: {
|
|
3759
|
+
top: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3760
|
+
bottom: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3761
|
+
left: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3762
|
+
right: { style: BorderStyle.NONE, size: 0, color: "auto" }
|
|
3763
|
+
},
|
|
3764
|
+
margins: { top: 60, bottom: 60, left: 100, right: 100 },
|
|
3765
|
+
children: colParagraphs
|
|
3766
|
+
})
|
|
3767
|
+
);
|
|
3768
|
+
}
|
|
3769
|
+
docElements.push(
|
|
3770
|
+
new Table({
|
|
3771
|
+
width: { size: 100, type: WidthType.PERCENTAGE },
|
|
3772
|
+
rows: [new TableRow({ children: cells })]
|
|
3773
|
+
})
|
|
3774
|
+
);
|
|
3775
|
+
docElements.push(new Paragraph({ spacing: { after: 120 } }));
|
|
3776
|
+
continue;
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
3780
|
+
docElements.push(
|
|
3781
|
+
new Paragraph({
|
|
3782
|
+
border: {
|
|
3783
|
+
top: { style: BorderStyle.SINGLE, size: 4, color: borderHex, space: 8 }
|
|
3784
|
+
},
|
|
3785
|
+
spacing: { before: 360, after: 120 }
|
|
3786
|
+
})
|
|
3787
|
+
);
|
|
3788
|
+
for (const def of doc.footnoteDefs) {
|
|
3789
|
+
const defRuns = await convertInlinesToTextRuns(def.inlines, baseDir, {
|
|
3790
|
+
font: defaultFont,
|
|
3791
|
+
size: 18,
|
|
3792
|
+
// 9pt
|
|
3793
|
+
color: textMutedHex
|
|
3794
|
+
});
|
|
3795
|
+
docElements.push(
|
|
3796
|
+
new Paragraph({
|
|
3797
|
+
children: [
|
|
3798
|
+
new TextRun({
|
|
3799
|
+
text: `[${def.id}] `,
|
|
3800
|
+
bold: true,
|
|
3801
|
+
color: primaryDarkHex,
|
|
3802
|
+
font: defaultFont,
|
|
3803
|
+
size: 18
|
|
3804
|
+
}),
|
|
3805
|
+
...defRuns
|
|
3806
|
+
],
|
|
3807
|
+
spacing: { after: 60 }
|
|
3808
|
+
})
|
|
3809
|
+
);
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
if (resolved.signatures && resolved.signatures.items.length > 0) {
|
|
3813
|
+
const sig = resolved.signatures;
|
|
3814
|
+
const numItems = sig.items.length;
|
|
3815
|
+
const contentWidth = Math.max(
|
|
3816
|
+
1e3,
|
|
3817
|
+
resolved.paperDimensions.widthTwip - resolved.margins.leftTwip - resolved.margins.rightTwip
|
|
3818
|
+
);
|
|
3819
|
+
docElements.push(new Paragraph({ spacing: { before: sig.spacingBeforeTwip } }));
|
|
3820
|
+
const sigCells = [];
|
|
3821
|
+
const colWidths = [];
|
|
3822
|
+
if (numItems === 1) {
|
|
3823
|
+
const cardWidth = Math.min(3400, Math.floor(contentWidth * 0.42));
|
|
3824
|
+
const spacerWidth = contentWidth - cardWidth;
|
|
3825
|
+
const cardCell = await buildDocxSignatureCell(sig.items[0], sig, cardWidth, defaultFont, baseDir);
|
|
3826
|
+
if (sig.align === "left") {
|
|
3827
|
+
colWidths.push(cardWidth, spacerWidth);
|
|
3828
|
+
sigCells.push(cardCell, createEmptyDocxCell(spacerWidth));
|
|
3829
|
+
} else if (sig.align === "center") {
|
|
3830
|
+
const sideWidth = Math.floor(spacerWidth / 2);
|
|
3831
|
+
colWidths.push(sideWidth, cardWidth, sideWidth);
|
|
3832
|
+
sigCells.push(createEmptyDocxCell(sideWidth), cardCell, createEmptyDocxCell(sideWidth));
|
|
3833
|
+
} else {
|
|
3834
|
+
colWidths.push(spacerWidth, cardWidth);
|
|
3835
|
+
sigCells.push(createEmptyDocxCell(spacerWidth), cardCell);
|
|
3836
|
+
}
|
|
3837
|
+
} else {
|
|
3838
|
+
const colWidth = Math.floor(contentWidth / numItems);
|
|
3839
|
+
for (let i = 0; i < numItems; i++) {
|
|
3840
|
+
colWidths.push(colWidth);
|
|
3841
|
+
const cell = await buildDocxSignatureCell(sig.items[i], sig, colWidth, defaultFont, baseDir);
|
|
3842
|
+
sigCells.push(cell);
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
const sigTable = new Table({
|
|
3846
|
+
width: { size: 100, type: WidthType.PERCENTAGE },
|
|
3847
|
+
columnWidths: colWidths,
|
|
3848
|
+
borders: {
|
|
3849
|
+
top: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3850
|
+
bottom: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3851
|
+
left: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3852
|
+
right: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3853
|
+
insideHorizontal: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3854
|
+
insideVertical: { style: BorderStyle.NONE, size: 0, color: "auto" }
|
|
3855
|
+
},
|
|
3856
|
+
rows: [
|
|
3857
|
+
new TableRow({
|
|
3858
|
+
cantSplit: true,
|
|
3859
|
+
children: sigCells
|
|
3860
|
+
})
|
|
3861
|
+
]
|
|
3862
|
+
});
|
|
3863
|
+
docElements.push(sigTable);
|
|
2667
3864
|
}
|
|
2668
3865
|
const contentWidthTwip = Math.max(
|
|
2669
3866
|
1e3,
|
|
@@ -2672,7 +3869,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2672
3869
|
const centerPos = Math.round(contentWidthTwip / 2);
|
|
2673
3870
|
const rightPos = contentWidthTwip;
|
|
2674
3871
|
const headerRuns = [];
|
|
2675
|
-
if ((
|
|
3872
|
+
if ((_e = resolved.header) == null ? void 0 : _e.left) {
|
|
2676
3873
|
headerRuns.push(
|
|
2677
3874
|
new TextRun({
|
|
2678
3875
|
text: resolved.header.left.text,
|
|
@@ -2685,7 +3882,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2685
3882
|
);
|
|
2686
3883
|
}
|
|
2687
3884
|
headerRuns.push(new TextRun({ text: " " }));
|
|
2688
|
-
if ((
|
|
3885
|
+
if ((_f = resolved.header) == null ? void 0 : _f.center) {
|
|
2689
3886
|
headerRuns.push(
|
|
2690
3887
|
new TextRun({
|
|
2691
3888
|
text: resolved.header.center.text,
|
|
@@ -2698,7 +3895,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2698
3895
|
);
|
|
2699
3896
|
}
|
|
2700
3897
|
headerRuns.push(new TextRun({ text: " " }));
|
|
2701
|
-
if ((
|
|
3898
|
+
if ((_g = resolved.header) == null ? void 0 : _g.right) {
|
|
2702
3899
|
headerRuns.push(
|
|
2703
3900
|
new TextRun({
|
|
2704
3901
|
text: resolved.header.right.text,
|
|
@@ -2710,7 +3907,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2710
3907
|
})
|
|
2711
3908
|
);
|
|
2712
3909
|
}
|
|
2713
|
-
const docHeader = resolved.header ? new
|
|
3910
|
+
const docHeader = resolved.header ? new Header({
|
|
2714
3911
|
children: [
|
|
2715
3912
|
new Paragraph({
|
|
2716
3913
|
tabStops: [
|
|
@@ -2737,7 +3934,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2737
3934
|
]
|
|
2738
3935
|
}) : void 0;
|
|
2739
3936
|
const footerRuns = [];
|
|
2740
|
-
if ((
|
|
3937
|
+
if ((_h = resolved.footer) == null ? void 0 : _h.left) {
|
|
2741
3938
|
footerRuns.push(
|
|
2742
3939
|
new TextRun({
|
|
2743
3940
|
text: resolved.footer.left.text,
|
|
@@ -2750,7 +3947,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2750
3947
|
);
|
|
2751
3948
|
}
|
|
2752
3949
|
footerRuns.push(new TextRun({ text: " " }));
|
|
2753
|
-
if ((
|
|
3950
|
+
if ((_i = resolved.footer) == null ? void 0 : _i.center) {
|
|
2754
3951
|
footerRuns.push(
|
|
2755
3952
|
new TextRun({
|
|
2756
3953
|
text: resolved.footer.center.text,
|
|
@@ -2763,7 +3960,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2763
3960
|
);
|
|
2764
3961
|
}
|
|
2765
3962
|
footerRuns.push(new TextRun({ text: " " }));
|
|
2766
|
-
if ((
|
|
3963
|
+
if ((_j = resolved.footer) == null ? void 0 : _j.right) {
|
|
2767
3964
|
const rZone = resolved.footer.right;
|
|
2768
3965
|
const rColor = rZone.color.replace("#", "");
|
|
2769
3966
|
const rSize = (rZone.fontSize || 9) * 2;
|
|
@@ -2848,6 +4045,91 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2848
4045
|
]
|
|
2849
4046
|
}) : void 0;
|
|
2850
4047
|
const isLandscape = resolved.orientation === "landscape";
|
|
4048
|
+
const docSections = [];
|
|
4049
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
4050
|
+
const coverElements = await buildDocxCoverPageElements(
|
|
4051
|
+
resolved.coverPage,
|
|
4052
|
+
defaultFont,
|
|
4053
|
+
textHex,
|
|
4054
|
+
primaryHex,
|
|
4055
|
+
primaryDarkHex,
|
|
4056
|
+
textMutedHex,
|
|
4057
|
+
baseDir
|
|
4058
|
+
);
|
|
4059
|
+
docSections.push({
|
|
4060
|
+
properties: {
|
|
4061
|
+
page: {
|
|
4062
|
+
size: {
|
|
4063
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4064
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4065
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4066
|
+
},
|
|
4067
|
+
margin: {
|
|
4068
|
+
top: resolved.margins.topTwip,
|
|
4069
|
+
bottom: resolved.margins.bottomTwip,
|
|
4070
|
+
left: resolved.margins.leftTwip,
|
|
4071
|
+
right: resolved.margins.rightTwip
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
},
|
|
4075
|
+
headers: void 0,
|
|
4076
|
+
footers: void 0,
|
|
4077
|
+
children: coverElements
|
|
4078
|
+
});
|
|
4079
|
+
}
|
|
4080
|
+
docSections.push({
|
|
4081
|
+
properties: {
|
|
4082
|
+
page: {
|
|
4083
|
+
size: {
|
|
4084
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4085
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4086
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4087
|
+
},
|
|
4088
|
+
margin: {
|
|
4089
|
+
top: resolved.margins.topTwip,
|
|
4090
|
+
bottom: resolved.margins.bottomTwip,
|
|
4091
|
+
left: resolved.margins.leftTwip,
|
|
4092
|
+
right: resolved.margins.rightTwip,
|
|
4093
|
+
header: 720,
|
|
4094
|
+
footer: 720
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
},
|
|
4098
|
+
headers: docHeader ? { default: docHeader } : void 0,
|
|
4099
|
+
footers: docFooter ? { default: docFooter } : void 0,
|
|
4100
|
+
children: docElements
|
|
4101
|
+
});
|
|
4102
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
4103
|
+
const backElements = await buildDocxBackCoverElements(
|
|
4104
|
+
resolved.backCover,
|
|
4105
|
+
defaultFont,
|
|
4106
|
+
textHex,
|
|
4107
|
+
primaryHex,
|
|
4108
|
+
primaryDarkHex,
|
|
4109
|
+
textMutedHex,
|
|
4110
|
+
baseDir
|
|
4111
|
+
);
|
|
4112
|
+
docSections.push({
|
|
4113
|
+
properties: {
|
|
4114
|
+
page: {
|
|
4115
|
+
size: {
|
|
4116
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4117
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4118
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4119
|
+
},
|
|
4120
|
+
margin: {
|
|
4121
|
+
top: resolved.margins.topTwip,
|
|
4122
|
+
bottom: resolved.margins.bottomTwip,
|
|
4123
|
+
left: resolved.margins.leftTwip,
|
|
4124
|
+
right: resolved.margins.rightTwip
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
},
|
|
4128
|
+
headers: void 0,
|
|
4129
|
+
footers: void 0,
|
|
4130
|
+
children: backElements
|
|
4131
|
+
});
|
|
4132
|
+
}
|
|
2851
4133
|
const document = new Document({
|
|
2852
4134
|
styles: {
|
|
2853
4135
|
default: {
|
|
@@ -2868,146 +4150,388 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2868
4150
|
}
|
|
2869
4151
|
}
|
|
2870
4152
|
},
|
|
2871
|
-
sections:
|
|
2872
|
-
{
|
|
2873
|
-
properties: {
|
|
2874
|
-
page: {
|
|
2875
|
-
size: {
|
|
2876
|
-
width: resolved.paperDimensions.widthTwip,
|
|
2877
|
-
height: resolved.paperDimensions.heightTwip,
|
|
2878
|
-
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
2879
|
-
},
|
|
2880
|
-
margin: {
|
|
2881
|
-
top: resolved.margins.topTwip,
|
|
2882
|
-
bottom: resolved.margins.bottomTwip,
|
|
2883
|
-
left: resolved.margins.leftTwip,
|
|
2884
|
-
right: resolved.margins.rightTwip,
|
|
2885
|
-
header: 720,
|
|
2886
|
-
footer: 720
|
|
2887
|
-
}
|
|
2888
|
-
}
|
|
2889
|
-
},
|
|
2890
|
-
headers: docHeader ? { default: docHeader } : void 0,
|
|
2891
|
-
footers: docFooter ? { default: docFooter } : void 0,
|
|
2892
|
-
children: docElements
|
|
2893
|
-
}
|
|
2894
|
-
]
|
|
4153
|
+
sections: docSections
|
|
2895
4154
|
});
|
|
2896
4155
|
return await Packer.toBuffer(document);
|
|
2897
4156
|
}
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
4157
|
+
async function buildDocxBackCoverElements(backCover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
|
|
4158
|
+
var _a;
|
|
4159
|
+
const elements = [];
|
|
4160
|
+
elements.push(new Paragraph({ spacing: { before: 1800 } }));
|
|
4161
|
+
if (backCover.logo) {
|
|
4162
|
+
const resolvedLogo = await resolveImage(backCover.logo, baseDir);
|
|
4163
|
+
if (resolvedLogo) {
|
|
4164
|
+
const logoW = typeof backCover.logoWidth === "number" ? backCover.logoWidth : 140;
|
|
4165
|
+
const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
|
|
4166
|
+
elements.push(
|
|
4167
|
+
new Paragraph({
|
|
4168
|
+
children: [
|
|
4169
|
+
new ImageRun({
|
|
4170
|
+
data: resolvedLogo.buffer,
|
|
4171
|
+
transformation: {
|
|
4172
|
+
width: logoW,
|
|
4173
|
+
height: Math.round(logoW * 0.75)
|
|
4174
|
+
},
|
|
4175
|
+
type: logoType
|
|
4176
|
+
})
|
|
4177
|
+
],
|
|
4178
|
+
spacing: { after: 240 }
|
|
4179
|
+
})
|
|
4180
|
+
);
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
if (backCover.badge) {
|
|
4184
|
+
elements.push(
|
|
4185
|
+
new Paragraph({
|
|
4186
|
+
children: [
|
|
4187
|
+
new TextRun({
|
|
4188
|
+
text: `[ ${backCover.badge.toUpperCase()} ]`,
|
|
4189
|
+
font: defaultFont,
|
|
4190
|
+
size: 20,
|
|
4191
|
+
bold: true,
|
|
4192
|
+
color: primaryDarkHex
|
|
4193
|
+
})
|
|
4194
|
+
],
|
|
4195
|
+
spacing: { after: 240 }
|
|
4196
|
+
})
|
|
4197
|
+
);
|
|
4198
|
+
}
|
|
4199
|
+
elements.push(
|
|
4200
|
+
new Paragraph({
|
|
4201
|
+
children: [
|
|
4202
|
+
new TextRun({
|
|
4203
|
+
text: backCover.title,
|
|
4204
|
+
font: defaultFont,
|
|
4205
|
+
size: 52,
|
|
4206
|
+
// 26pt
|
|
4207
|
+
bold: true,
|
|
4208
|
+
color: textHex
|
|
4209
|
+
})
|
|
4210
|
+
],
|
|
4211
|
+
spacing: { after: 140 }
|
|
4212
|
+
})
|
|
4213
|
+
);
|
|
4214
|
+
if (backCover.subtitle) {
|
|
4215
|
+
elements.push(
|
|
4216
|
+
new Paragraph({
|
|
4217
|
+
children: [
|
|
4218
|
+
new TextRun({
|
|
4219
|
+
text: backCover.subtitle,
|
|
4220
|
+
font: defaultFont,
|
|
4221
|
+
size: 24,
|
|
4222
|
+
// 12pt
|
|
4223
|
+
color: textMutedHex
|
|
4224
|
+
})
|
|
4225
|
+
],
|
|
4226
|
+
spacing: { after: 480 }
|
|
4227
|
+
})
|
|
4228
|
+
);
|
|
4229
|
+
}
|
|
4230
|
+
elements.push(
|
|
4231
|
+
new Paragraph({
|
|
4232
|
+
border: {
|
|
4233
|
+
bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
|
|
4234
|
+
},
|
|
4235
|
+
spacing: { after: 480 }
|
|
4236
|
+
})
|
|
4237
|
+
);
|
|
4238
|
+
const contactRuns = [];
|
|
4239
|
+
if (backCover.company) contactRuns.push(new TextRun({ text: `Organization: ${backCover.company}
|
|
4240
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4241
|
+
if (backCover.address) contactRuns.push(new TextRun({ text: `Address: ${backCover.address}
|
|
4242
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4243
|
+
if (backCover.email) contactRuns.push(new TextRun({ text: `Email: ${backCover.email}
|
|
4244
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4245
|
+
if (backCover.phone) contactRuns.push(new TextRun({ text: `Phone: ${backCover.phone}
|
|
4246
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4247
|
+
if (backCover.website) contactRuns.push(new TextRun({ text: `Website: ${backCover.website}
|
|
4248
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4249
|
+
if (backCover.social) {
|
|
4250
|
+
for (const [net, url] of Object.entries(backCover.social)) {
|
|
4251
|
+
if (url) {
|
|
4252
|
+
contactRuns.push(new TextRun({ text: `${net.toUpperCase()}: ${url}
|
|
4253
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
2960
4254
|
}
|
|
2961
|
-
} catch (err) {
|
|
2962
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2963
|
-
errors.push(`Failed to generate ${fmt}: ${errMsg}`);
|
|
2964
4255
|
}
|
|
2965
4256
|
}
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
}
|
|
4257
|
+
if (contactRuns.length > 0) {
|
|
4258
|
+
elements.push(
|
|
4259
|
+
new Paragraph({
|
|
4260
|
+
children: contactRuns,
|
|
4261
|
+
spacing: { before: 360, after: 360 }
|
|
4262
|
+
})
|
|
4263
|
+
);
|
|
4264
|
+
}
|
|
4265
|
+
if (backCover.copyright) {
|
|
4266
|
+
elements.push(
|
|
4267
|
+
new Paragraph({
|
|
4268
|
+
children: [
|
|
4269
|
+
new TextRun({
|
|
4270
|
+
text: backCover.copyright,
|
|
4271
|
+
font: defaultFont,
|
|
4272
|
+
size: 18,
|
|
4273
|
+
color: "94A3B8"
|
|
4274
|
+
})
|
|
4275
|
+
],
|
|
4276
|
+
spacing: { before: 720 }
|
|
4277
|
+
})
|
|
4278
|
+
);
|
|
4279
|
+
}
|
|
4280
|
+
return elements;
|
|
4281
|
+
}
|
|
4282
|
+
async function buildDocxCoverPageElements(cover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
|
|
4283
|
+
var _a;
|
|
4284
|
+
const elements = [];
|
|
4285
|
+
elements.push(new Paragraph({ spacing: { before: 1800 } }));
|
|
4286
|
+
if (cover.logo) {
|
|
4287
|
+
const resolvedLogo = await resolveImage(cover.logo, baseDir);
|
|
4288
|
+
if (resolvedLogo) {
|
|
4289
|
+
const logoW = typeof cover.logoWidth === "number" ? cover.logoWidth : 140;
|
|
4290
|
+
const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
|
|
4291
|
+
elements.push(
|
|
4292
|
+
new Paragraph({
|
|
4293
|
+
children: [
|
|
4294
|
+
new ImageRun({
|
|
4295
|
+
data: resolvedLogo.buffer,
|
|
4296
|
+
transformation: {
|
|
4297
|
+
width: logoW,
|
|
4298
|
+
height: Math.round(logoW * 0.75)
|
|
4299
|
+
},
|
|
4300
|
+
type: logoType
|
|
4301
|
+
})
|
|
4302
|
+
],
|
|
4303
|
+
spacing: { after: 240 }
|
|
4304
|
+
})
|
|
4305
|
+
);
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
if (cover.badge) {
|
|
4309
|
+
elements.push(
|
|
4310
|
+
new Paragraph({
|
|
4311
|
+
children: [
|
|
4312
|
+
new TextRun({
|
|
4313
|
+
text: `[ ${cover.badge.toUpperCase()} ]`,
|
|
4314
|
+
font: defaultFont,
|
|
4315
|
+
size: 20,
|
|
4316
|
+
bold: true,
|
|
4317
|
+
color: primaryDarkHex
|
|
4318
|
+
})
|
|
4319
|
+
],
|
|
4320
|
+
spacing: { after: 240 }
|
|
4321
|
+
})
|
|
4322
|
+
);
|
|
4323
|
+
}
|
|
4324
|
+
elements.push(
|
|
4325
|
+
new Paragraph({
|
|
4326
|
+
children: [
|
|
4327
|
+
new TextRun({
|
|
4328
|
+
text: cover.title,
|
|
4329
|
+
font: defaultFont,
|
|
4330
|
+
size: 56,
|
|
4331
|
+
// 28pt
|
|
4332
|
+
bold: true,
|
|
4333
|
+
color: textHex
|
|
4334
|
+
})
|
|
4335
|
+
],
|
|
4336
|
+
spacing: { after: 140 }
|
|
4337
|
+
})
|
|
4338
|
+
);
|
|
4339
|
+
if (cover.subtitle) {
|
|
4340
|
+
elements.push(
|
|
4341
|
+
new Paragraph({
|
|
4342
|
+
children: [
|
|
4343
|
+
new TextRun({
|
|
4344
|
+
text: cover.subtitle,
|
|
4345
|
+
font: defaultFont,
|
|
4346
|
+
size: 26,
|
|
4347
|
+
// 13pt
|
|
4348
|
+
color: textMutedHex
|
|
4349
|
+
})
|
|
4350
|
+
],
|
|
4351
|
+
spacing: { after: 480 }
|
|
4352
|
+
})
|
|
4353
|
+
);
|
|
4354
|
+
}
|
|
4355
|
+
elements.push(
|
|
4356
|
+
new Paragraph({
|
|
4357
|
+
border: {
|
|
4358
|
+
bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
|
|
4359
|
+
},
|
|
4360
|
+
spacing: { after: 480 }
|
|
4361
|
+
})
|
|
4362
|
+
);
|
|
4363
|
+
if (cover.company || cover.author || cover.version || cover.date) {
|
|
4364
|
+
const metaRuns = [];
|
|
4365
|
+
if (cover.company) metaRuns.push(new TextRun({ text: `Organization: ${cover.company}
|
|
4366
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4367
|
+
if (cover.author) metaRuns.push(new TextRun({ text: `Author: ${cover.author}
|
|
4368
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4369
|
+
if (cover.version) metaRuns.push(new TextRun({ text: `Version: ${cover.version}
|
|
4370
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4371
|
+
if (cover.date) metaRuns.push(new TextRun({ text: `Date: ${cover.date}
|
|
4372
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4373
|
+
elements.push(
|
|
4374
|
+
new Paragraph({
|
|
4375
|
+
children: metaRuns,
|
|
4376
|
+
spacing: { before: 360, after: 360 }
|
|
4377
|
+
})
|
|
4378
|
+
);
|
|
4379
|
+
}
|
|
4380
|
+
if (cover.footerText) {
|
|
4381
|
+
elements.push(
|
|
4382
|
+
new Paragraph({
|
|
4383
|
+
children: [
|
|
4384
|
+
new TextRun({
|
|
4385
|
+
text: cover.footerText,
|
|
4386
|
+
font: defaultFont,
|
|
4387
|
+
size: 18,
|
|
4388
|
+
color: "94A3B8"
|
|
4389
|
+
})
|
|
4390
|
+
],
|
|
4391
|
+
spacing: { before: 720 }
|
|
4392
|
+
})
|
|
4393
|
+
);
|
|
4394
|
+
}
|
|
4395
|
+
return elements;
|
|
4396
|
+
}
|
|
4397
|
+
async function buildDocxSignatureCell(item, sig, widthDxa, defaultFont, baseDir) {
|
|
4398
|
+
const cellParagraphs = [];
|
|
4399
|
+
if (item.title) {
|
|
4400
|
+
cellParagraphs.push(
|
|
4401
|
+
new Paragraph({
|
|
4402
|
+
children: [
|
|
4403
|
+
new TextRun({
|
|
4404
|
+
text: item.title,
|
|
4405
|
+
font: defaultFont,
|
|
4406
|
+
size: 18,
|
|
4407
|
+
// 9pt
|
|
4408
|
+
color: sig.titleColor.replace("#", ""),
|
|
4409
|
+
bold: true
|
|
4410
|
+
})
|
|
4411
|
+
],
|
|
4412
|
+
spacing: { after: 60 }
|
|
4413
|
+
})
|
|
4414
|
+
);
|
|
4415
|
+
}
|
|
4416
|
+
if (item.image) {
|
|
4417
|
+
const resolvedImg = await resolveImage(item.image, baseDir);
|
|
4418
|
+
if (resolvedImg) {
|
|
4419
|
+
cellParagraphs.push(
|
|
4420
|
+
new Paragraph({
|
|
4421
|
+
children: [
|
|
4422
|
+
new ImageRun({
|
|
4423
|
+
data: resolvedImg.buffer,
|
|
4424
|
+
transformation: {
|
|
4425
|
+
width: 140,
|
|
4426
|
+
height: 60
|
|
4427
|
+
},
|
|
4428
|
+
type: "png"
|
|
4429
|
+
})
|
|
4430
|
+
],
|
|
4431
|
+
spacing: { before: 40, after: 40 }
|
|
4432
|
+
})
|
|
4433
|
+
);
|
|
4434
|
+
} else {
|
|
4435
|
+
cellParagraphs.push(new Paragraph({ spacing: { before: 240, after: 240 } }));
|
|
4436
|
+
}
|
|
4437
|
+
} else {
|
|
4438
|
+
cellParagraphs.push(new Paragraph({ spacing: { before: 240, after: 240 } }));
|
|
4439
|
+
}
|
|
4440
|
+
if (sig.style === "line") {
|
|
4441
|
+
cellParagraphs.push(
|
|
4442
|
+
new Paragraph({
|
|
4443
|
+
border: {
|
|
4444
|
+
bottom: {
|
|
4445
|
+
style: BorderStyle.SINGLE,
|
|
4446
|
+
size: 6,
|
|
4447
|
+
space: 2,
|
|
4448
|
+
color: sig.borderColor.replace("#", "")
|
|
4449
|
+
}
|
|
4450
|
+
},
|
|
4451
|
+
spacing: { after: 60 }
|
|
4452
|
+
})
|
|
4453
|
+
);
|
|
4454
|
+
}
|
|
4455
|
+
cellParagraphs.push(
|
|
4456
|
+
new Paragraph({
|
|
4457
|
+
children: [
|
|
4458
|
+
new TextRun({
|
|
4459
|
+
text: item.name,
|
|
4460
|
+
font: defaultFont,
|
|
4461
|
+
size: 21,
|
|
4462
|
+
// 10.5pt
|
|
4463
|
+
bold: true,
|
|
4464
|
+
color: sig.nameColor.replace("#", "")
|
|
4465
|
+
})
|
|
4466
|
+
],
|
|
4467
|
+
spacing: { before: sig.style === "line" ? 40 : 20, after: 20 }
|
|
4468
|
+
})
|
|
4469
|
+
);
|
|
4470
|
+
if (item.role) {
|
|
4471
|
+
cellParagraphs.push(
|
|
4472
|
+
new Paragraph({
|
|
4473
|
+
children: [
|
|
4474
|
+
new TextRun({
|
|
4475
|
+
text: item.role,
|
|
4476
|
+
font: defaultFont,
|
|
4477
|
+
size: 18,
|
|
4478
|
+
// 9pt
|
|
4479
|
+
color: sig.roleColor.replace("#", "")
|
|
4480
|
+
})
|
|
4481
|
+
],
|
|
4482
|
+
spacing: { after: 20 }
|
|
4483
|
+
})
|
|
4484
|
+
);
|
|
4485
|
+
}
|
|
4486
|
+
if (item.date) {
|
|
4487
|
+
cellParagraphs.push(
|
|
4488
|
+
new Paragraph({
|
|
4489
|
+
children: [
|
|
4490
|
+
new TextRun({
|
|
4491
|
+
text: `Date: ${item.date}`,
|
|
4492
|
+
font: defaultFont,
|
|
4493
|
+
size: 17,
|
|
4494
|
+
// 8.5pt
|
|
4495
|
+
color: sig.roleColor.replace("#", "")
|
|
4496
|
+
})
|
|
4497
|
+
],
|
|
4498
|
+
spacing: { after: 20 }
|
|
4499
|
+
})
|
|
4500
|
+
);
|
|
4501
|
+
}
|
|
4502
|
+
const isBox = sig.style === "box";
|
|
4503
|
+
const boxBorder = { style: BorderStyle.SINGLE, size: 4, color: sig.borderColor.replace("#", "") };
|
|
4504
|
+
const noneBorder = { style: BorderStyle.NONE, size: 0, color: "auto" };
|
|
4505
|
+
return new TableCell({
|
|
4506
|
+
width: { size: widthDxa, type: WidthType.DXA },
|
|
4507
|
+
shading: isBox ? { fill: "F8FAFC", type: ShadingType.CLEAR } : void 0,
|
|
4508
|
+
margins: isBox ? { top: 140, bottom: 140, left: 160, right: 160 } : { top: 60, bottom: 60, left: 60, right: 60 },
|
|
4509
|
+
borders: {
|
|
4510
|
+
top: isBox ? boxBorder : noneBorder,
|
|
4511
|
+
bottom: isBox ? boxBorder : noneBorder,
|
|
4512
|
+
left: isBox ? boxBorder : noneBorder,
|
|
4513
|
+
right: isBox ? boxBorder : noneBorder
|
|
4514
|
+
},
|
|
4515
|
+
children: cellParagraphs
|
|
4516
|
+
});
|
|
4517
|
+
}
|
|
4518
|
+
function createEmptyDocxCell(widthDxa) {
|
|
4519
|
+
const noneBorder = { style: BorderStyle.NONE, size: 0, color: "auto" };
|
|
4520
|
+
return new TableCell({
|
|
4521
|
+
width: { size: widthDxa, type: WidthType.DXA },
|
|
4522
|
+
borders: {
|
|
4523
|
+
top: noneBorder,
|
|
4524
|
+
bottom: noneBorder,
|
|
4525
|
+
left: noneBorder,
|
|
4526
|
+
right: noneBorder
|
|
4527
|
+
},
|
|
4528
|
+
children: [new Paragraph({})]
|
|
4529
|
+
});
|
|
2974
4530
|
}
|
|
2975
4531
|
|
|
2976
|
-
// src/ui/App.tsx
|
|
2977
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2978
|
-
var App = ({ inputFile, config, onComplete }) => {
|
|
2979
|
-
const [status, setStatus] = useState("Initializing...");
|
|
2980
|
-
const [isCompiling, setIsCompiling] = useState(true);
|
|
2981
|
-
const [result, setResult] = useState(null);
|
|
2982
|
-
useEffect(() => {
|
|
2983
|
-
async function run() {
|
|
2984
|
-
try {
|
|
2985
|
-
const res = await compileMarkdown(inputFile, config, (msg) => setStatus(msg));
|
|
2986
|
-
setResult(res);
|
|
2987
|
-
setIsCompiling(false);
|
|
2988
|
-
onComplete == null ? void 0 : onComplete(res);
|
|
2989
|
-
} catch (err) {
|
|
2990
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2991
|
-
const errResult = {
|
|
2992
|
-
inputFile,
|
|
2993
|
-
durationMs: 0,
|
|
2994
|
-
metadata: {},
|
|
2995
|
-
files: [],
|
|
2996
|
-
errors: [errMsg]
|
|
2997
|
-
};
|
|
2998
|
-
setResult(errResult);
|
|
2999
|
-
setIsCompiling(false);
|
|
3000
|
-
onComplete == null ? void 0 : onComplete(errResult);
|
|
3001
|
-
}
|
|
3002
|
-
}
|
|
3003
|
-
run();
|
|
3004
|
-
}, [inputFile, config, onComplete]);
|
|
3005
|
-
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
3006
|
-
/* @__PURE__ */ jsx4(Header, { inputFile, theme: config.theme }),
|
|
3007
|
-
/* @__PURE__ */ jsx4(LiveProgress, { status, isCompiling }),
|
|
3008
|
-
/* @__PURE__ */ jsx4(SummaryTable, { result })
|
|
3009
|
-
] });
|
|
3010
|
-
};
|
|
3011
4532
|
export {
|
|
3012
|
-
|
|
4533
|
+
parseMarkdownDocument,
|
|
4534
|
+
buildHtmlDocument,
|
|
4535
|
+
buildPdfDocument,
|
|
4536
|
+
buildDocxDocument
|
|
3013
4537
|
};
|