gutterpress 0.11.17 → 0.11.18-alpha.1

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.
Files changed (25) hide show
  1. package/dist/api/index.js +2 -2
  2. package/dist/{build-gxy185pv.js → build-fpd3qp17.js} +4 -4
  3. package/dist/{cli-a4qtctrw.js → cli-1msxnhzy.js} +4 -4
  4. package/dist/{cli-8nw6d915.js → cli-bzz33hjz.js} +1 -1
  5. package/dist/{cli-zfgvssqz.js → cli-gv97c2a6.js} +1 -1
  6. package/dist/{cli-ycbg7mxk.js → cli-th1ve2cx.js} +4 -4
  7. package/dist/cli.js +12 -12
  8. package/dist/{doctor-fygmzevd.js → doctor-cg0kb8h6.js} +2 -2
  9. package/dist/{engine-yf2w9hj7.js → engine-0g9t43gx.js} +1 -1
  10. package/dist/{engine-5d1rpxxq.js → engine-s2caze6b.js} +2 -2
  11. package/dist/{ext-c48s56jm.js → ext-keedd40p.js} +4 -4
  12. package/dist/{gutterpress-viewer-ez7k4ha7.js → gutterpress-viewer-p50c4f08.js} +274 -1
  13. package/dist/{index-09h3n36d.js → index-3pnmf25p.js} +1 -1
  14. package/dist/{index-vmcfahe2.js → index-jg1r9t4w.js} +4 -4
  15. package/dist/{index-3k3fyrec.js → index-pdanxwn1.js} +3 -3
  16. package/dist/index.js +3 -3
  17. package/dist/{new-a9m2jwyy.js → new-d010czw1.js} +4 -4
  18. package/dist/{preflight-w3tnbtb8.js → preflight-jgcp1xsr.js} +4 -4
  19. package/dist/{preview-bridge-8jhd1wpb.js → preview-bridge-ga409pgz.js} +5 -1
  20. package/dist/{preview-interface-c44qk17f.js → preview-interface-dm6wbdq6.js} +71 -1
  21. package/dist/{preview-7z8tt0b4.js → preview-m3afbq53.js} +4 -4
  22. package/dist/{preview-shell-xwn84kqr.js → preview-shell-c909krk2.js} +3 -0
  23. package/dist/{publish-bbftdxh2.js → publish-69x46m3f.js} +4 -4
  24. package/dist/{validate-x1ha1gqj.js → validate-vc6cp1cs.js} +4 -4
  25. package/package.json +1 -1
package/dist/api/index.js CHANGED
@@ -136,11 +136,11 @@ import {
136
136
  testRemoteAccess,
137
137
  updateExtensions,
138
138
  validateProjectExtensions
139
- } from "../index-3k3fyrec.js";
139
+ } from "../index-pdanxwn1.js";
140
140
  import"../index-ht1bcqdd.js";
141
141
  import {
142
142
  BuildError
143
- } from "../index-vmcfahe2.js";
143
+ } from "../index-jg1r9t4w.js";
144
144
  import {
145
145
  DEFAULT_PRINT_OPTS,
146
146
  assertMilestone,
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  runBuild,
3
3
  splitOutPath
4
- } from "./cli-a4qtctrw.js";
4
+ } from "./cli-1msxnhzy.js";
5
5
  import {
6
6
  log
7
- } from "./cli-zfgvssqz.js";
7
+ } from "./cli-gv97c2a6.js";
8
8
  import {
9
9
  UsageError,
10
10
  parseFormat,
11
11
  parsePdfxFlavor,
12
12
  rejectExtraPositionals,
13
13
  rejectUnknownFlags
14
- } from "./cli-8nw6d915.js";
14
+ } from "./cli-bzz33hjz.js";
15
15
  import"./cli-ht1bcqdd.js";
16
- import"./cli-ycbg7mxk.js";
16
+ import"./cli-th1ve2cx.js";
17
17
  import {
18
18
  BuildError
19
19
  } from "./cli-46ycxe6r.js";
@@ -13,12 +13,12 @@ import {
13
13
  stampCreator,
14
14
  stripAnnotations,
15
15
  warn
16
- } from "./cli-zfgvssqz.js";
16
+ } from "./cli-gv97c2a6.js";
17
17
  import {
18
18
  DEBOUNCE,
19
19
  UsageError,
20
20
  resolvePort
21
- } from "./cli-8nw6d915.js";
21
+ } from "./cli-bzz33hjz.js";
22
22
  import {
23
23
  blackTextToGray
24
24
  } from "./cli-ht1bcqdd.js";
