gutterpress 0.11.19 → 0.11.20-alpha.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.
- package/dist/api/index.js +2 -2
- package/dist/{build-czbaj4qf.js → build-qmjg9r2d.js} +4 -4
- package/dist/checks/pdf/index.d.ts +1 -0
- package/dist/checks/pdf/safe-margins.d.ts +3 -0
- package/dist/{cli-cgbzdrwz.js → cli-7z29z4wz.js} +1 -1
- package/dist/{cli-dzw28t3s.js → cli-gh0ym80r.js} +2 -1
- package/dist/{cli-xx94a1k6.js → cli-j802s31j.js} +5 -5
- package/dist/{cli-aw614ztv.js → cli-zacevwcy.js} +299 -184
- package/dist/cli.js +12 -12
- package/dist/{doctor-6e9perj7.js → doctor-fe7tcs4v.js} +2 -2
- package/dist/{engine-fe0n7v9p.js → engine-9xb1ky8d.js} +1 -1
- package/dist/{engine-zehw6tkv.js → engine-yax79k9m.js} +2 -2
- package/dist/{ext-kavfk1zn.js → ext-ahwxt6gv.js} +4 -4
- package/dist/{gutterpress-viewer-k4mpqjh0.js → gutterpress-viewer-retj6ym2.js} +515 -281
- package/dist/{index-jt552wtf.js → index-3nr5rzzp.js} +5 -5
- package/dist/{index-b866g2ph.js → index-6xwtb7cw.js} +1 -1
- package/dist/{index-g7vszjqf.js → index-razpty47.js} +298 -182
- package/dist/index.js +3 -3
- package/dist/lib/ghostscript.d.ts +7 -0
- package/dist/lib/presets.d.ts +3 -1
- package/dist/{manifest.schema-5pzhscqh.json → manifest.schema-74s1ykyv.json} +20 -1
- package/dist/{new-ckpas1ya.js → new-ftd4fec4.js} +4 -4
- package/dist/{preflight-yh57q9nn.js → preflight-8sqarcsr.js} +4 -4
- package/dist/preview/file-watcher.d.ts +16 -2
- package/dist/{preview-bridge-evecsh4w.js → preview-bridge-8wjcjec3.js} +3 -2
- package/dist/{preview-interface-2n1d9pbf.js → preview-interface-nnmrxyqm.js} +37 -41
- package/dist/{preview-a4x2ezjp.js → preview-q76xn95h.js} +4 -4
- package/dist/{preview-shell-hyp7g158.js → preview-shell-wk9k3gcd.js} +18 -6
- package/dist/{publish-sfn5hmnx.js → publish-7gdy6gbf.js} +4 -4
- package/dist/schema/manifest.types.d.ts +38 -3
- package/dist/{validate-281rsdsv.js → validate-e3ryegce.js} +4 -4
- package/package.json +1 -1
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
--gp-sheet-bg: #fff;
|
|
63
63
|
--gp-stage-bg: #4a4a52;
|
|
64
64
|
--gp-guide: #e5484d;
|
|
65
|
-
--gp-safe: #30a46c;
|
|
66
65
|
background: var(--gp-stage-bg);
|
|
67
66
|
margin: 0;
|
|
68
67
|
padding: 32px;
|
|
@@ -275,110 +274,8 @@
|
|
|
275
274
|
.gp-marginbox[data-align="center"] > .gp-marginbox-content { justify-content: center; }
|
|
276
275
|
.gp-marginbox[data-align="end"] > .gp-marginbox-content { justify-content: flex-end; }
|
|
277
276
|
|
|
278
|
-
/* margin & bleed overlay (overlay.ts) -------------------------------- */
|
|
279
|
-
/* THE LOOK LIVES HERE, in these tokens, and nowhere else: colours, line
|
|
280
|
-
width, line style, tint strength. The desktop app's settings change the
|
|
281
|
-
colour (an inline \`--gp-ov-color\` on <body>) and pick a strength preset
|
|
282
|
-
(\`data-overlay-strength\`); nothing in a book's CSS is involved or needed. */
|
|
283
|
-
.gp-stage {
|
|
284
|
-
--gp-ov-color: #2f80ed; /* margin box line + the tint over the margins */
|
|
285
|
-
--gp-ov-width: 2px; /* line width as seen on screen, at any zoom */
|
|
286
|
-
--gp-ov-style: dashed; /* margin box line style */
|
|
287
|
-
--gp-ov-tint: 0.1; /* opacity of the tint over the margin area */
|
|
288
|
-
--gp-ov-bleed-color: #e5484d; /* bleed band + trim line */
|
|
289
|
-
--gp-ov-bleed-alpha: 0.45; /* opacity of the bleed band */
|
|
290
|
-
--gp-ov-trim-color: #8a0b18; /* the trim line: darker than the band so it reads as an edge */
|
|
291
|
-
--gp-ov-flag-width: 2px; /* overflow flag outline */
|
|
292
|
-
--gp-ov-warn: #f59e0b; /* reaches into the margin */
|
|
293
|
-
--gp-ov-error: #e5484d; /* crosses the trim / leaves the page */
|
|
294
|
-
--gp-ov-intent: #8b5cf6; /* placed on purpose */
|
|
295
|
-
}
|
|
296
|
-
.gp-stage[data-overlay-strength="subtle"] {
|
|
297
|
-
--gp-ov-width: 1px;
|
|
298
|
-
--gp-ov-tint: 0.05;
|
|
299
|
-
--gp-ov-bleed-alpha: 0.3;
|
|
300
|
-
}
|
|
301
|
-
.gp-stage[data-overlay-strength="strong"] {
|
|
302
|
-
--gp-ov-width: 3px;
|
|
303
|
-
--gp-ov-tint: 0.2;
|
|
304
|
-
--gp-ov-bleed-alpha: 0.65;
|
|
305
|
-
--gp-ov-flag-width: 3px;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/* One sibling layer per run, ABOVE the strip so the lines stay visible over
|
|
309
|
-
author backgrounds and art. Absolutely positioned and pointer-transparent:
|
|
310
|
-
it takes no flow space and no hits, so it cannot move a page break. Exists
|
|
311
|
-
only while the overlay is on. */
|
|
312
|
-
.gp-ov {
|
|
313
|
-
position: absolute;
|
|
314
|
-
inset: 0;
|
|
315
|
-
z-index: 5;
|
|
316
|
-
pointer-events: none;
|
|
317
|
-
/* The stage is a paint transform, so a 2px line would shrink with the zoom
|
|
318
|
-
and vanish at fit-to-width. Lines are sized in layout px divided by the
|
|
319
|
-
zoom, which makes them the same width on screen at every zoom. */
|
|
320
|
-
--gp-ov-w: calc(var(--gp-ov-width) / var(--gp-zoom, 1));
|
|
321
|
-
--gp-ov-flag-w: calc(var(--gp-ov-flag-width) / var(--gp-zoom, 1));
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
.gp-ov-page {
|
|
325
|
-
position: absolute;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/* the margins as a region: the trim minus the content box (clip-path, set in
|
|
329
|
-
overlay.ts), so a margin reads as an area, not a hairline */
|
|
330
|
-
.gp-ov-tint {
|
|
331
|
-
position: absolute;
|
|
332
|
-
inset: 0;
|
|
333
|
-
background: color-mix(in srgb, var(--gp-ov-color) calc(var(--gp-ov-tint) * 100%), transparent);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/* margin box: the content area's outline */
|
|
337
|
-
.gp-ov-margin {
|
|
338
|
-
position: absolute;
|
|
339
|
-
box-sizing: border-box;
|
|
340
|
-
border: var(--gp-ov-w) var(--gp-ov-style) var(--gp-ov-color);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/* bleed: a translucent band OUTSIDE the trim (its width is the border) */
|
|
344
|
-
.gp-ov-bleed {
|
|
345
|
-
position: absolute;
|
|
346
|
-
box-sizing: border-box;
|
|
347
|
-
border-style: solid;
|
|
348
|
-
border-color: color-mix(in srgb, var(--gp-ov-bleed-color) calc(var(--gp-ov-bleed-alpha) * 100%), transparent);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/* trim: where the sheet will be cut, drawn only when there is bleed — solid,
|
|
352
|
-
just inside the edge so it never paints over the band (overlay.ts sizes and
|
|
353
|
-
places it: the whole sheet, or the sheet less an in-sheet bleed) */
|
|
354
|
-
.gp-ov-trim {
|
|
355
|
-
position: absolute;
|
|
356
|
-
outline: var(--gp-ov-w) solid var(--gp-ov-trim-color);
|
|
357
|
-
outline-offset: calc(-1 * var(--gp-ov-w));
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/* overflow flags — outline + faint tint, never a box change */
|
|
361
|
-
.gp-ov-flag {
|
|
362
|
-
position: absolute;
|
|
363
|
-
box-sizing: border-box;
|
|
364
|
-
}
|
|
365
|
-
.gp-ov-flag[data-kind="margin"] {
|
|
366
|
-
outline: var(--gp-ov-flag-w) solid var(--gp-ov-warn);
|
|
367
|
-
background: color-mix(in srgb, var(--gp-ov-warn) 16%, transparent);
|
|
368
|
-
}
|
|
369
|
-
.gp-ov-flag[data-kind="bleed"],
|
|
370
|
-
.gp-ov-flag[data-kind="off-page"] {
|
|
371
|
-
outline: var(--gp-ov-flag-w) solid var(--gp-ov-error);
|
|
372
|
-
background: color-mix(in srgb, var(--gp-ov-error) 18%, transparent);
|
|
373
|
-
}
|
|
374
|
-
/* placed on purpose (.gp-bleed, .gp-pin, …): present, not a problem */
|
|
375
|
-
.gp-ov-flag[data-kind="intended"] {
|
|
376
|
-
outline: var(--gp-ov-flag-w) dotted var(--gp-ov-intent);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
277
|
/* designer mode ------------------------------------------------------- */
|
|
380
278
|
.gp-guide-trim,
|
|
381
|
-
.gp-guide-safe,
|
|
382
279
|
.gp-crop-mark {
|
|
383
280
|
position: absolute;
|
|
384
281
|
pointer-events: none;
|
|
@@ -386,13 +283,11 @@
|
|
|
386
283
|
}
|
|
387
284
|
|
|
388
285
|
.gp-stage[data-designer="on"] .gp-guide-trim,
|
|
389
|
-
.gp-stage[data-designer="on"] .gp-guide-safe,
|
|
390
286
|
.gp-stage[data-designer="on"] .gp-crop-mark {
|
|
391
287
|
display: block;
|
|
392
288
|
}
|
|
393
289
|
|
|
394
290
|
.gp-guide-trim { outline: 1px dashed var(--gp-guide); }
|
|
395
|
-
.gp-guide-safe { outline: 1px dashed var(--gp-safe); }
|
|
396
291
|
.gp-crop-mark { background: var(--gp-guide); }
|
|
397
292
|
|
|
398
293
|
.gp-warning {
|
|
@@ -419,10 +314,8 @@
|
|
|
419
314
|
transform: none;
|
|
420
315
|
}
|
|
421
316
|
.gp-layer,
|
|
422
|
-
.gp-ov,
|
|
423
317
|
.gp-warning,
|
|
424
318
|
.gp-guide-trim,
|
|
425
|
-
.gp-guide-safe,
|
|
426
319
|
.gp-crop-mark {
|
|
427
320
|
display: none !important;
|
|
428
321
|
}
|
|
@@ -2202,96 +2095,325 @@
|
|
|
2202
2095
|
return /right/.test(name) ? "end" : "start";
|
|
2203
2096
|
}
|
|
2204
2097
|
|
|
2205
|
-
// src/engine/compiler/tier2.ts
|
|
2206
|
-
var DEFAULT_SLUG_PT = 18;
|
|
2207
|
-
function pageGeometry(model, opts) {
|
|
2208
|
-
const base = resolvePage(model);
|
|
2209
|
-
const trim = { width: base.geometry.width, height: base.geometry.height };
|
|
2210
|
-
const bleed = opts.bleedPt ?? base.geometry.bleed;
|
|
2211
|
-
const wantsMarks = base.geometry.marks.length > 0 || opts.marks === true;
|
|
2212
|
-
const slug = wantsMarks ? opts.slugPt ?? DEFAULT_SLUG_PT : 0;
|
|
2213
|
-
return {
|
|
2214
|
-
trim,
|
|
2215
|
-
bleed,
|
|
2216
|
-
slug,
|
|
2217
|
-
marks: base.geometry.marks.length ? base.geometry.marks : wantsMarks ? ["crop"] : [],
|
|
2218
|
-
media: {
|
|
2219
|
-
width: trim.width + 2 * (bleed + slug),
|
|
2220
|
-
height: trim.height + 2 * (bleed + slug)
|
|
2221
|
-
}
|
|
2222
|
-
};
|
|
2223
|
-
}
|
|
2224
|
-
|
|
2225
2098
|
// src/engine/viewer/overlay.ts
|
|
2226
|
-
function
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
const
|
|
2231
|
-
const
|
|
2232
|
-
const
|
|
2099
|
+
function pageBoxes(area, side, scale = 1) {
|
|
2100
|
+
const w = area.width * scale;
|
|
2101
|
+
const h = area.height * scale;
|
|
2102
|
+
const b = Math.max(0, area.bleed) * scale;
|
|
2103
|
+
const s = Math.max(0, area.safe) * scale;
|
|
2104
|
+
const a = Math.max(0, area.artSafe) * scale;
|
|
2105
|
+
const [left, right] = side === "verso" ? [a, s] : [s, a];
|
|
2106
|
+
const trim = { x: side === "verso" ? b : 0, y: b, w: Math.max(0, w - b), h: Math.max(0, h - 2 * b) };
|
|
2233
2107
|
return {
|
|
2234
|
-
|
|
2235
|
-
trim
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2108
|
+
sheet: { x: 0, y: 0, w, h },
|
|
2109
|
+
trim,
|
|
2110
|
+
safe: { x: trim.x + s, y: trim.y + s, w: Math.max(0, trim.w - 2 * s), h: Math.max(0, trim.h - 2 * s) },
|
|
2111
|
+
safeArt: {
|
|
2112
|
+
x: trim.x + left,
|
|
2113
|
+
y: trim.y + a,
|
|
2114
|
+
w: Math.max(0, trim.w - left - right),
|
|
2115
|
+
h: Math.max(0, trim.h - 2 * a)
|
|
2241
2116
|
},
|
|
2242
|
-
bleedBox: { x: -b, y: -b, w: w + 2 * b, h: h + 2 * b },
|
|
2243
|
-
bleed: b
|
|
2244
|
-
};
|
|
2245
|
-
}
|
|
2246
|
-
function insetPageBoxes(g, margin, bleed, side, scale = 1) {
|
|
2247
|
-
const sheet = pageBoxes(g, margin, 0, scale);
|
|
2248
|
-
const b = Math.max(0, bleed) * scale;
|
|
2249
|
-
return {
|
|
2250
|
-
host: sheet.host,
|
|
2251
|
-
trim: { x: side === "verso" ? b : 0, y: b, w: sheet.host.w - b, h: sheet.host.h - 2 * b },
|
|
2252
|
-
content: sheet.content,
|
|
2253
|
-
bleedBox: sheet.host,
|
|
2254
2117
|
bleed: b
|
|
2255
2118
|
};
|
|
2256
2119
|
}
|
|
2257
|
-
var SEVERITY = { inside: 0,
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2120
|
+
var SEVERITY = { inside: 0, unsafe: 1, bleed: 2, "off-page": 3 };
|
|
2121
|
+
function classifyRect(r, boxes, rule, tol = 0) {
|
|
2122
|
+
const { sheet, trim } = boxes;
|
|
2123
|
+
const safe = rule === "art" ? boxes.safeArt : boxes.safe;
|
|
2124
|
+
const sides = [
|
|
2125
|
+
[-r.x, -safe.x, -trim.x, -sheet.x],
|
|
2126
|
+
[r.x + r.w, safe.x + safe.w, trim.x + trim.w, sheet.x + sheet.w],
|
|
2127
|
+
[-r.y, -safe.y, -trim.y, -sheet.y],
|
|
2128
|
+
[r.y + r.h, safe.y + safe.h, trim.y + trim.h, sheet.y + sheet.h]
|
|
2129
|
+
];
|
|
2130
|
+
let worst = { kind: "inside", gap: 0, need: 0 };
|
|
2131
|
+
let beyond = 0;
|
|
2132
|
+
for (const [ink, limit, edge, sheetEdge] of sides) {
|
|
2133
|
+
const past = ink - limit;
|
|
2134
|
+
if (past <= tol || rule === "art" && ink >= sheetEdge - tol)
|
|
2135
|
+
continue;
|
|
2136
|
+
const kind = ink > sheetEdge + tol ? "off-page" : ink > edge + tol ? "bleed" : "unsafe";
|
|
2137
|
+
if (SEVERITY[kind] > SEVERITY[worst.kind] || kind === worst.kind && past > beyond) {
|
|
2138
|
+
worst = { kind, gap: edge - ink, need: edge - limit };
|
|
2139
|
+
beyond = past;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return worst;
|
|
2270
2143
|
}
|
|
2271
2144
|
var INTENT_SELECTOR = ".gp-bleed, .gp-pin, .gp-flush, .gp-behind, .gp-page-full-bleed";
|
|
2145
|
+
var OVERLAY_LAYERS = ["bleed", "safe", "art", "margins"];
|
|
2146
|
+
function layersFrom(state) {
|
|
2147
|
+
const named = state && typeof state === "object" ? state : null;
|
|
2148
|
+
const on = (layer) => named ? named[layer] === true : !!state;
|
|
2149
|
+
return { bleed: on("bleed"), safe: on("safe"), art: on("art"), margins: on("margins") };
|
|
2150
|
+
}
|
|
2272
2151
|
var OVERLAY_STRENGTHS = ["subtle", "normal", "strong"];
|
|
2273
2152
|
var HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
2274
2153
|
function sanitizeOverlayStyle(style) {
|
|
2275
2154
|
const s = style && typeof style === "object" ? style : {};
|
|
2155
|
+
const given = s.colors && typeof s.colors === "object" ? s.colors : {};
|
|
2156
|
+
const hex = (v) => typeof v === "string" && HEX_COLOR.test(v.trim()) ? v.trim() : undefined;
|
|
2276
2157
|
const out = {};
|
|
2277
|
-
|
|
2278
|
-
|
|
2158
|
+
for (const layer of OVERLAY_LAYERS) {
|
|
2159
|
+
const color = hex(given[layer]) ?? (layer === "safe" ? hex(s.color) : undefined);
|
|
2160
|
+
if (color)
|
|
2161
|
+
(out.colors ??= {})[layer] = color;
|
|
2162
|
+
}
|
|
2279
2163
|
if (OVERLAY_STRENGTHS.includes(s.strength))
|
|
2280
2164
|
out.strength = s.strength;
|
|
2281
2165
|
return out;
|
|
2282
2166
|
}
|
|
2283
|
-
var OVERLAY_OFF = {
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2167
|
+
var OVERLAY_OFF = {
|
|
2168
|
+
on: false,
|
|
2169
|
+
layers: { bleed: false, safe: false, art: false, margins: false },
|
|
2170
|
+
issues: 0,
|
|
2171
|
+
intended: 0,
|
|
2172
|
+
bleedPt: 0,
|
|
2173
|
+
safePt: 0,
|
|
2174
|
+
artSafePt: 0,
|
|
2175
|
+
counts: { text: 0, art: 0, bleed: 0, offPage: 0, intended: 0 }
|
|
2176
|
+
};
|
|
2177
|
+
function printAreaFromMeta() {
|
|
2178
|
+
const raw = document.querySelector('meta[name="gp-print-area"]')?.getAttribute("content");
|
|
2179
|
+
if (!raw)
|
|
2180
|
+
return null;
|
|
2181
|
+
try {
|
|
2182
|
+
const v = JSON.parse(raw);
|
|
2183
|
+
const n = (x) => typeof x === "number" && Number.isFinite(x) && x > 0 ? x : 0;
|
|
2184
|
+
if (!n(v.width) || !n(v.height))
|
|
2185
|
+
return null;
|
|
2186
|
+
const safe = n(v.safe);
|
|
2187
|
+
const spec = v.spec && typeof v.spec.label === "string" && typeof v.spec.url === "string" && /^https?:\/\//i.test(v.spec.url) ? v.spec : undefined;
|
|
2188
|
+
return {
|
|
2189
|
+
width: n(v.width),
|
|
2190
|
+
height: n(v.height),
|
|
2191
|
+
bleed: n(v.bleed),
|
|
2192
|
+
safe,
|
|
2193
|
+
artSafe: typeof v.artSafe === "number" ? n(v.artSafe) : safe,
|
|
2194
|
+
preset: typeof v.preset === "string" ? v.preset : undefined,
|
|
2195
|
+
spec
|
|
2196
|
+
};
|
|
2197
|
+
} catch {
|
|
2198
|
+
return null;
|
|
2199
|
+
}
|
|
2288
2200
|
}
|
|
2289
|
-
function
|
|
2290
|
-
const
|
|
2291
|
-
return
|
|
2201
|
+
function sheetArea(sheet) {
|
|
2202
|
+
const px = (name) => parseFloat(sheet.style.getPropertyValue(name)) || 0;
|
|
2203
|
+
return { width: px("--gp-page-w") / PX_PER_PT, height: px("--gp-page-h") / PX_PER_PT, bleed: 0, safe: 0, artSafe: 0 };
|
|
2204
|
+
}
|
|
2205
|
+
var OVERLAY_CSS = `
|
|
2206
|
+
.root {
|
|
2207
|
+
--gp-ov-color: #2f80ed; /* safe layer: the text line + the tint outside it */
|
|
2208
|
+
--gp-ov-width: 2px; /* line width as seen on screen, at any zoom */
|
|
2209
|
+
--gp-ov-style: dashed; /* text safe line style */
|
|
2210
|
+
--gp-ov-art-style: dotted; /* art safe line style */
|
|
2211
|
+
--gp-ov-tint: 0.1; /* opacity of the tint between the text line and the trim */
|
|
2212
|
+
--gp-ov-bleed-color: #e5484d; /* bleed layer: the band, and (darker) the trim line */
|
|
2213
|
+
--gp-ov-bleed-alpha: 0.45; /* opacity of the bleed band */
|
|
2214
|
+
--gp-ov-trim-color: color-mix(in srgb, var(--gp-ov-bleed-color) 60%, #000); /* darker than the band so it reads as an edge */
|
|
2215
|
+
--gp-ov-art-color: #00b4d8; /* art layer: the art line (dotted, a second cue) */
|
|
2216
|
+
--gp-ov-margins-color: #1a9c6b; /* margins layer: the page's own content box */
|
|
2217
|
+
--gp-ov-flag-width: 2px; /* overflow flag outline */
|
|
2218
|
+
--gp-ov-warn: #f59e0b; /* leaves the safe area */
|
|
2219
|
+
--gp-ov-error: #e5484d; /* crosses the trim / leaves the sheet */
|
|
2220
|
+
--gp-ov-intent: #8b5cf6; /* placed on purpose */
|
|
2221
|
+
/* The overlay is scaled with the stage, so a 2px line would shrink with the
|
|
2222
|
+
zoom; dividing by it keeps lines the same width on screen at every zoom. */
|
|
2223
|
+
--gp-ov-w: calc(var(--gp-ov-width) / var(--gp-ov-z, 1));
|
|
2224
|
+
--gp-ov-flag-w: calc(var(--gp-ov-flag-width) / var(--gp-ov-z, 1));
|
|
2225
|
+
--gp-ov-margins-w: calc(1px / var(--gp-ov-z, 1)); /* thin, whatever the strength */
|
|
2226
|
+
position: absolute;
|
|
2227
|
+
inset: 0;
|
|
2228
|
+
pointer-events: none;
|
|
2229
|
+
}
|
|
2230
|
+
/* the stage's zoomed copy, holding the pages' boxes; the legend sits beside it, not in it */
|
|
2231
|
+
.gp-ov-canvas {
|
|
2232
|
+
position: absolute;
|
|
2233
|
+
left: 0;
|
|
2234
|
+
top: 0;
|
|
2235
|
+
transform-origin: 0 0;
|
|
2236
|
+
}
|
|
2237
|
+
.root[data-strength="subtle"] {
|
|
2238
|
+
--gp-ov-width: 1px;
|
|
2239
|
+
--gp-ov-tint: 0.05;
|
|
2240
|
+
--gp-ov-bleed-alpha: 0.3;
|
|
2241
|
+
}
|
|
2242
|
+
.root[data-strength="strong"] {
|
|
2243
|
+
--gp-ov-width: 3px;
|
|
2244
|
+
--gp-ov-tint: 0.2;
|
|
2245
|
+
--gp-ov-bleed-alpha: 0.65;
|
|
2246
|
+
--gp-ov-flag-width: 3px;
|
|
2247
|
+
}
|
|
2248
|
+
.gp-ov-page, .gp-ov-tint, .gp-ov-safe, .gp-ov-art, .gp-ov-bleed, .gp-ov-trim, .gp-ov-margins, .gp-ov-flag {
|
|
2249
|
+
position: absolute;
|
|
2250
|
+
box-sizing: border-box;
|
|
2251
|
+
}
|
|
2252
|
+
/* the band between the text line and the trim, as a REGION (clip-path, set in
|
|
2253
|
+
overlay.ts), so it reads as an area, not a hairline */
|
|
2254
|
+
.gp-ov-tint {
|
|
2255
|
+
background: color-mix(in srgb, var(--gp-ov-color) calc(var(--gp-ov-tint) * 100%), transparent);
|
|
2256
|
+
}
|
|
2257
|
+
.gp-ov-safe {
|
|
2258
|
+
border: var(--gp-ov-w) var(--gp-ov-style) var(--gp-ov-color);
|
|
2259
|
+
}
|
|
2260
|
+
.gp-ov-art {
|
|
2261
|
+
border: var(--gp-ov-w) var(--gp-ov-art-style) var(--gp-ov-art-color);
|
|
2262
|
+
}
|
|
2263
|
+
/* bleed: a translucent band between the trim and the sheet edge (its width is the border) */
|
|
2264
|
+
.gp-ov-bleed {
|
|
2265
|
+
border-style: solid;
|
|
2266
|
+
border-color: color-mix(in srgb, var(--gp-ov-bleed-color) calc(var(--gp-ov-bleed-alpha) * 100%), transparent);
|
|
2267
|
+
}
|
|
2268
|
+
/* trim: where the sheet will be cut, drawn only when there is bleed */
|
|
2269
|
+
.gp-ov-trim {
|
|
2270
|
+
outline: var(--gp-ov-w) solid var(--gp-ov-trim-color);
|
|
2271
|
+
outline-offset: calc(-1 * var(--gp-ov-w));
|
|
2272
|
+
}
|
|
2273
|
+
/* margins: the page's own content box, a thin solid line */
|
|
2274
|
+
.gp-ov-margins {
|
|
2275
|
+
border: var(--gp-ov-margins-w) solid var(--gp-ov-margins-color);
|
|
2276
|
+
}
|
|
2277
|
+
/* overflow flags: outline + faint tint, never a box change */
|
|
2278
|
+
.gp-ov-flag[data-kind="unsafe"] {
|
|
2279
|
+
outline: var(--gp-ov-flag-w) solid var(--gp-ov-warn);
|
|
2280
|
+
background: color-mix(in srgb, var(--gp-ov-warn) 16%, transparent);
|
|
2281
|
+
}
|
|
2282
|
+
.gp-ov-flag[data-kind="bleed"],
|
|
2283
|
+
.gp-ov-flag[data-kind="off-page"] {
|
|
2284
|
+
outline: var(--gp-ov-flag-w) solid var(--gp-ov-error);
|
|
2285
|
+
background: color-mix(in srgb, var(--gp-ov-error) 18%, transparent);
|
|
2286
|
+
}
|
|
2287
|
+
.gp-ov-flag[data-kind="intended"] {
|
|
2288
|
+
outline: var(--gp-ov-flag-w) dotted var(--gp-ov-intent);
|
|
2289
|
+
}
|
|
2290
|
+
/* the legend: small, fixed in a corner of the viewport, and the one part that takes the pointer (its link) */
|
|
2291
|
+
.gp-ov-legend {
|
|
2292
|
+
position: fixed;
|
|
2293
|
+
right: 12px;
|
|
2294
|
+
bottom: 12px;
|
|
2295
|
+
box-sizing: border-box;
|
|
2296
|
+
max-width: min(420px, calc(100vw - 24px));
|
|
2297
|
+
padding: 8px 10px;
|
|
2298
|
+
border-radius: 8px;
|
|
2299
|
+
background: rgba(20, 20, 24, 0.92);
|
|
2300
|
+
color: #fff;
|
|
2301
|
+
font: 11px/1.45 ui-sans-serif, system-ui, sans-serif;
|
|
2302
|
+
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.4);
|
|
2303
|
+
pointer-events: auto;
|
|
2304
|
+
}
|
|
2305
|
+
.gp-ov-legend > div + div { margin-top: 3px; }
|
|
2306
|
+
.gp-ov-legend a { color: #9cc2ff; }
|
|
2307
|
+
.gp-ov-row { display: flex; align-items: flex-start; gap: 6px; }
|
|
2308
|
+
.gp-ov-swatch {
|
|
2309
|
+
flex: none;
|
|
2310
|
+
box-sizing: border-box;
|
|
2311
|
+
width: 10px;
|
|
2312
|
+
height: 10px;
|
|
2313
|
+
margin-top: 3px;
|
|
2314
|
+
border: 1px solid rgba(255, 255, 255, 0.7);
|
|
2315
|
+
border-radius: 2px;
|
|
2316
|
+
}
|
|
2317
|
+
.gp-ov-swatch[data-layer="bleed"] { background: var(--gp-ov-bleed-color); }
|
|
2318
|
+
.gp-ov-swatch[data-layer="safe"] { background: var(--gp-ov-color); }
|
|
2319
|
+
.gp-ov-swatch[data-layer="art"] { background: var(--gp-ov-art-color); }
|
|
2320
|
+
.gp-ov-swatch[data-layer="margins"] { background: var(--gp-ov-margins-color); }
|
|
2321
|
+
.gp-ov-note { opacity: 0.75; }
|
|
2322
|
+
@media print {
|
|
2323
|
+
.root { display: none; }
|
|
2324
|
+
}
|
|
2325
|
+
`;
|
|
2326
|
+
var HOST_STYLE = [
|
|
2327
|
+
"all: initial",
|
|
2328
|
+
"display: block",
|
|
2329
|
+
"position: absolute",
|
|
2330
|
+
"left: 0",
|
|
2331
|
+
"top: 0",
|
|
2332
|
+
"width: 0",
|
|
2333
|
+
"height: 0",
|
|
2334
|
+
"margin: 0",
|
|
2335
|
+
"padding: 0",
|
|
2336
|
+
"border: 0",
|
|
2337
|
+
"overflow: visible",
|
|
2338
|
+
"visibility: visible",
|
|
2339
|
+
"opacity: 1",
|
|
2340
|
+
"filter: none",
|
|
2341
|
+
"clip-path: none",
|
|
2342
|
+
"mask: none",
|
|
2343
|
+
"z-index: 2147483647",
|
|
2344
|
+
"pointer-events: none",
|
|
2345
|
+
"contain: style"
|
|
2346
|
+
].map((d) => `${d} !important`).join("; ");
|
|
2347
|
+
var OVERLAY_TAG = "gp-overlay";
|
|
2348
|
+
var host = null;
|
|
2349
|
+
var root = null;
|
|
2350
|
+
var canvas = null;
|
|
2351
|
+
var observer = null;
|
|
2352
|
+
var currentStyle = {};
|
|
2353
|
+
var COLOR_TOKEN = {
|
|
2354
|
+
bleed: "--gp-ov-bleed-color",
|
|
2355
|
+
safe: "--gp-ov-color",
|
|
2356
|
+
art: "--gp-ov-art-color",
|
|
2357
|
+
margins: "--gp-ov-margins-color"
|
|
2358
|
+
};
|
|
2359
|
+
function applyStyle() {
|
|
2360
|
+
if (!root)
|
|
2361
|
+
return;
|
|
2362
|
+
if (currentStyle.strength)
|
|
2363
|
+
root.dataset.strength = currentStyle.strength;
|
|
2364
|
+
for (const layer of OVERLAY_LAYERS) {
|
|
2365
|
+
const color = currentStyle.colors?.[layer];
|
|
2366
|
+
if (color)
|
|
2367
|
+
root.style.setProperty(COLOR_TOKEN[layer], color);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
function setOverlayStyle(style) {
|
|
2371
|
+
currentStyle = { ...currentStyle, ...style, colors: { ...currentStyle.colors, ...style.colors } };
|
|
2372
|
+
applyStyle();
|
|
2373
|
+
}
|
|
2374
|
+
function stageFrame() {
|
|
2375
|
+
const stage = document.body;
|
|
2376
|
+
const r = stage.getBoundingClientRect();
|
|
2377
|
+
const zoom = stage.offsetWidth > 0 ? r.width / stage.offsetWidth : 1;
|
|
2378
|
+
return { left: r.left, top: r.top, zoom: zoom || 1 };
|
|
2379
|
+
}
|
|
2380
|
+
function syncToStage() {
|
|
2381
|
+
if (!root || !canvas)
|
|
2382
|
+
return;
|
|
2383
|
+
const { left, top, zoom } = stageFrame();
|
|
2384
|
+
canvas.style.transform = `translate(${left + window.scrollX}px, ${top + window.scrollY}px) scale(${zoom})`;
|
|
2385
|
+
root.style.setProperty("--gp-ov-z", String(zoom));
|
|
2386
|
+
}
|
|
2387
|
+
function ensureRoot() {
|
|
2388
|
+
if (!(host && root && host.isConnected)) {
|
|
2389
|
+
host = document.createElement(OVERLAY_TAG);
|
|
2390
|
+
host.setAttribute("style", HOST_STYLE);
|
|
2391
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
2392
|
+
const sheet = document.createElement("style");
|
|
2393
|
+
sheet.textContent = OVERLAY_CSS;
|
|
2394
|
+
root = document.createElement("div");
|
|
2395
|
+
root.className = "root";
|
|
2396
|
+
shadow.append(sheet, root);
|
|
2397
|
+
document.documentElement.appendChild(host);
|
|
2398
|
+
applyStyle();
|
|
2399
|
+
observer = new MutationObserver(syncToStage);
|
|
2400
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["style"] });
|
|
2401
|
+
observer.observe(document.body, { attributes: true, attributeFilter: ["style"] });
|
|
2402
|
+
}
|
|
2403
|
+
root.textContent = "";
|
|
2404
|
+
canvas = div("gp-ov-canvas");
|
|
2405
|
+
canvas.setAttribute("aria-hidden", "true");
|
|
2406
|
+
root.appendChild(canvas);
|
|
2407
|
+
return canvas;
|
|
2408
|
+
}
|
|
2409
|
+
function clearOverlay() {
|
|
2410
|
+
observer?.disconnect();
|
|
2411
|
+
observer = null;
|
|
2412
|
+
host?.remove();
|
|
2413
|
+
host = null;
|
|
2414
|
+
root = null;
|
|
2415
|
+
canvas = null;
|
|
2292
2416
|
}
|
|
2293
|
-
var SKIP = new Set(["SCRIPT", "STYLE", "LINK", "TEMPLATE", "BR", "WBR", "SOURCE", "TRACK", "META"]);
|
|
2294
|
-
var TOL_PX = 1;
|
|
2295
2417
|
function div(cls, box) {
|
|
2296
2418
|
const el = document.createElement("div");
|
|
2297
2419
|
el.className = cls;
|
|
@@ -2305,111 +2427,225 @@
|
|
|
2305
2427
|
el.style.width = `${r.w}px`;
|
|
2306
2428
|
el.style.height = `${r.h}px`;
|
|
2307
2429
|
}
|
|
2308
|
-
function
|
|
2309
|
-
const el = div("gp-ov-tint");
|
|
2430
|
+
function unsafeTint(b) {
|
|
2431
|
+
const el = div("gp-ov-tint", b.sheet);
|
|
2310
2432
|
const t = b.trim;
|
|
2311
|
-
const
|
|
2312
|
-
|
|
2313
|
-
const r = clamp(b.content.x + b.content.w, t.x, t.x + t.w);
|
|
2314
|
-
const top = clamp(b.content.y, t.y, t.y + t.h);
|
|
2315
|
-
const bot = clamp(b.content.y + b.content.h, t.y, t.y + t.h);
|
|
2316
|
-
const x2 = t.x + t.w;
|
|
2317
|
-
const y2 = t.y + t.h;
|
|
2318
|
-
el.style.clipPath = `polygon(evenodd, ${t.x}px ${t.y}px, ${x2}px ${t.y}px, ${x2}px ${y2}px, ${t.x}px ${y2}px, ${t.x}px ${t.y}px, ` + `${l}px ${top}px, ${l}px ${bot}px, ${r}px ${bot}px, ${r}px ${top}px, ${l}px ${top}px)`;
|
|
2433
|
+
const s = b.safe;
|
|
2434
|
+
el.style.clipPath = `polygon(evenodd, ${t.x}px ${t.y}px, ${t.x + t.w}px ${t.y}px, ${t.x + t.w}px ${t.y + t.h}px, ${t.x}px ${t.y + t.h}px, ${t.x}px ${t.y}px, ` + `${s.x}px ${s.y}px, ${s.x}px ${s.y + s.h}px, ${s.x + s.w}px ${s.y + s.h}px, ${s.x + s.w}px ${s.y}px, ${s.x}px ${s.y}px)`;
|
|
2319
2435
|
return el;
|
|
2320
2436
|
}
|
|
2321
|
-
function
|
|
2322
|
-
|
|
2323
|
-
|
|
2437
|
+
function marginsBox(p, side) {
|
|
2438
|
+
const { width, height, margin } = p.strip.geometry;
|
|
2439
|
+
const shift = side === "verso" ? p.strip.versoShift : 0;
|
|
2440
|
+
const left = margin.left - shift;
|
|
2441
|
+
const right = margin.right + shift;
|
|
2442
|
+
return {
|
|
2443
|
+
x: left * PX_PER_PT,
|
|
2444
|
+
y: margin.top * PX_PER_PT,
|
|
2445
|
+
w: Math.max(0, width - left - right) * PX_PER_PT,
|
|
2446
|
+
h: Math.max(0, height - margin.top - margin.bottom) * PX_PER_PT
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
var TOL_PX = 1;
|
|
2450
|
+
var SKIP = new Set(["SCRIPT", "STYLE", "LINK", "TEMPLATE", "BR", "WBR", "SOURCE", "TRACK", "META"]);
|
|
2451
|
+
var ART_TAGS = new Set(["img", "svg", "video", "canvas"]);
|
|
2452
|
+
var inches = (px) => +(Math.abs(px) / 96).toFixed(2);
|
|
2453
|
+
var ptIn = (pt2) => `${+(pt2 / 72).toFixed(3)}in`;
|
|
2454
|
+
function legend(layers, area, summary) {
|
|
2455
|
+
const el = div("gp-ov-legend");
|
|
2456
|
+
const add = (cls, ...content) => {
|
|
2457
|
+
const line = div(cls);
|
|
2458
|
+
line.append(...content);
|
|
2459
|
+
el.appendChild(line);
|
|
2460
|
+
};
|
|
2461
|
+
const row = (layer, name, text) => {
|
|
2462
|
+
const swatch = div("gp-ov-swatch");
|
|
2463
|
+
swatch.dataset.layer = layer;
|
|
2464
|
+
const bold = document.createElement("b");
|
|
2465
|
+
bold.textContent = name;
|
|
2466
|
+
const label = document.createElement("span");
|
|
2467
|
+
label.append(bold, text);
|
|
2468
|
+
add("gp-ov-row", swatch, label);
|
|
2469
|
+
};
|
|
2470
|
+
const { bleedPt, safePt, artSafePt, counts } = summary;
|
|
2471
|
+
if (layers.bleed) {
|
|
2472
|
+
row("bleed", "Bleed", bleedPt > 0 ? ` ${ptIn(bleedPt)} — top, bottom, outside; none at the binding` : " — none set (page.bleed in manifest.yaml)");
|
|
2473
|
+
}
|
|
2474
|
+
if (layers.safe) {
|
|
2475
|
+
row("safe", "Safe area: text", safePt > 0 ? ` — ${ptIn(safePt)}, every edge` : " — none set (page.safe in manifest.yaml)");
|
|
2476
|
+
}
|
|
2477
|
+
if (layers.art) {
|
|
2478
|
+
row("art", "Safe area: art", safePt <= 0 && artSafePt <= 0 ? " — none set (page.artSafe in manifest.yaml)" : artSafePt === safePt ? ` — ${ptIn(artSafePt)}, every edge` : ` — ${ptIn(artSafePt)} top, bottom, outside; ${ptIn(safePt)} at the binding`);
|
|
2479
|
+
}
|
|
2480
|
+
if (layers.margins)
|
|
2481
|
+
row("margins", "Page margins", " — your stylesheet's @page margins");
|
|
2482
|
+
if (area && (layers.bleed || layers.safe || layers.art)) {
|
|
2483
|
+
if (area.spec) {
|
|
2484
|
+
const link = document.createElement("a");
|
|
2485
|
+
link.href = area.spec.url;
|
|
2486
|
+
link.target = "_blank";
|
|
2487
|
+
link.rel = "noopener";
|
|
2488
|
+
link.textContent = area.spec.label;
|
|
2489
|
+
add("gp-ov-note", "from ", link);
|
|
2490
|
+
} else {
|
|
2491
|
+
add("gp-ov-note", `from manifest.yaml${area.preset ? ` (preset ${area.preset})` : ""}`);
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
if (layers.safe || layers.art) {
|
|
2495
|
+
const found = [];
|
|
2496
|
+
if (counts.text)
|
|
2497
|
+
found.push(`${counts.text} text outside the safe area`);
|
|
2498
|
+
if (counts.art)
|
|
2499
|
+
found.push(`${counts.art} art outside${counts.text ? "" : " the safe area"}`);
|
|
2500
|
+
if (counts.bleed)
|
|
2501
|
+
found.push(`${counts.bleed} in the bleed band`);
|
|
2502
|
+
if (counts.offPage)
|
|
2503
|
+
found.push(`${counts.offPage} off the page`);
|
|
2504
|
+
if (!found.length) {
|
|
2505
|
+
found.push(`${layers.safe && layers.art ? "everything" : layers.safe ? "all text" : "all art"} inside the safe area`);
|
|
2506
|
+
}
|
|
2507
|
+
if (counts.intended)
|
|
2508
|
+
found.push(`${counts.intended} placed on purpose`);
|
|
2509
|
+
add("gp-ov-found", found.join(" · "));
|
|
2510
|
+
}
|
|
2511
|
+
const key = document.documentElement.dataset.overlayKey;
|
|
2512
|
+
if (key)
|
|
2513
|
+
add("gp-ov-note", `${key} hides`);
|
|
2514
|
+
return el;
|
|
2324
2515
|
}
|
|
2325
|
-
function paintOverlay(pages, strips,
|
|
2326
|
-
const
|
|
2327
|
-
|
|
2328
|
-
const
|
|
2516
|
+
function paintOverlay(pages, strips, area, layers) {
|
|
2517
|
+
const layer = ensureRoot();
|
|
2518
|
+
syncToStage();
|
|
2519
|
+
const stage = stageFrame();
|
|
2329
2520
|
const painted = new Map;
|
|
2330
2521
|
for (const p of pages) {
|
|
2331
|
-
const
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
host.style.top = p.sheet.style.top;
|
|
2344
|
-
host.dataset.page = String(p.index + 1);
|
|
2345
|
-
if (boxes.bleed > 0) {
|
|
2346
|
-
const bb = boxes.bleedBox;
|
|
2522
|
+
const side = p.sheet.dataset.side === "verso" ? "verso" : "recto";
|
|
2523
|
+
const boxes = pageBoxes(area ?? sheetArea(p.sheet), side, PX_PER_PT);
|
|
2524
|
+
const rect = p.sheet.getBoundingClientRect();
|
|
2525
|
+
const host2 = div("gp-ov-page", {
|
|
2526
|
+
x: (rect.left - stage.left) / stage.zoom,
|
|
2527
|
+
y: (rect.top - stage.top) / stage.zoom,
|
|
2528
|
+
w: boxes.sheet.w,
|
|
2529
|
+
h: boxes.sheet.h
|
|
2530
|
+
});
|
|
2531
|
+
host2.dataset.page = String(p.index + 1);
|
|
2532
|
+
if (layers.bleed && boxes.bleed > 0) {
|
|
2533
|
+
const sh = boxes.sheet;
|
|
2347
2534
|
const t = boxes.trim;
|
|
2348
|
-
const band = div("gp-ov-bleed",
|
|
2349
|
-
band.style.borderWidth = `${t.y -
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
}
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2535
|
+
const band = div("gp-ov-bleed", sh);
|
|
2536
|
+
band.style.borderWidth = `${t.y - sh.y}px ${sh.x + sh.w - (t.x + t.w)}px ${sh.y + sh.h - (t.y + t.h)}px ${t.x - sh.x}px`;
|
|
2537
|
+
host2.appendChild(band);
|
|
2538
|
+
host2.appendChild(div("gp-ov-trim", t));
|
|
2539
|
+
}
|
|
2540
|
+
if (layers.safe && area && area.safe > 0) {
|
|
2541
|
+
host2.appendChild(unsafeTint(boxes));
|
|
2542
|
+
host2.appendChild(div("gp-ov-safe", boxes.safe));
|
|
2543
|
+
}
|
|
2544
|
+
if (layers.art && area && area.artSafe > 0)
|
|
2545
|
+
host2.appendChild(div("gp-ov-art", boxes.safeArt));
|
|
2546
|
+
if (layers.margins && !p.padded)
|
|
2547
|
+
host2.appendChild(div("gp-ov-margins", marginsBox(p, side)));
|
|
2548
|
+
layer.appendChild(host2);
|
|
2549
|
+
painted.set(p.index, { host: host2, boxes, sheet: p.sheet, rect });
|
|
2357
2550
|
}
|
|
2358
2551
|
const flags = [];
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
const kinds = [];
|
|
2369
|
-
const found = [];
|
|
2370
|
-
for (const r of Array.from(el.getClientRects())) {
|
|
2552
|
+
const counts = { text: 0, art: 0, bleed: 0, offPage: 0, intended: 0 };
|
|
2553
|
+
const seen = new Set;
|
|
2554
|
+
const range = document.createRange();
|
|
2555
|
+
const source = area?.spec?.label ?? "the safe area";
|
|
2556
|
+
const inspect = (root2, pageOf2, zoom) => {
|
|
2557
|
+
if (!layers.safe && !layers.art)
|
|
2558
|
+
return;
|
|
2559
|
+
const judge = (el, rule, rects) => {
|
|
2560
|
+
for (const r of rects) {
|
|
2371
2561
|
if (r.width <= 0 && r.height <= 0)
|
|
2372
2562
|
continue;
|
|
2373
|
-
const
|
|
2374
|
-
const ay = r.top + Math.min(r.height, colH || r.height) / 2;
|
|
2375
|
-
const target = painted.get(strip.offset + indexInStrip(ax, ay, strip));
|
|
2563
|
+
const target = pageOf2(r);
|
|
2376
2564
|
if (!target)
|
|
2377
2565
|
continue;
|
|
2378
2566
|
target.rect ??= target.sheet.getBoundingClientRect();
|
|
2379
|
-
const
|
|
2567
|
+
const box = {
|
|
2380
2568
|
x: (r.left - target.rect.left) / zoom,
|
|
2381
2569
|
y: (r.top - target.rect.top) / zoom,
|
|
2382
2570
|
w: r.width / zoom,
|
|
2383
2571
|
h: r.height / zoom
|
|
2384
2572
|
};
|
|
2385
|
-
const kind = classifyRect(
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2573
|
+
const { kind, gap, need } = classifyRect(box, target.boxes, rule, TOL_PX);
|
|
2574
|
+
if (kind === "inside")
|
|
2575
|
+
continue;
|
|
2576
|
+
const key = `${target.host.dataset.page} ${box.x} ${box.y} ${box.w} ${box.h}`;
|
|
2577
|
+
if (seen.has(key))
|
|
2578
|
+
continue;
|
|
2579
|
+
seen.add(key);
|
|
2580
|
+
const placed = el.closest(INTENT_SELECTOR) !== null;
|
|
2581
|
+
const bucket = placed ? "intended" : kind === "unsafe" ? rule : kind === "bleed" ? "bleed" : "offPage";
|
|
2582
|
+
counts[bucket]++;
|
|
2583
|
+
const title = `${rule} ${inches(gap)}in ${gap < 0 ? "past" : "from"} the trim; ${source} needs ${inches(need)}in`;
|
|
2584
|
+
flags.push({
|
|
2585
|
+
host: target.host,
|
|
2586
|
+
kind: placed ? "intended" : kind,
|
|
2587
|
+
rule,
|
|
2588
|
+
box,
|
|
2589
|
+
title: placed ? `${title} (placed on purpose)` : title
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
const visit = (node) => {
|
|
2594
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
2595
|
+
if (!layers.safe || !node.nodeValue?.trim())
|
|
2596
|
+
return;
|
|
2597
|
+
range.selectNodeContents(node);
|
|
2598
|
+
judge(node.parentElement, "text", range.getClientRects());
|
|
2599
|
+
return;
|
|
2389
2600
|
}
|
|
2390
|
-
|
|
2391
|
-
if (worst !== "inside") {
|
|
2392
|
-
const isIntended = el.closest(INTENT_SELECTOR) !== null;
|
|
2393
|
-
if (isIntended)
|
|
2394
|
-
intended++;
|
|
2395
|
-
else
|
|
2396
|
-
issues++;
|
|
2397
|
-
for (const f of found)
|
|
2398
|
-
flags.push(isIntended ? { ...f, kind: "intended" } : f);
|
|
2601
|
+
if (!(node instanceof Element) || SKIP.has(node.tagName) || node.classList.contains("gp-wrap-spacer"))
|
|
2399
2602
|
return;
|
|
2603
|
+
if (layers.art) {
|
|
2604
|
+
const cs = getComputedStyle(node);
|
|
2605
|
+
if (ART_TAGS.has(node.localName) || cs.backgroundImage !== "none" || !/^rgba\(.*, 0\)$/.test(cs.backgroundColor) || parseFloat(cs.borderTopWidth) > 0 || parseFloat(cs.borderRightWidth) > 0 || parseFloat(cs.borderBottomWidth) > 0 || parseFloat(cs.borderLeftWidth) > 0) {
|
|
2606
|
+
judge(node, "art", node.getClientRects());
|
|
2607
|
+
}
|
|
2400
2608
|
}
|
|
2401
|
-
for (const child of
|
|
2609
|
+
for (const child of node.childNodes)
|
|
2402
2610
|
visit(child);
|
|
2403
2611
|
};
|
|
2404
|
-
|
|
2405
|
-
|
|
2612
|
+
visit(root2);
|
|
2613
|
+
};
|
|
2614
|
+
for (const strip of strips) {
|
|
2615
|
+
const zoom = cssZoomOf(strip.el);
|
|
2616
|
+
const colW = (parseFloat(strip.el.style.getPropertyValue("--gp-content-w")) || 0) * zoom;
|
|
2617
|
+
const colH = (parseFloat(strip.el.style.getPropertyValue("--gp-content-h")) || 0) * zoom;
|
|
2618
|
+
const pageOf2 = (r) => {
|
|
2619
|
+
const ax = r.left + Math.min(r.width, colW || r.width) / 2;
|
|
2620
|
+
const ay = r.top + Math.min(r.height, colH || r.height) / 2;
|
|
2621
|
+
return painted.get(strip.offset + indexInStrip(ax, ay, strip));
|
|
2622
|
+
};
|
|
2623
|
+
for (const child of strip.el.childNodes)
|
|
2624
|
+
inspect(child, pageOf2, zoom);
|
|
2625
|
+
}
|
|
2626
|
+
for (const target of painted.values()) {
|
|
2627
|
+
for (const furniture of target.sheet.querySelectorAll(".gp-marginbox"))
|
|
2628
|
+
inspect(furniture, () => target, stage.zoom);
|
|
2406
2629
|
}
|
|
2407
2630
|
for (const f of flags) {
|
|
2408
|
-
const el = div(
|
|
2631
|
+
const el = div("gp-ov-flag", f.box);
|
|
2409
2632
|
el.dataset.kind = f.kind;
|
|
2633
|
+
el.dataset.rule = f.rule;
|
|
2634
|
+
el.title = f.title;
|
|
2410
2635
|
f.host.appendChild(el);
|
|
2411
2636
|
}
|
|
2412
|
-
|
|
2637
|
+
const summary = {
|
|
2638
|
+
on: true,
|
|
2639
|
+
layers,
|
|
2640
|
+
issues: counts.text + counts.art + counts.bleed + counts.offPage,
|
|
2641
|
+
intended: counts.intended,
|
|
2642
|
+
bleedPt: area?.bleed ?? 0,
|
|
2643
|
+
safePt: area?.safe ?? 0,
|
|
2644
|
+
artSafePt: area?.artSafe ?? 0,
|
|
2645
|
+
counts
|
|
2646
|
+
};
|
|
2647
|
+
root?.appendChild(legend(layers, area, summary));
|
|
2648
|
+
return summary;
|
|
2413
2649
|
}
|
|
2414
2650
|
|
|
2415
2651
|
// src/engine/viewer/decorate.ts
|
|
@@ -2441,10 +2677,11 @@
|
|
|
2441
2677
|
let paddedPages = new Set;
|
|
2442
2678
|
const warnings = [];
|
|
2443
2679
|
let overlayOn = false;
|
|
2680
|
+
let overlayLayers = OVERLAY_OFF.layers;
|
|
2444
2681
|
let overlayPages = [];
|
|
2445
2682
|
let overlaySummary = OVERLAY_OFF;
|
|
2446
2683
|
const paintOverlayNow = () => {
|
|
2447
|
-
overlaySummary = paintOverlay(overlayPages, layout.strips,
|
|
2684
|
+
overlaySummary = paintOverlay(overlayPages, layout.strips, printAreaFromMeta(), overlayLayers);
|
|
2448
2685
|
window.dispatchEvent(new CustomEvent("gp:overlay", { detail: overlaySummary }));
|
|
2449
2686
|
};
|
|
2450
2687
|
const api = {
|
|
@@ -2457,19 +2694,31 @@
|
|
|
2457
2694
|
setDesigner(on) {
|
|
2458
2695
|
document.body.dataset.designer = on ? "on" : "off";
|
|
2459
2696
|
},
|
|
2460
|
-
setOverlay(
|
|
2697
|
+
setOverlay(state, style) {
|
|
2461
2698
|
if (style) {
|
|
2462
|
-
const
|
|
2699
|
+
const clean = sanitizeOverlayStyle(style);
|
|
2700
|
+
setOverlayStyle(clean);
|
|
2701
|
+
const { strength, colors } = clean;
|
|
2463
2702
|
if (strength)
|
|
2464
2703
|
document.body.dataset.overlayStrength = strength;
|
|
2465
|
-
if (
|
|
2466
|
-
document.body.
|
|
2704
|
+
if (colors?.safe)
|
|
2705
|
+
document.body.dataset.overlayColor = colors.safe;
|
|
2706
|
+
if (colors?.art)
|
|
2707
|
+
document.body.dataset.overlayArtColor = colors.art;
|
|
2708
|
+
if (colors?.bleed)
|
|
2709
|
+
document.body.dataset.overlayBleedColor = colors.bleed;
|
|
2710
|
+
if (colors?.margins)
|
|
2711
|
+
document.body.dataset.overlayMarginsColor = colors.margins;
|
|
2467
2712
|
}
|
|
2468
2713
|
const wasOn = overlayOn;
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2714
|
+
const next = layersFrom(state);
|
|
2715
|
+
const sameLayers = OVERLAY_LAYERS.every((layer) => next[layer] === overlayLayers[layer]);
|
|
2716
|
+
overlayLayers = next;
|
|
2717
|
+
overlayOn = OVERLAY_LAYERS.some((layer) => next[layer]);
|
|
2718
|
+
document.body.dataset.overlay = overlayOn ? "on" : "off";
|
|
2719
|
+
if (overlayOn) {
|
|
2720
|
+
document.body.dataset.overlayLayers = OVERLAY_LAYERS.filter((layer) => next[layer]).join(",");
|
|
2721
|
+
if (!(wasOn && sameLayers && style))
|
|
2473
2722
|
paintOverlayNow();
|
|
2474
2723
|
} else {
|
|
2475
2724
|
clearOverlay();
|
|
@@ -2613,8 +2862,8 @@
|
|
|
2613
2862
|
}
|
|
2614
2863
|
if (!marked.length)
|
|
2615
2864
|
return;
|
|
2616
|
-
const
|
|
2617
|
-
const cx =
|
|
2865
|
+
const canvas2 = document.createElement("canvas");
|
|
2866
|
+
const cx = canvas2.getContext("2d");
|
|
2618
2867
|
for (const m of marked)
|
|
2619
2868
|
m.el.setAttribute(m.attr, m.raw.replace(LEADER_RE, ""));
|
|
2620
2869
|
document.body.offsetHeight;
|
|
@@ -2678,13 +2927,7 @@
|
|
|
2678
2927
|
drawMarginBoxes(sheet, ctx, layout.totalPages - paddedPages.size);
|
|
2679
2928
|
drawGuides(sheet, ctx);
|
|
2680
2929
|
drawCropMarks(sheet, ctx);
|
|
2681
|
-
overlayPages.push({
|
|
2682
|
-
index: bookIndex,
|
|
2683
|
-
sheet,
|
|
2684
|
-
strip,
|
|
2685
|
-
geometry: ctx.geometry,
|
|
2686
|
-
margin: ctx.padded || blankPages.has(bookIndex) ? ctx.geometry.margin : pageFrameMargin(flushMargins(g.margin, strip.flushEdges ?? []), strip.versoShift, side)
|
|
2687
|
-
});
|
|
2930
|
+
overlayPages.push({ index: bookIndex, sheet, strip, padded: ctx.padded });
|
|
2688
2931
|
}
|
|
2689
2932
|
const rows = Math.max(1, Math.ceil((strip.pages + shift) / perRow));
|
|
2690
2933
|
run.style.height = `${rowStride * (rows - 1) + PX_PER_PT * g.height}px`;
|
|
@@ -2773,15 +3016,6 @@
|
|
|
2773
3016
|
});
|
|
2774
3017
|
sheet.appendChild(trim);
|
|
2775
3018
|
}
|
|
2776
|
-
const safe = document.createElement("div");
|
|
2777
|
-
safe.className = "gp-guide-safe";
|
|
2778
|
-
Object.assign(safe.style, {
|
|
2779
|
-
left: px(g.margin.left),
|
|
2780
|
-
top: px(g.margin.top),
|
|
2781
|
-
width: px(g.width - g.margin.left - g.margin.right),
|
|
2782
|
-
height: px(g.height - g.margin.top - g.margin.bottom)
|
|
2783
|
-
});
|
|
2784
|
-
sheet.appendChild(safe);
|
|
2785
3019
|
}
|
|
2786
3020
|
function checkOverflow(strip, out) {
|
|
2787
3021
|
const h = strip.el.clientHeight;
|