ghost-paper 0.3.1 → 0.3.2
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.
|
@@ -1138,31 +1138,26 @@ var PRINT_CSS = `
|
|
|
1138
1138
|
.sidebar, .mobile-header, .mobile-dropdown, .mobile-overlay { display: none !important; }
|
|
1139
1139
|
.main { margin-left: 0; min-height: auto; }
|
|
1140
1140
|
|
|
1141
|
-
/* \u2500\u2500 Cover page \u2014 full bleed dark background \u2500\u2500 */
|
|
1141
|
+
/* \u2500\u2500 Cover page \u2014 full bleed dark background, content at bottom \u2500\u2500 */
|
|
1142
1142
|
.print-header {
|
|
1143
1143
|
min-height: 100vh;
|
|
1144
1144
|
display: flex;
|
|
1145
1145
|
flex-direction: column;
|
|
1146
|
-
justify-content: flex-
|
|
1146
|
+
justify-content: flex-end;
|
|
1147
1147
|
background: var(--charcoal);
|
|
1148
1148
|
margin: -0.7in -0.65in 0;
|
|
1149
|
-
padding: calc(0.
|
|
1149
|
+
padding: 56px calc(0.65in + 48px) calc(0.7in + 56px);
|
|
1150
1150
|
page-break-after: always;
|
|
1151
1151
|
break-after: page;
|
|
1152
1152
|
}
|
|
1153
1153
|
.print-title {
|
|
1154
|
-
font-size:
|
|
1154
|
+
font-size: 72px;
|
|
1155
1155
|
font-weight: 700;
|
|
1156
|
-
letter-spacing: -
|
|
1156
|
+
letter-spacing: -3px;
|
|
1157
1157
|
color: #fff;
|
|
1158
|
-
padding-bottom:
|
|
1158
|
+
padding-bottom: 24px;
|
|
1159
1159
|
border-bottom: 5px solid var(--accent);
|
|
1160
|
-
line-height:
|
|
1161
|
-
word-spacing: 100vw;
|
|
1162
|
-
}
|
|
1163
|
-
.print-title .title-minor {
|
|
1164
|
-
color: rgba(255,255,255,0.4);
|
|
1165
|
-
font-weight: 400;
|
|
1160
|
+
line-height: 1.05;
|
|
1166
1161
|
}
|
|
1167
1162
|
.print-subtitle {
|
|
1168
1163
|
font-size: 15px;
|
|
@@ -1235,19 +1230,28 @@ var PRINT_CSS = `
|
|
|
1235
1230
|
}
|
|
1236
1231
|
|
|
1237
1232
|
/* Tables: in-column with light grey box */
|
|
1238
|
-
.
|
|
1239
|
-
|
|
1233
|
+
.table-wrap {
|
|
1234
|
+
overflow: hidden;
|
|
1240
1235
|
margin: 12px 0;
|
|
1241
1236
|
break-inside: avoid;
|
|
1242
|
-
width: 100%;
|
|
1243
1237
|
background: #F6F6F4;
|
|
1238
|
+
border-radius: 4px;
|
|
1239
|
+
}
|
|
1240
|
+
.table-wrap.table-wide { column-span: all; }
|
|
1241
|
+
.tab-content table {
|
|
1242
|
+
font-size: 10px;
|
|
1243
|
+
margin: 0;
|
|
1244
|
+
width: 100%;
|
|
1245
|
+
table-layout: fixed;
|
|
1244
1246
|
border-collapse: separate;
|
|
1245
1247
|
border-spacing: 0;
|
|
1246
|
-
padding:
|
|
1247
|
-
|
|
1248
|
+
padding: 0;
|
|
1249
|
+
background: transparent;
|
|
1250
|
+
border-radius: 0;
|
|
1248
1251
|
}
|
|
1249
|
-
.tab-content
|
|
1250
|
-
.tab-content
|
|
1252
|
+
.tab-content tbody td { word-wrap: break-word; overflow-wrap: break-word; }
|
|
1253
|
+
.tab-content thead th { font-size: 8px; letter-spacing: 0.8px; padding: 8px 10px; border-bottom: 2px solid #D0D0CB; }
|
|
1254
|
+
.tab-content tbody td { padding: 8px 10px; font-weight: 400; border-bottom: 1px solid #E8E8E4; }
|
|
1251
1255
|
.tab-content tbody tr:last-child td { border-bottom: none; }
|
|
1252
1256
|
|
|
1253
1257
|
/* KPIs: compact grid for column width */
|
|
@@ -1273,7 +1277,6 @@ var PRINT_CSS = `
|
|
|
1273
1277
|
.chart-container { height: 190px; overflow: hidden; }
|
|
1274
1278
|
|
|
1275
1279
|
.kpi-strip { break-inside: avoid; page-break-inside: avoid; }
|
|
1276
|
-
table { break-inside: auto; }
|
|
1277
1280
|
thead { display: table-header-group; }
|
|
1278
1281
|
tr { break-inside: avoid; }
|
|
1279
1282
|
|
|
@@ -1353,12 +1356,13 @@ function renderTable(table) {
|
|
|
1353
1356
|
}).join("");
|
|
1354
1357
|
return `<tr>${cells}</tr>`;
|
|
1355
1358
|
}).join("\n ");
|
|
1356
|
-
|
|
1359
|
+
const wideClass = table.headers.length >= 5 ? " table-wide" : "";
|
|
1360
|
+
return ` <div class="table-wrap${wideClass}"><table>
|
|
1357
1361
|
<thead><tr>${thead}</tr></thead>
|
|
1358
1362
|
<tbody>
|
|
1359
1363
|
${tbody}
|
|
1360
1364
|
</tbody>
|
|
1361
|
-
</table>`;
|
|
1365
|
+
</table></div>`;
|
|
1362
1366
|
}
|
|
1363
1367
|
function renderChart(chartId, caption, chartType, rowCount) {
|
|
1364
1368
|
let styleAttr = "";
|
|
@@ -1469,32 +1473,11 @@ function buildChartScript(doc, printMode = false) {
|
|
|
1469
1473
|
if (printMode) return script + "\nwindow.__ghostPaperChartsReady = true;";
|
|
1470
1474
|
return script;
|
|
1471
1475
|
}
|
|
1472
|
-
function stylizePrintTitle(raw) {
|
|
1473
|
-
const MINOR = /* @__PURE__ */ new Set(["the", "a", "an", "for", "of", "in", "and", "or", "to", "with", "by", "on", "at", "is"]);
|
|
1474
|
-
const words = escapeHtml3(raw).split(/\s+/);
|
|
1475
|
-
const result = [];
|
|
1476
|
-
let i = 0;
|
|
1477
|
-
while (i < words.length) {
|
|
1478
|
-
const lower = words[i].toLowerCase();
|
|
1479
|
-
if (i + 1 < words.length && MINOR.has(lower) && MINOR.has(words[i + 1].toLowerCase())) {
|
|
1480
|
-
result.push(`<span class="title-minor" style="white-space:nowrap;word-spacing:normal">${words[i]} ${words[i + 1]}</span>`);
|
|
1481
|
-
i += 2;
|
|
1482
|
-
} else if (MINOR.has(lower)) {
|
|
1483
|
-
result.push(`<span class="title-minor">${words[i]}</span>`);
|
|
1484
|
-
i++;
|
|
1485
|
-
} else {
|
|
1486
|
-
result.push(words[i]);
|
|
1487
|
-
i++;
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
return result.join(" ");
|
|
1491
|
-
}
|
|
1492
1476
|
function buildPrintContent(doc) {
|
|
1493
1477
|
const subtitle = doc.frontmatter.subtitle ? `
|
|
1494
1478
|
<div class="print-subtitle">${escapeHtml3(doc.frontmatter.subtitle)}</div>` : "";
|
|
1495
|
-
const styledTitle = stylizePrintTitle(doc.frontmatter.title);
|
|
1496
1479
|
const header = ` <div class="print-header">
|
|
1497
|
-
<div class="print-title">${
|
|
1480
|
+
<div class="print-title">${escapeHtml3(doc.frontmatter.title)}</div>${subtitle}
|
|
1498
1481
|
</div>`;
|
|
1499
1482
|
const tabs = doc.tabs.map((tab, i) => {
|
|
1500
1483
|
const elements = tab.elements.map(renderElement).join("\n\n");
|
|
@@ -1539,7 +1522,7 @@ function buildPrintHtml(markdown) {
|
|
|
1539
1522
|
async function buildPdf(markdown, outputPath, options) {
|
|
1540
1523
|
const doc = parse(markdown);
|
|
1541
1524
|
const html = render(doc, { printMode: true });
|
|
1542
|
-
const { generatePdf } = await import("./pdf-
|
|
1525
|
+
const { generatePdf } = await import("./pdf-CVTVSJBX.js");
|
|
1543
1526
|
await generatePdf({
|
|
1544
1527
|
html,
|
|
1545
1528
|
outputPath,
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
build
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VH6KYYQG.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -72,7 +72,7 @@ buildCmd.command("pdf").description("Convert a markdown file to a PDF report").a
|
|
|
72
72
|
const inputPath = resolve(input);
|
|
73
73
|
const markdown = readFileSync(inputPath, "utf-8");
|
|
74
74
|
const outputPath = opts.output ? resolve(opts.output) : inputPath.replace(/\.md$/, ".pdf");
|
|
75
|
-
const { buildPdf } = await import("./-
|
|
75
|
+
const { buildPdf } = await import("./-3QXRJ2CJ.js");
|
|
76
76
|
await buildPdf(markdown, outputPath, {
|
|
77
77
|
pageSize: opts.pageSize ?? "A4",
|
|
78
78
|
landscape: opts.landscape ?? false
|
|
@@ -52,8 +52,9 @@ async function generatePdf(opts) {
|
|
|
52
52
|
});
|
|
53
53
|
await new Promise((r) => setTimeout(r, 300));
|
|
54
54
|
const title = escapeHtml(opts.title ?? "");
|
|
55
|
-
const
|
|
56
|
-
const
|
|
55
|
+
const hideOnPage1 = `<script>if(document.querySelector('.pageNumber').textContent==='1')document.querySelector('#c').style.display='none';</script>`;
|
|
56
|
+
const headerTemplate = `<div style="font-size: 8px; font-family: -apple-system, system-ui, sans-serif; color: #999; width: 100%; padding: 0 0.65in; letter-spacing: 0.5px; text-transform: uppercase;"><span id="c">${title}</span>${hideOnPage1}</div>`;
|
|
57
|
+
const footerTemplate = `<div style="font-size: 8px; font-family: -apple-system, system-ui, sans-serif; color: #999; width: 100%; text-align: right; padding: 0 0.65in;"><span id="c"><span class="pageNumber"></span> / <span class="totalPages"></span></span>${hideOnPage1}</div>`;
|
|
57
58
|
const pdfBuffer = await page.pdf({
|
|
58
59
|
format: opts.pageSize ?? "A4",
|
|
59
60
|
landscape: opts.landscape ?? false,
|