@@ -27,7 +27,7 @@ import {
27
27
  getAssetPath,
28
28
  getAssetsDir,
29
29
  lastPageMode
30
- } from "./cli-ycbg7mxk.js";
30
+ } from "./cli-th1ve2cx.js";
31
31
  import {
32
32
  BuildError,
33
33
  EXIT_CODES
@@ -9723,7 +9723,7 @@ class PdfOutput {
9723
9723
  const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
9724
9724
  await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
9725
9725
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
9726
- const { buildNativePdf } = await import("./engine-yf2w9hj7.js");
9726
+ const { buildNativePdf } = await import("./engine-0g9t43gx.js");
9727
9727
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
9728
9728
  title: config.title,
9729
9729
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -4,7 +4,7 @@ import {
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "gutterpress",
7
- version: "0.11.17",
7
+ version: "0.11.18-alpha.1",
8
8
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
9
9
  author: "itlackey",
10
10
  license: "MPL-2.0",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./cli-8nw6d915.js";
3
+ } from "./cli-bzz33hjz.js";
4
4
  import {
5
5
  execCapture,
6
6
  findTool,
@@ -1119,19 +1119,19 @@ var favicon_default = "./favicon-272ga6y0.ico";
1119
1119
  var manifest_schema_default = "./manifest.schema-gh0jjve9.json";
1120
1120
 
1121
1121
  // src/assets/preview/scripts/preview-interface.js
1122
- var preview_interface_default = "./preview-interface-c44qk17f.js";
1122
+ var preview_interface_default = "./preview-interface-dm6wbdq6.js";
1123
1123
 
1124
1124
  // src/assets/preview/scripts/preview-bridge.js
1125
- var preview_bridge_default = "./preview-bridge-8jhd1wpb.js";
1125
+ var preview_bridge_default = "./preview-bridge-ga409pgz.js";
1126
1126
 
1127
1127
  // src/assets/preview/scripts/preview-shell.js
1128
- var preview_shell_default = "./preview-shell-xwn84kqr.js";
1128
+ var preview_shell_default = "./preview-shell-c909krk2.js";
1129
1129
 
1130
1130
  // profiles/CGATS21_CRPC1.icc
1131
1131
  var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
1132
1132
 
1133
1133
  // src/assets/engine/gutterpress-viewer.js
1134
- var gutterpress_viewer_default = "./gutterpress-viewer-ez7k4ha7.js";
1134
+ var gutterpress_viewer_default = "./gutterpress-viewer-p50c4f08.js";
1135
1135
 
1136
1136
  // src/assets/engine/gutterpress-agent.js
1137
1137
  var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  UsageError,
7
7
  package_default,
8
8
  rejectUnknownFlags
9
- } from "./cli-8nw6d915.js";
9
+ } from "./cli-bzz33hjz.js";
10
10
  import {
11
11
  EXIT_CODES
12
12
  } from "./cli-46ycxe6r.js";
@@ -18,14 +18,14 @@ import {
18
18
  import { defineCommand, parseArgs, runMain } from "citty";
19
19
  import { statSync } from "node:fs";
20
20
  var SUBCOMMANDS = {
21
- new: () => import("./new-a9m2jwyy.js").then((m) => m.default),
22
- preview: () => import("./preview-7z8tt0b4.js").then((m) => m.default),
23
- build: () => import("./build-gxy185pv.js").then((m) => m.default),
24
- publish: () => import("./publish-bbftdxh2.js").then((m) => m.default),
25
- validate: () => import("./validate-x1ha1gqj.js").then((m) => m.default),
26
- preflight: () => import("./preflight-w3tnbtb8.js").then((m) => m.default),
27
- doctor: () => import("./doctor-fygmzevd.js").then((m) => m.default),
28
- ext: () => import("./ext-c48s56jm.js").then((m) => m.default)
21
+ new: () => import("./new-d010czw1.js").then((m) => m.default),
22
+ preview: () => import("./preview-m3afbq53.js").then((m) => m.default),
23
+ build: () => import("./build-fpd3qp17.js").then((m) => m.default),
24
+ publish: () => import("./publish-69x46m3f.js").then((m) => m.default),
25
+ validate: () => import("./validate-vc6cp1cs.js").then((m) => m.default),
26
+ preflight: () => import("./preflight-jgcp1xsr.js").then((m) => m.default),
27
+ doctor: () => import("./doctor-cg0kb8h6.js").then((m) => m.default),
28
+ ext: () => import("./ext-keedd40p.js").then((m) => m.default)
29
29
  };
30
30
  var VERSION = package_default.version;
31
31
  var main = defineCommand({
@@ -50,7 +50,7 @@ async function preflightRequiredInvocations(rawArgs) {
50
50
  const [command, ...commandArgs] = rawArgs;
51
51
  try {
52
52
  if (command === "new") {
53
- const { newArgs } = await import("./new-a9m2jwyy.js");
53
+ const { newArgs } = await import("./new-d010czw1.js");
54
54
  rejectUnknownFlags(commandArgs, newArgs, "new");
55
55
  const parsed = parseArgs(commandArgs, {
56
56
  ...newArgs,
@@ -62,7 +62,7 @@ async function preflightRequiredInvocations(rawArgs) {
62
62
  return;
63
63
  }
64
64
  if (command === "preflight") {
65
- const { preflightArgs } = await import("./preflight-w3tnbtb8.js");
65
+ const { preflightArgs } = await import("./preflight-jgcp1xsr.js");
66
66
  rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
67
67
  const parsed = parseArgs(commandArgs, {
68
68
  ...preflightArgs,
@@ -82,7 +82,7 @@ async function preflightRequiredInvocations(rawArgs) {
82
82
  }
83
83
  if (subcommand.startsWith("-"))
84
84
  return;
85
- const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-c48s56jm.js");
85
+ const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-keedd40p.js");
86
86
  if (!EXT_SUBCOMMANDS.includes(subcommand)) {
87
87
  throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
88
88
  }
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getSystemDiagnostics,
3
3
  log
4
- } from "./cli-zfgvssqz.js";
4
+ } from "./cli-gv97c2a6.js";
5
5
  import {
6
6
  UsageError,
7
7
  rejectExtraPositionals,
8
8
  rejectUnknownFlags
9
- } from "./cli-8nw6d915.js";
9
+ } from "./cli-bzz33hjz.js";
10
10
  import"./cli-46ycxe6r.js";
11
11
  import"./cli-7fkhgtfn.js";
12
12
  import"./cli-37x76zdn.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  build
3
- } from "./cli-ycbg7mxk.js";
3
+ } from "./cli-th1ve2cx.js";
4
4
  import {
5
5
  BuildError
6
6
  } from "./cli-46ycxe6r.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  build
3
- } from "./index-09h3n36d.js";
3
+ } from "./index-3pnmf25p.js";
4
4
  import {
5
5
  BuildError
6
- } from "./index-vmcfahe2.js";
6
+ } from "./index-jg1r9t4w.js";
7
7
  import"./index-rzm1phg0.js";
8
8
  import"./index-37x76zdn.js";
9
9
 
@@ -12,17 +12,17 @@ import {
12
12
  searchNpmExtensions,
13
13
  setExtensionEnabled,
14
14
  updateExtensions
15
- } from "./cli-a4qtctrw.js";
16
- import"./cli-zfgvssqz.js";
15
+ } from "./cli-1msxnhzy.js";
16
+ import"./cli-gv97c2a6.js";
17
17
  import {
18
18
  UsageError,
19
19
  exitForUsage,
20
20
  rejectExtraPositionals,
21
21
  rejectUnknownFlags,
22
22
  resolveProjectDir
23
- } from "./cli-8nw6d915.js";
23
+ } from "./cli-bzz33hjz.js";
24
24
  import"./cli-ht1bcqdd.js";
25
- import"./cli-ycbg7mxk.js";
25
+ import"./cli-th1ve2cx.js";
26
26
  import {
27
27
  EXIT_CODES
28
28
  } from "./cli-46ycxe6r.js";
@@ -34,7 +34,9 @@
34
34
  loadStyleSources: () => loadStyleSources,
35
35
  injectViewerCss: () => injectViewerCss,
36
36
  injectBreakMapping: () => injectBreakMapping,
37
+ indexInStrip: () => indexInStrip,
37
38
  fragmentDocument: () => fragmentDocument,
39
+ cssZoomOf: () => cssZoomOf,
38
40
  contentEdgeRect: () => contentEdgeRect,
39
41
  compensateRepeatedHeaders: () => compensateRepeatedHeaders,
40
42
  compensateRectoBreaks: () => compensateRectoBreaks,
@@ -267,6 +269,77 @@
267
269
  .gp-marginbox[data-align="center"] > .gp-marginbox-content { justify-content: center; }
268
270
  .gp-marginbox[data-align="end"] > .gp-marginbox-content { justify-content: flex-end; }
269
271
 
272
+ /* margin & bleed overlay (overlay.ts) -------------------------------- */
273
+ /* One sibling layer per run, ABOVE the strip so the lines stay visible over
274
+ author backgrounds and art. Absolutely positioned and pointer-transparent:
275
+ it takes no flow space and no hits, so it cannot move a page break. Exists
276
+ only while the overlay is on. */
277
+ .gp-ov {
278
+ position: absolute;
279
+ inset: 0;
280
+ z-index: 5;
281
+ pointer-events: none;
282
+ --gp-ov-margin: #2f80ed;
283
+ --gp-ov-bleed: 229 72 77;
284
+ --gp-ov-warn: #f59e0b;
285
+ --gp-ov-error: #e5484d;
286
+ --gp-ov-intent: #8b5cf6;
287
+ }
288
+
289
+ .gp-ov-page {
290
+ position: absolute;
291
+ }
292
+
293
+ /* margin box: thin dashed outline of the content area */
294
+ .gp-ov-margin {
295
+ position: absolute;
296
+ box-sizing: border-box;
297
+ border: 1px dashed var(--gp-ov-margin);
298
+ }
299
+
300
+ /* the PDF's own margins for this page, where they differ from where the
301
+ preview lays the text (mirrored :left/:right, .gp-flush): fainter, dotted */
302
+ .gp-ov-print {
303
+ position: absolute;
304
+ box-sizing: border-box;
305
+ border: 1px dotted var(--gp-ov-margin);
306
+ opacity: 0.55;
307
+ }
308
+
309
+ /* bleed: a translucent band OUTSIDE the trim (its width is the border) */
310
+ .gp-ov-bleed {
311
+ position: absolute;
312
+ box-sizing: border-box;
313
+ border-style: solid;
314
+ border-color: rgb(var(--gp-ov-bleed) / 0.3);
315
+ }
316
+
317
+ /* trim: where the sheet will be cut, drawn only when there is bleed */
318
+ .gp-ov-trim {
319
+ position: absolute;
320
+ inset: 0;
321
+ outline: 1px solid rgb(var(--gp-ov-bleed) / 0.9);
322
+ }
323
+
324
+ /* overflow flags — outline + faint tint, never a box change */
325
+ .gp-ov-flag {
326
+ position: absolute;
327
+ box-sizing: border-box;
328
+ }
329
+ .gp-ov-flag[data-kind="margin"] {
330
+ outline: 2px solid var(--gp-ov-warn);
331
+ background: rgb(245 158 11 / 0.14);
332
+ }
333
+ .gp-ov-flag[data-kind="bleed"],
334
+ .gp-ov-flag[data-kind="off-page"] {
335
+ outline: 2px solid var(--gp-ov-error);
336
+ background: rgb(229 72 77 / 0.16);
337
+ }
338
+ /* placed on purpose (.gp-bleed, .gp-pin, …): present, not a problem */
339
+ .gp-ov-flag[data-kind="intended"] {
340
+ outline: 1px dotted var(--gp-ov-intent);
341
+ }
342
+
270
343
  /* designer mode ------------------------------------------------------- */
271
344
  .gp-guide-trim,
272
345
  .gp-guide-safe,
@@ -310,6 +383,7 @@
310
383
  transform: none;
311
384
  }
312
385
  .gp-layer,
386
+ .gp-ov,
313
387
  .gp-warning,
314
388
  .gp-guide-trim,
315
389
  .gp-guide-safe,
@@ -2067,6 +2141,174 @@
2067
2141
  return /right/.test(name) ? "end" : "start";
2068
2142
  }
2069
2143
 
2144
+ // src/engine/compiler/tier2.ts
2145
+ var DEFAULT_SLUG_PT = 18;
2146
+ function pageGeometry(model, opts) {
2147
+ const base = resolvePage(model);
2148
+ const trim = { width: base.geometry.width, height: base.geometry.height };
2149
+ const bleed = opts.bleedPt ?? base.geometry.bleed;
2150
+ const wantsMarks = base.geometry.marks.length > 0 || opts.marks === true;
2151
+ const slug = wantsMarks ? opts.slugPt ?? DEFAULT_SLUG_PT : 0;
2152
+ return {
2153
+ trim,
2154
+ bleed,
2155
+ slug,
2156
+ marks: base.geometry.marks.length ? base.geometry.marks : wantsMarks ? ["crop"] : [],
2157
+ media: {
2158
+ width: trim.width + 2 * (bleed + slug),
2159
+ height: trim.height + 2 * (bleed + slug)
2160
+ }
2161
+ };
2162
+ }
2163
+
2164
+ // src/engine/viewer/overlay.ts
2165
+ function documentBleedPt(model) {
2166
+ return pageGeometry(model, { model }).bleed;
2167
+ }
2168
+ function pageBoxes(g, margin, bleed, scale = 1) {
2169
+ const w = g.width * scale;
2170
+ const h = g.height * scale;
2171
+ const b = Math.max(0, bleed) * scale;
2172
+ return {
2173
+ trim: { x: 0, y: 0, w, h },
2174
+ content: {
2175
+ x: margin.left * scale,
2176
+ y: margin.top * scale,
2177
+ w: w - (margin.left + margin.right) * scale,
2178
+ h: h - (margin.top + margin.bottom) * scale
2179
+ },
2180
+ bleedBox: { x: -b, y: -b, w: w + 2 * b, h: h + 2 * b },
2181
+ bleed: b
2182
+ };
2183
+ }
2184
+ var SEVERITY = { inside: 0, margin: 1, bleed: 2, "off-page": 3 };
2185
+ var within = (r, outer, tol) => r.x >= outer.x - tol && r.y >= outer.y - tol && r.x + r.w <= outer.x + outer.w + tol && r.y + r.h <= outer.y + outer.h + tol;
2186
+ function classifyRect(r, boxes, tol = 0) {
2187
+ if (within(r, boxes.content, tol))
2188
+ return "inside";
2189
+ if (within(r, boxes.trim, tol))
2190
+ return "margin";
2191
+ if (boxes.bleed > 0 && within(r, boxes.bleedBox, tol))
2192
+ return "bleed";
2193
+ return "off-page";
2194
+ }
2195
+ function worstKind(kinds) {
2196
+ return kinds.reduce((worst, k) => SEVERITY[k] > SEVERITY[worst] ? k : worst, "inside");
2197
+ }
2198
+ var INTENT_SELECTOR = ".gp-bleed, .gp-pin, .gp-flush, .gp-behind, .gp-page-full-bleed";
2199
+ var OVERLAY_OFF = { on: false, issues: 0, intended: 0, bleedPt: 0 };
2200
+ function marginsDiffer(a, b) {
2201
+ return ["top", "right", "bottom", "left"].some((k) => Math.abs(a[k] - b[k]) > 0.5);
2202
+ }
2203
+ var SKIP = new Set(["SCRIPT", "STYLE", "LINK", "TEMPLATE", "BR", "WBR", "SOURCE", "TRACK", "META"]);
2204
+ var TOL_PX = 1;
2205
+ function div(cls, box) {
2206
+ const el = document.createElement("div");
2207
+ el.className = cls;
2208
+ if (box)
2209
+ place(el, box);
2210
+ return el;
2211
+ }
2212
+ function place(el, r) {
2213
+ el.style.left = `${r.x}px`;
2214
+ el.style.top = `${r.y}px`;
2215
+ el.style.width = `${r.w}px`;
2216
+ el.style.height = `${r.h}px`;
2217
+ }
2218
+ function clearOverlay() {
2219
+ for (const layer of Array.from(document.querySelectorAll(".gp-ov")))
2220
+ layer.remove();
2221
+ }
2222
+ function paintOverlay(pages, strips, bleedPt) {
2223
+ clearOverlay();
2224
+ const layers = new Map;
2225
+ const painted = new Map;
2226
+ for (const p of pages) {
2227
+ const run = p.sheet.closest(".gp-run");
2228
+ if (!run)
2229
+ continue;
2230
+ let layer = layers.get(run);
2231
+ if (!layer) {
2232
+ layer = div("gp-ov");
2233
+ run.appendChild(layer);
2234
+ layers.set(run, layer);
2235
+ }
2236
+ const boxes = pageBoxes(p.geometry, p.margin, bleedPt, PX_PER_PT);
2237
+ const host = div("gp-ov-page", boxes.trim);
2238
+ host.style.left = p.sheet.style.left;
2239
+ host.style.top = p.sheet.style.top;
2240
+ host.dataset.page = String(p.index + 1);
2241
+ if (boxes.bleed > 0) {
2242
+ const band = div("gp-ov-bleed");
2243
+ band.style.inset = `${-boxes.bleed}px`;
2244
+ band.style.borderWidth = `${boxes.bleed}px`;
2245
+ host.appendChild(band);
2246
+ host.appendChild(div("gp-ov-trim"));
2247
+ }
2248
+ host.appendChild(div("gp-ov-margin", boxes.content));
2249
+ if (marginsDiffer(p.printMargin, p.margin)) {
2250
+ host.appendChild(div("gp-ov-print", pageBoxes(p.geometry, p.printMargin, 0, PX_PER_PT).content));
2251
+ }
2252
+ layer.appendChild(host);
2253
+ painted.set(p.index, { host, boxes, sheet: p.sheet });
2254
+ }
2255
+ const flags = [];
2256
+ let issues = 0;
2257
+ let intended = 0;
2258
+ for (const strip of strips) {
2259
+ const zoom = cssZoomOf(strip.el);
2260
+ const colW = (parseFloat(strip.el.style.getPropertyValue("--gp-content-w")) || 0) * zoom;
2261
+ const colH = (parseFloat(strip.el.style.getPropertyValue("--gp-content-h")) || 0) * zoom;
2262
+ const visit = (el) => {
2263
+ if (SKIP.has(el.tagName) || el.classList.contains("gp-wrap-spacer"))
2264
+ return;
2265
+ const kinds = [];
2266
+ const found = [];
2267
+ for (const r of Array.from(el.getClientRects())) {
2268
+ if (r.width <= 0 && r.height <= 0)
2269
+ continue;
2270
+ const ax = r.left + Math.min(r.width, colW || r.width) / 2;
2271
+ const ay = r.top + Math.min(r.height, colH || r.height) / 2;
2272
+ const target = painted.get(strip.offset + indexInStrip(ax, ay, strip));
2273
+ if (!target)
2274
+ continue;
2275
+ target.rect ??= target.sheet.getBoundingClientRect();
2276
+ const local = {
2277
+ x: (r.left - target.rect.left) / zoom,
2278
+ y: (r.top - target.rect.top) / zoom,
2279
+ w: r.width / zoom,
2280
+ h: r.height / zoom
2281
+ };
2282
+ const kind = classifyRect(local, target.boxes, TOL_PX);
2283
+ kinds.push(kind);
2284
+ if (kind !== "inside")
2285
+ found.push({ host: target.host, kind, box: local });
2286
+ }
2287
+ const worst = worstKind(kinds);
2288
+ if (worst !== "inside") {
2289
+ const isIntended = el.closest(INTENT_SELECTOR) !== null;
2290
+ if (isIntended)
2291
+ intended++;
2292
+ else
2293
+ issues++;
2294
+ for (const f of found)
2295
+ flags.push(isIntended ? { ...f, kind: "intended" } : f);
2296
+ return;
2297
+ }
2298
+ for (const child of Array.from(el.children))
2299
+ visit(child);
2300
+ };
2301
+ for (const child of Array.from(strip.el.children))
2302
+ visit(child);
2303
+ }
2304
+ for (const f of flags) {
2305
+ const el = div(`gp-ov-flag`, f.box);
2306
+ el.dataset.kind = f.kind;
2307
+ f.host.appendChild(el);
2308
+ }
2309
+ return { on: true, issues, intended, bleedPt };
2310
+ }
2311
+
2070
2312
  // src/engine/viewer/decorate.ts
2071
2313
  var px = (v) => `${v * PX_PER_PT}px`;
2072
2314
  function elementForHref(href) {
@@ -2095,6 +2337,13 @@
2095
2337
  let blankPages = new Set;
2096
2338
  let paddedPages = new Set;
2097
2339
  const warnings = [];
2340
+ let overlayOn = false;
2341
+ let overlayPages = [];
2342
+ let overlaySummary = OVERLAY_OFF;
2343
+ const paintOverlayNow = () => {
2344
+ overlaySummary = paintOverlay(overlayPages, layout.strips, documentBleedPt(model));
2345
+ window.dispatchEvent(new CustomEvent("gp:overlay", { detail: overlaySummary }));
2346
+ };
2098
2347
  const api = {
2099
2348
  redraw: () => draw(),
2100
2349
  sheetFor: (p) => sheets.get(p),
@@ -2104,7 +2353,20 @@
2104
2353
  warnings,
2105
2354
  setDesigner(on) {
2106
2355
  document.body.dataset.designer = on ? "on" : "off";
2107
- }
2356
+ },
2357
+ setOverlay(on) {
2358
+ overlayOn = on;
2359
+ document.body.dataset.overlay = on ? "on" : "off";
2360
+ if (on)
2361
+ paintOverlayNow();
2362
+ else {
2363
+ clearOverlay();
2364
+ overlaySummary = OVERLAY_OFF;
2365
+ window.dispatchEvent(new CustomEvent("gp:overlay", { detail: overlaySummary }));
2366
+ }
2367
+ return overlaySummary;
2368
+ },
2369
+ overlay: () => overlaySummary
2108
2370
  };
2109
2371
  const canvasBg = captureCanvasBackground();
2110
2372
  document.body.classList.add("gp-stage");
@@ -2262,6 +2524,7 @@
2262
2524
  warnings.length = 0;
2263
2525
  blankPages = new Set(layout.blankPageIndices);
2264
2526
  paddedPages = new Set(layout.paddedPageIndices);
2527
+ overlayPages = [];
2265
2528
  buildMaps();
2266
2529
  fillXrefs();
2267
2530
  let prevPageH = 0;
@@ -2300,6 +2563,14 @@
2300
2563
  drawMarginBoxes(sheet, ctx, layout.totalPages - paddedPages.size);
2301
2564
  drawGuides(sheet, ctx);
2302
2565
  drawCropMarks(sheet, ctx);
2566
+ overlayPages.push({
2567
+ index: bookIndex,
2568
+ sheet,
2569
+ strip,
2570
+ geometry: ctx.geometry,
2571
+ printMargin: ctx.geometry.margin,
2572
+ margin: ctx.padded || blankPages.has(bookIndex) ? ctx.geometry.margin : strip.flushEdges?.length ? flushMargins(g.margin, strip.flushEdges) : g.margin
2573
+ });
2303
2574
  }
2304
2575
  const rows = Math.max(1, Math.ceil((strip.pages + shift) / perRow));
2305
2576
  run.style.height = `${rowStride * (rows - 1) + PX_PER_PT * g.height}px`;
@@ -2310,6 +2581,8 @@
2310
2581
  if (opts.designer)
2311
2582
  checkOverflow(strip, warnings);
2312
2583
  }
2584
+ if (overlayOn)
2585
+ paintOverlayNow();
2313
2586
  }
2314
2587
  function drawMarginBoxes(sheet, ctx, totalPages) {
2315
2588
  const g = ctx.geometry;
@@ -19,7 +19,7 @@ import {
19
19
  stringValueAt,
20
20
  toFolioPage,
21
21
  wantsRecto
22
- } from "./index-vmcfahe2.js";
22
+ } from "./index-jg1r9t4w.js";
23
23
  import {
24
24
  launchChromium
25
25
  } from "./index-rzm1phg0.js";
@@ -151,19 +151,19 @@ var favicon_default = "./favicon-272ga6y0.ico";
151
151
  var manifest_schema_default = "./manifest.schema-gh0jjve9.json";
152
152
 
153
153
  // src/assets/preview/scripts/preview-interface.js
154
- var preview_interface_default = "./preview-interface-c44qk17f.js";
154
+ var preview_interface_default = "./preview-interface-dm6wbdq6.js";
155
155
 
156
156
  // src/assets/preview/scripts/preview-bridge.js
157
- var preview_bridge_default = "./preview-bridge-8jhd1wpb.js";
157
+ var preview_bridge_default = "./preview-bridge-ga409pgz.js";
158
158
 
159
159
  // src/assets/preview/scripts/preview-shell.js
160
- var preview_shell_default = "./preview-shell-xwn84kqr.js";
160
+ var preview_shell_default = "./preview-shell-c909krk2.js";
161
161
 
162
162
  // profiles/CGATS21_CRPC1.icc
163
163
  var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
164
164
 
165
165
  // src/assets/engine/gutterpress-viewer.js
166
- var gutterpress_viewer_default = "./gutterpress-viewer-ez7k4ha7.js";
166
+ var gutterpress_viewer_default = "./gutterpress-viewer-p50c4f08.js";
167
167
 
168
168
  // src/assets/engine/gutterpress-agent.js
169
169
  var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
@@ -9,7 +9,7 @@ import {
9
9
  getAssetsDir,
10
10
  lastPageMode,
11
11
  parseSize
12
- } from "./index-vmcfahe2.js";
12
+ } from "./index-jg1r9t4w.js";
13
13
  import {
14
14
  INSTALL_HINTS,
15
15
  execCapture,
@@ -5747,7 +5747,7 @@ import git from "isomorphic-git";
5747
5747
  // package.json
5748
5748
  var package_default = {
5749
5749
  name: "gutterpress",
5750
- version: "0.11.17",
5750
+ version: "0.11.18-alpha.1",
5751
5751
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
5752
5752
  author: "itlackey",
5753
5753
  license: "MPL-2.0",
@@ -10303,7 +10303,7 @@ class PdfOutput {
10303
10303
  const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
10304
10304
  await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
10305
10305
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
10306
- const { buildNativePdf } = await import("./engine-5d1rpxxq.js");
10306
+ const { buildNativePdf } = await import("./engine-s2caze6b.js");
10307
10307
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
10308
10308
  title: config.title,
10309
10309
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
package/dist/index.js CHANGED
@@ -153,14 +153,14 @@ import {
153
153
  testRemoteAccess,
154
154
  updateExtensions,
155
155
  validateProjectExtensions
156
- } from "./index-3k3fyrec.js";
156
+ } from "./index-pdanxwn1.js";
157
157
  import"./index-ht1bcqdd.js";
158
158
  import {
159
159
  BUILD_DIAGNOSTIC_CODES
160
- } from "./index-09h3n36d.js";
160
+ } from "./index-3pnmf25p.js";
161
161
  import {
162
162
  BuildError
163
- } from "./index-vmcfahe2.js";
163
+ } from "./index-jg1r9t4w.js";
164
164
  import {
165
165
  DEFAULT_PRINT_OPTS,
166
166
  assertMilestone,
@@ -7,17 +7,17 @@ import {
7
7
  TARGET_IDS,
8
8
  scaffoldExtension,
9
9
  scaffoldProject
10
- } from "./cli-a4qtctrw.js";
10
+ } from "./cli-1msxnhzy.js";
11
11
  import {
12
12
  resolveGhostscript
13
- } from "./cli-zfgvssqz.js";
13
+ } from "./cli-gv97c2a6.js";
14
14
  import {
15
15
  UsageError,
16
16
  rejectExtraPositionals,
17
17
  rejectUnknownFlags
18
- } from "./cli-8nw6d915.js";
18
+ } from "./cli-bzz33hjz.js";
19
19
  import"./cli-ht1bcqdd.js";
20
- import"./cli-ycbg7mxk.js";
20
+ import"./cli-th1ve2cx.js";
21
21
  import {
22
22
  EXIT_CODES
23
23
  } from "./cli-46ycxe6r.js";
@@ -2,17 +2,17 @@ import {
2
2
  executeValidation,
3
3
  publishTargetFor,
4
4
  reportMissingTools
5
- } from "./cli-a4qtctrw.js";
5
+ } from "./cli-1msxnhzy.js";
6
6
  import {
7
7
  log
8
- } from "./cli-zfgvssqz.js";
8
+ } from "./cli-gv97c2a6.js";
9
9
  import {
10
10
  UsageError,
11
11
  rejectExtraPositionals,
12
12
  rejectUnknownFlags
13
- } from "./cli-8nw6d915.js";
13
+ } from "./cli-bzz33hjz.js";
14
14
  import"./cli-ht1bcqdd.js";
15
- import"./cli-ycbg7mxk.js";
15
+ import"./cli-th1ve2cx.js";
16
16
  import {
17
17
  BuildError,
18
18
  EXIT_CODES
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // Commands map 1:1 to previewAPI methods: getTotalPages, getCurrentPage,
16
16
  // goToPage, firstPage, prevPage, nextPage, lastPage, setViewMode, setZoom,
17
- // toggleDebugMode. Plus a synthetic 'print' command that calls window.print().
17
+ // toggleDebugMode, setMarginOverlay. Plus a synthetic 'print' command that calls window.print().
18
18
  //
19
19
  // Additional messages:
20
20
  // parent -> iframe: { type: 'gutterpress:inject-styles', id: <attr-name>, css: <string> }
@@ -82,6 +82,10 @@
82
82
  window.addEventListener('contextMenuRequested', function (e) {
83
83
  post({ type: 'gutterpress:event', name: 'contextMenuRequested', detail: e.detail });
84
84
  });
85
+ // Margin & bleed overlay result (protocol v9): {on, issues, intended, bleedPt}.
86
+ window.addEventListener('overlayChanged', function (e) {
87
+ post({ type: 'gutterpress:event', name: 'overlayChanged', detail: e.detail });
88
+ });
85
89
  // In-flow block editing (protocol v8). `Requested` is the double-click entry
86
90
  // point — the SPA answers it with a beginBlockEdit command. `Finished`
87
91
  // carries the edited text back for an end the AUTHOR initiated inside the
@@ -1070,6 +1070,12 @@
1070
1070
  refreshPages();
1071
1071
  currentPage = detectVisiblePage();
1072
1072
  recordVisibleSource();
1073
+ // A hot-reload swap makes this frame the active one AFTER its overlay was
1074
+ // switched on (while hidden, where nothing is relayed): say so now.
1075
+ var overlay = api.getMarginOverlay();
1076
+ if (overlay && overlay.on) {
1077
+ window.dispatchEvent(new CustomEvent('overlayChanged', { detail: overlay }));
1078
+ }
1073
1079
  return api.notifyPageChange();
1074
1080
  },
1075
1081
 
@@ -1091,7 +1097,28 @@
1091
1097
  // floating edit panel this replaces. A v8 lib with a pre-v8 SPA loses the
1092
1098
  // "Edit this block" action and nothing else; a v8 SPA feature-detects on
1093
1099
  // the version before offering it.
1094
- getProtocolVersion: function () { return 8; },
1100
+ // v9: ADDED setMarginOverlay()/toggleMarginOverlay()/getMarginOverlay() and
1101
+ // the overlayChanged event (margin & bleed overlay, engine/viewer/
1102
+ // overlay.ts). A v9 lib with a pre-v9 SPA simply never turns it on; a v9
1103
+ // SPA feature-detects on the version before offering the toggle.
1104
+ getProtocolVersion: function () { return 9; },
1105
+
1106
+ // Margin & bleed overlay. Viewer chrome only — it adds no box to the book
1107
+ // and no attribute to its elements, so pagination is identical on or off.
1108
+ // Returns the summary {on, issues, intended, bleedPt}, or null when the
1109
+ // viewer predates it.
1110
+ setMarginOverlay: function (on) {
1111
+ var d = window.Gutterpress && window.Gutterpress.decoration;
1112
+ return d && typeof d.setOverlay === 'function' ? d.setOverlay(!!on) : null;
1113
+ },
1114
+ toggleMarginOverlay: function () {
1115
+ var d = window.Gutterpress && window.Gutterpress.decoration;
1116
+ return d && typeof d.setOverlay === 'function' ? d.setOverlay(document.body.dataset.overlay !== 'on') : null;
1117
+ },
1118
+ getMarginOverlay: function () {
1119
+ var d = window.Gutterpress && window.Gutterpress.decoration;
1120
+ return d && typeof d.overlay === 'function' ? d.overlay() : null;
1121
+ },
1095
1122
 
1096
1123
  // Resolve the annotated element/selection at a viewport point (protocol
1097
1124
  // v4). Pure read; see buildContextTarget() above for the full contract.
@@ -1596,4 +1623,47 @@
1596
1623
  // The Gutterpress engine viewer dispatches this when its pagination
1597
1624
  // completes (engine/viewer/index.ts's mount()).
1598
1625
  window.addEventListener('gp:layout', onRenderingComplete);
1626
+
1627
+ // Margin & bleed overlay: relay the viewer's result as 'overlayChanged' (the
1628
+ // bridge posts it to a host toolbar) and, where no host toolbar exists, give
1629
+ // the standalone CLI preview its own switch: Alt+M, plus a small status pill.
1630
+ // "Standalone" = the shell is top level (the CLI); under the desktop app the
1631
+ // shell's parent is the app, which owns the toggle and the count.
1632
+ var standalone = false;
1633
+ try { standalone = window.parent === window || window.parent.parent === window.parent; } catch (_e) {}
1634
+
1635
+ function updateOverlayBadge(summary) {
1636
+ var badge = document.getElementById('gp-ov-badge');
1637
+ if (!standalone || !summary || !summary.on) {
1638
+ if (badge) badge.remove();
1639
+ return;
1640
+ }
1641
+ if (!badge) {
1642
+ badge = document.createElement('div');
1643
+ badge.id = 'gp-ov-badge';
1644
+ badge.setAttribute('role', 'status');
1645
+ badge.style.cssText = 'position:fixed;top:8px;right:8px;z-index:2147483000;pointer-events:none;' +
1646
+ 'background:rgba(20,20,24,.88);color:#fff;font:600 11px/1.4 ui-sans-serif,system-ui,sans-serif;' +
1647
+ 'padding:4px 10px;border-radius:999px;box-shadow:0 1px 6px rgba(0,0,0,.4)';
1648
+ document.documentElement.appendChild(badge);
1649
+ }
1650
+ var parts = ['Margins & bleed'];
1651
+ parts.push(summary.issues ? summary.issues + ' overflowing' : 'nothing overflows');
1652
+ if (summary.intended) parts.push(summary.intended + ' placed on purpose');
1653
+ if (!summary.bleedPt) parts.push('no @page bleed set');
1654
+ badge.textContent = parts.join(' \u00b7 ') + ' (Alt+M hides)';
1655
+ }
1656
+
1657
+ window.addEventListener('gp:overlay', function (e) {
1658
+ updateOverlayBadge(e.detail);
1659
+ window.dispatchEvent(new CustomEvent('overlayChanged', { detail: e.detail }));
1660
+ });
1661
+
1662
+ if (standalone) {
1663
+ document.addEventListener('keydown', function (e) {
1664
+ if (e.code !== 'KeyM' || !e.altKey || e.ctrlKey || e.metaKey || e.defaultPrevented) return;
1665
+ e.preventDefault();
1666
+ api.toggleMarginOverlay();
1667
+ });
1668
+ }
1599
1669
  })();
@@ -7,10 +7,10 @@ import {
7
7
  runBuild,
8
8
  splitOutPath,
9
9
  startPreviewServer
10
- } from "./cli-a4qtctrw.js";
10
+ } from "./cli-1msxnhzy.js";
11
11
  import {
12
12
  log
13
- } from "./cli-zfgvssqz.js";
13
+ } from "./cli-gv97c2a6.js";
14
14
  import {
15
15
  UsageError,
16
16
  parseFormat,
@@ -18,9 +18,9 @@ import {
18
18
  rejectExtraPositionals,
19
19
  rejectUnknownFlags,
20
20
  resolvePort
21
- } from "./cli-8nw6d915.js";
21
+ } from "./cli-bzz33hjz.js";
22
22
  import"./cli-ht1bcqdd.js";
23
- import"./cli-ycbg7mxk.js";
23
+ import"./cli-th1ve2cx.js";
24
24
  import {
25
25
  BuildError
26
26
  } from "./cli-46ycxe6r.js";
@@ -106,6 +106,9 @@
106
106
  else if (sourceBody.classList.contains('view-spread')) api.setViewMode('spread', true);
107
107
  else if (sourceBody.classList.contains('view-two-column')) api.setViewMode('two-column', true);
108
108
  if (sourceBody.classList.contains('debug')) api.toggleDebugMode();
109
+ // The margin & bleed overlay is a review aid the author switched on: a
110
+ // hot reload must not drop it.
111
+ if (sourceBody.dataset.overlay === 'on' && api.setMarginOverlay) api.setMarginOverlay(true);
109
112
  }
110
113
  var zoom = source.documentElement.style.getPropertyValue('--gutterpress-zoom');
111
114
  // Carry the fit flag too (setZoom's third argument clips sideways overflow).
@@ -11,18 +11,18 @@ import {
11
11
  publishProviderFor,
12
12
  resolvePublishFormat,
13
13
  runPublish
14
- } from "./cli-a4qtctrw.js";
14
+ } from "./cli-1msxnhzy.js";
15
15
  import {
16
16
  FileTokenStore,
17
17
  log
18
- } from "./cli-zfgvssqz.js";
18
+ } from "./cli-gv97c2a6.js";
19
19
  import {
20
20
  UsageError,
21
21
  rejectExtraPositionals,
22
22
  rejectUnknownFlags
23
- } from "./cli-8nw6d915.js";
23
+ } from "./cli-bzz33hjz.js";
24
24
  import"./cli-ht1bcqdd.js";
25
- import"./cli-ycbg7mxk.js";
25
+ import"./cli-th1ve2cx.js";
26
26
  import {
27
27
  EXIT_CODES
28
28
  } from "./cli-46ycxe6r.js";
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  executeAndReport
3
- } from "./cli-a4qtctrw.js";
3
+ } from "./cli-1msxnhzy.js";
4
4
  import {
5
5
  log
6
- } from "./cli-zfgvssqz.js";
6
+ } from "./cli-gv97c2a6.js";
7
7
  import {
8
8
  UsageError,
9
9
  rejectExtraPositionals,
10
10
  rejectUnknownFlags
11
- } from "./cli-8nw6d915.js";
11
+ } from "./cli-bzz33hjz.js";
12
12
  import"./cli-ht1bcqdd.js";
13
- import"./cli-ycbg7mxk.js";
13
+ import"./cli-th1ve2cx.js";
14
14
  import {
15
15
  BuildError,
16
16
  EXIT_CODES
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gutterpress",
3
- "version": "0.11.17",
3
+ "version": "0.11.18-alpha.1",
4
4
  "description": "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
5
5
  "author": "itlackey",
6
6
  "license": "MPL-2.0",