@drawnagency/primitives 0.1.117 → 0.1.119
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/{chunk-O37AV27P.js → chunk-5JYHTHVR.js} +28 -0
- package/dist/{chunk-W72BPGR3.js → chunk-BZKHHUIN.js} +44 -8
- package/dist/{chunk-CEFFP3CH.js → chunk-G6O3TYPJ.js} +297 -83
- package/dist/{chunk-L7WTERU5.js → chunk-HFHM4MNK.js} +33 -10
- package/dist/{chunk-RIITGTV3.js → chunk-LQHBC7C6.js} +37 -2
- package/dist/{chunk-VY3IFGE3.js → chunk-QAMAIDXZ.js} +1 -1
- package/dist/{chunk-LNQUUC2S.js → chunk-RIN2QCYJ.js} +9 -11
- package/dist/{chunk-HUOW3ZV2.js → chunk-UNFPATDE.js} +8 -10
- package/dist/{chunk-MSBHMY3C.js → chunk-YKKGVSJH.js} +35 -37
- package/dist/{chunk-67P34WNW.js → chunk-ZKVQMIMJ.js} +3 -20
- package/dist/collab/rebase.js +4 -5
- package/dist/components/chat/ChatComposer.d.ts +0 -4
- package/dist/components/chat/ChatComposer.d.ts.map +1 -1
- package/dist/components/chat/ChatPanel.d.ts +2 -3
- package/dist/components/chat/ChatPanel.d.ts.map +1 -1
- package/dist/components/chat/markdown.d.ts +2 -3
- package/dist/components/chat/markdown.d.ts.map +1 -1
- package/dist/components/editor/PagesModal.d.ts +0 -2
- package/dist/components/editor/PagesModal.d.ts.map +1 -1
- package/dist/components/editor/index.js +15 -19
- package/dist/components/primitives/EditablePlainText.d.ts.map +1 -1
- package/dist/components/primitives/index.js +11 -15
- package/dist/components/sections/brand-guide.js +10 -13
- package/dist/components/sections/register-schemas.js +16 -21
- package/dist/components/sections/register.js +16 -21
- package/dist/components/shell/AudienceChips.d.ts +1 -3
- package/dist/components/shell/AudienceChips.d.ts.map +1 -1
- package/dist/components/shell/AudienceDetailsPanel.d.ts +3 -1
- package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts +0 -34
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
- package/dist/hooks/useSortableNavRow.d.ts +1 -1
- package/dist/hooks/useSortableRow.d.ts +1 -1
- package/dist/index.js +83 -90
- package/dist/lib/index-ops.js +5 -6
- package/dist/lib/index.js +27 -32
- package/dist/lib/pages.d.ts +0 -2
- package/dist/lib/pages.d.ts.map +1 -1
- package/dist/lib/sidecars.js +2 -2
- package/dist/lib/site-validation.js +13 -14
- package/dist/lib/storage-tier.js +4 -4
- package/dist/schemas/index.js +42 -45
- package/dist/schemas/site-config.d.ts +1 -277
- package/dist/schemas/site-config.d.ts.map +1 -1
- package/package.json +2 -42
- package/src/components/chat/ChatComposer.tsx +0 -4
- package/src/components/chat/ChatPanel.tsx +2 -3
- package/src/components/chat/markdown.ts +2 -3
- package/src/components/editor/PagesModal.tsx +1 -15
- package/src/components/editor/StatusIndicator.tsx +4 -4
- package/src/components/primitives/EditablePlainText.tsx +27 -3
- package/src/components/shell/AudienceChips.tsx +1 -3
- package/src/components/shell/AudienceDetailsPanel.tsx +6 -4
- package/src/components/shell/EditorShell.tsx +18 -114
- package/src/components/shell/SiteSettingsModal.tsx +0 -11
- package/src/lib/pages.ts +0 -22
- package/src/schemas/index.ts +0 -4
- package/src/schemas/site-config.ts +4 -32
- package/dist/chunk-4TZJZU2T.js +0 -92
- package/dist/chunk-DIMDRBFK.js +0 -11
- package/dist/chunk-FV7JQRCN.js +0 -94
- package/dist/chunk-IIDKW7AV.js +0 -41
- package/dist/chunk-JCDZAFX2.js +0 -224
- package/dist/chunk-MM7KZS5C.js +0 -30
- package/dist/chunk-QQ3S3P5P.js +0 -38
- package/dist/chunk-TEOAKGZA.js +0 -784
- package/dist/chunk-VAYZJKVR.js +0 -209
- package/dist/components/shell/DocInspector.d.ts +0 -18
- package/dist/components/shell/DocInspector.d.ts.map +0 -1
- package/dist/components/shell/DocumentEditorOverlay.d.ts +0 -29
- package/dist/components/shell/DocumentEditorOverlay.d.ts.map +0 -1
- package/dist/components/shell/DocumentPresentOverlay.d.ts +0 -30
- package/dist/components/shell/DocumentPresentOverlay.d.ts.map +0 -1
- package/dist/components/shell/SiteSettingsDecks.d.ts +0 -13
- package/dist/components/shell/SiteSettingsDecks.d.ts.map +0 -1
- package/dist/deck/DeckComponentView.d.ts +0 -13
- package/dist/deck/DeckComponentView.d.ts.map +0 -1
- package/dist/deck/DeckPlayer.d.ts +0 -26
- package/dist/deck/DeckPlayer.d.ts.map +0 -1
- package/dist/deck/DeckSlideView.d.ts +0 -17
- package/dist/deck/DeckSlideView.d.ts.map +0 -1
- package/dist/deck/DeckStage.d.ts +0 -16
- package/dist/deck/DeckStage.d.ts.map +0 -1
- package/dist/deck/components/DeckImage.d.ts +0 -14
- package/dist/deck/components/DeckImage.d.ts.map +0 -1
- package/dist/deck/components/DeckImageGrid.d.ts +0 -27
- package/dist/deck/components/DeckImageGrid.d.ts.map +0 -1
- package/dist/deck/components/DeckRichText.d.ts +0 -22
- package/dist/deck/components/DeckRichText.d.ts.map +0 -1
- package/dist/deck/components/DeckVideo.d.ts +0 -15
- package/dist/deck/components/DeckVideo.d.ts.map +0 -1
- package/dist/deck/editing.d.ts +0 -50
- package/dist/deck/editing.d.ts.map +0 -1
- package/dist/deck/flip.d.ts +0 -11
- package/dist/deck/flip.d.ts.map +0 -1
- package/dist/deck/index.d.ts +0 -24
- package/dist/deck/index.d.ts.map +0 -1
- package/dist/deck/index.js +0 -51
- package/dist/deck/layouts/CenteredTextLayout.d.ts +0 -12
- package/dist/deck/layouts/CenteredTextLayout.d.ts.map +0 -1
- package/dist/deck/layouts/ColumnSplitLayout.d.ts +0 -14
- package/dist/deck/layouts/ColumnSplitLayout.d.ts.map +0 -1
- package/dist/deck/layouts/FullBleedImageLayout.d.ts +0 -14
- package/dist/deck/layouts/FullBleedImageLayout.d.ts.map +0 -1
- package/dist/deck/media.d.ts +0 -33
- package/dist/deck/media.d.ts.map +0 -1
- package/dist/deck/tokens.d.ts +0 -22
- package/dist/deck/tokens.d.ts.map +0 -1
- package/dist/deck/useStageScale.d.ts +0 -10
- package/dist/deck/useStageScale.d.ts.map +0 -1
- package/dist/deck-builder/DeckBuilderApp.d.ts +0 -30
- package/dist/deck-builder/DeckBuilderApp.d.ts.map +0 -1
- package/dist/deck-builder/DeckBuilderTopBar.d.ts +0 -24
- package/dist/deck-builder/DeckBuilderTopBar.d.ts.map +0 -1
- package/dist/deck-builder/DeckChatPanel.d.ts +0 -45
- package/dist/deck-builder/DeckChatPanel.d.ts.map +0 -1
- package/dist/deck-builder/DeckEditor.d.ts +0 -37
- package/dist/deck-builder/DeckEditor.d.ts.map +0 -1
- package/dist/deck-builder/DeckLibrary.d.ts +0 -22
- package/dist/deck-builder/DeckLibrary.d.ts.map +0 -1
- package/dist/deck-builder/DeckSlideSurface.d.ts +0 -31
- package/dist/deck-builder/DeckSlideSurface.d.ts.map +0 -1
- package/dist/deck-builder/deck-api.d.ts +0 -76
- package/dist/deck-builder/deck-api.d.ts.map +0 -1
- package/dist/deck-builder/deck-chat-client.d.ts +0 -44
- package/dist/deck-builder/deck-chat-client.d.ts.map +0 -1
- package/dist/deck-builder/deck-chat-history.d.ts +0 -10
- package/dist/deck-builder/deck-chat-history.d.ts.map +0 -1
- package/dist/deck-builder/index.d.ts +0 -13
- package/dist/deck-builder/index.d.ts.map +0 -1
- package/dist/deck-builder/index.js +0 -1498
- package/dist/deck-builder/starter-deck.d.ts +0 -23
- package/dist/deck-builder/starter-deck.d.ts.map +0 -1
- package/dist/deck-builder/types.d.ts +0 -29
- package/dist/deck-builder/types.d.ts.map +0 -1
- package/dist/deck-builder/useSortableSlide.d.ts +0 -29
- package/dist/deck-builder/useSortableSlide.d.ts.map +0 -1
- package/dist/document/assets/fonts/albra-grotesk-bold.woff +0 -0
- package/dist/document/assets/fonts/albra-grotesk-regular.woff +0 -0
- package/dist/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
- package/dist/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
- package/dist/document/components/DocCoverPage.d.ts +0 -11
- package/dist/document/components/DocCoverPage.d.ts.map +0 -1
- package/dist/document/components/DocPage.d.ts +0 -10
- package/dist/document/components/DocPage.d.ts.map +0 -1
- package/dist/document/components/DocRail.d.ts +0 -28
- package/dist/document/components/DocRail.d.ts.map +0 -1
- package/dist/document/components/DocSectionPage.d.ts +0 -12
- package/dist/document/components/DocSectionPage.d.ts.map +0 -1
- package/dist/document/components/DocViewer.d.ts +0 -21
- package/dist/document/components/DocViewer.d.ts.map +0 -1
- package/dist/document/components/Wordmark.d.ts +0 -4
- package/dist/document/components/Wordmark.d.ts.map +0 -1
- package/dist/document/components/measure.d.ts +0 -7
- package/dist/document/components/measure.d.ts.map +0 -1
- package/dist/document/components/useDocPages.d.ts +0 -12
- package/dist/document/components/useDocPages.d.ts.map +0 -1
- package/dist/document/engine/blocks.d.ts +0 -2
- package/dist/document/engine/blocks.d.ts.map +0 -1
- package/dist/document/engine/harvest.d.ts +0 -3
- package/dist/document/engine/harvest.d.ts.map +0 -1
- package/dist/document/engine/masonry.d.ts +0 -26
- package/dist/document/engine/masonry.d.ts.map +0 -1
- package/dist/document/engine/paginate.d.ts +0 -43
- package/dist/document/engine/paginate.d.ts.map +0 -1
- package/dist/document/engine/settings.d.ts +0 -91
- package/dist/document/engine/settings.d.ts.map +0 -1
- package/dist/document/engine/types.d.ts +0 -44
- package/dist/document/engine/types.d.ts.map +0 -1
- package/dist/document/index.d.ts +0 -13
- package/dist/document/index.d.ts.map +0 -1
- package/dist/document/index.js +0 -1030
- package/dist/document/styles/document.css +0 -217
- package/dist/lib/deck-access.d.ts +0 -86
- package/dist/lib/deck-access.d.ts.map +0 -1
- package/dist/lib/deck-access.js +0 -58
- package/dist/lib/deck-dexie.d.ts +0 -88
- package/dist/lib/deck-dexie.d.ts.map +0 -1
- package/dist/lib/deck-dexie.js +0 -22
- package/dist/lib/deck-edit.d.ts +0 -67
- package/dist/lib/deck-edit.d.ts.map +0 -1
- package/dist/lib/deck-media-assets.d.ts +0 -27
- package/dist/lib/deck-media-assets.d.ts.map +0 -1
- package/dist/lib/deck-media-assets.js +0 -25
- package/dist/lib/deck-media-refs.d.ts +0 -35
- package/dist/lib/deck-media-refs.d.ts.map +0 -1
- package/dist/lib/deck-media-refs.js +0 -36
- package/dist/lib/deck-tool.d.ts +0 -25
- package/dist/lib/deck-tool.d.ts.map +0 -1
- package/dist/lib/deck-tool.js +0 -58
- package/dist/lib/document-input.d.ts +0 -25
- package/dist/lib/document-input.d.ts.map +0 -1
- package/dist/schemas/deck-meta.d.ts +0 -85
- package/dist/schemas/deck-meta.d.ts.map +0 -1
- package/dist/schemas/deck-meta.js +0 -64
- package/dist/schemas/deck.d.ts +0 -954
- package/dist/schemas/deck.d.ts.map +0 -1
- package/dist/schemas/deck.js +0 -65
- package/src/components/shell/DocInspector.tsx +0 -314
- package/src/components/shell/DocumentEditorOverlay.tsx +0 -179
- package/src/components/shell/DocumentPresentOverlay.tsx +0 -87
- package/src/components/shell/SiteSettingsDecks.tsx +0 -41
- package/src/deck/DeckComponentView.tsx +0 -28
- package/src/deck/DeckPlayer.tsx +0 -166
- package/src/deck/DeckSlideView.tsx +0 -38
- package/src/deck/DeckStage.tsx +0 -39
- package/src/deck/components/DeckImage.tsx +0 -38
- package/src/deck/components/DeckImageGrid.tsx +0 -254
- package/src/deck/components/DeckRichText.tsx +0 -111
- package/src/deck/components/DeckVideo.tsx +0 -81
- package/src/deck/editing.tsx +0 -201
- package/src/deck/flip.ts +0 -70
- package/src/deck/index.ts +0 -30
- package/src/deck/layouts/CenteredTextLayout.tsx +0 -29
- package/src/deck/layouts/ColumnSplitLayout.tsx +0 -69
- package/src/deck/layouts/FullBleedImageLayout.tsx +0 -58
- package/src/deck/media.tsx +0 -46
- package/src/deck/tokens.ts +0 -57
- package/src/deck/useStageScale.ts +0 -44
- package/src/deck-builder/DeckBuilderApp.tsx +0 -572
- package/src/deck-builder/DeckBuilderTopBar.tsx +0 -62
- package/src/deck-builder/DeckChatPanel.tsx +0 -334
- package/src/deck-builder/DeckEditor.tsx +0 -258
- package/src/deck-builder/DeckLibrary.tsx +0 -195
- package/src/deck-builder/DeckSlideSurface.tsx +0 -55
- package/src/deck-builder/deck-api.ts +0 -177
- package/src/deck-builder/deck-chat-client.ts +0 -129
- package/src/deck-builder/deck-chat-history.ts +0 -62
- package/src/deck-builder/index.ts +0 -12
- package/src/deck-builder/starter-deck.ts +0 -86
- package/src/deck-builder/types.ts +0 -24
- package/src/deck-builder/useSortableSlide.ts +0 -102
- package/src/document/assets/fonts/albra-grotesk-bold.woff +0 -0
- package/src/document/assets/fonts/albra-grotesk-regular.woff +0 -0
- package/src/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
- package/src/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
- package/src/document/components/DocCoverPage.tsx +0 -45
- package/src/document/components/DocPage.tsx +0 -40
- package/src/document/components/DocRail.tsx +0 -189
- package/src/document/components/DocSectionPage.tsx +0 -48
- package/src/document/components/DocViewer.tsx +0 -313
- package/src/document/components/Wordmark.tsx +0 -18
- package/src/document/components/measure.tsx +0 -133
- package/src/document/components/useDocPages.ts +0 -95
- package/src/document/engine/blocks.ts +0 -116
- package/src/document/engine/harvest.ts +0 -95
- package/src/document/engine/masonry.ts +0 -158
- package/src/document/engine/paginate.ts +0 -232
- package/src/document/engine/settings.ts +0 -125
- package/src/document/engine/types.ts +0 -64
- package/src/document/index.ts +0 -18
- package/src/document/styles/document.css +0 -217
- package/src/lib/deck-access.ts +0 -132
- package/src/lib/deck-dexie.ts +0 -190
- package/src/lib/deck-edit.ts +0 -196
- package/src/lib/deck-media-assets.ts +0 -57
- package/src/lib/deck-media-refs.ts +0 -67
- package/src/lib/deck-tool.ts +0 -95
- package/src/lib/document-input.ts +0 -57
- package/src/schemas/deck-meta.ts +0 -88
- package/src/schemas/deck.ts +0 -478
- package/dist/{chunk-DJABADOO.js → chunk-AJ2QOAZI.js} +3 -3
package/dist/document/index.js
DELETED
|
@@ -1,1030 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
documentOptionsSchema,
|
|
3
|
-
sectionSettingsSchema,
|
|
4
|
-
settingsFor,
|
|
5
|
-
settingsIssuesFor
|
|
6
|
-
} from "../chunk-4TZJZU2T.js";
|
|
7
|
-
import "../chunk-JSBRDJBE.js";
|
|
8
|
-
|
|
9
|
-
// src/document/engine/types.ts
|
|
10
|
-
var PREAMBLE_ID = "__preamble";
|
|
11
|
-
|
|
12
|
-
// src/document/engine/blocks.ts
|
|
13
|
-
var DISALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
14
|
-
"script",
|
|
15
|
-
"style",
|
|
16
|
-
"iframe",
|
|
17
|
-
"object",
|
|
18
|
-
"embed",
|
|
19
|
-
"link",
|
|
20
|
-
"meta",
|
|
21
|
-
"base",
|
|
22
|
-
"form",
|
|
23
|
-
// Raw-text / escapable-raw-text and declarative elements whose contents are
|
|
24
|
-
// not parsed as normal markup. Left in place they enable serialize/reparse
|
|
25
|
-
// (mXSS) bypasses — e.g. an <img onerror> smuggled inside <noscript> text.
|
|
26
|
-
// Removing the element drops its contents too (including <template> content).
|
|
27
|
-
"noscript",
|
|
28
|
-
"xmp",
|
|
29
|
-
"noembed",
|
|
30
|
-
"noframes",
|
|
31
|
-
"plaintext",
|
|
32
|
-
"template"
|
|
33
|
-
]);
|
|
34
|
-
var DISALLOWED_SELECTOR = Array.from(DISALLOWED_TAGS).join(",");
|
|
35
|
-
var URL_ATTRS = /* @__PURE__ */ new Set([
|
|
36
|
-
"href",
|
|
37
|
-
"src",
|
|
38
|
-
"srcset",
|
|
39
|
-
"poster",
|
|
40
|
-
"xlink:href",
|
|
41
|
-
"formaction",
|
|
42
|
-
"action",
|
|
43
|
-
"ping",
|
|
44
|
-
"data",
|
|
45
|
-
"background"
|
|
46
|
-
]);
|
|
47
|
-
function isDangerousUrl(attrName, rawValue) {
|
|
48
|
-
const value = rawValue.toLowerCase().replace(/[\u0000-\u0020]/g, "");
|
|
49
|
-
if (value.startsWith("javascript:") || value.startsWith("vbscript:")) return true;
|
|
50
|
-
if (attrName === "src" && value.startsWith("data:text/html")) return true;
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
function hasDangerousUrl(attrName, rawValue) {
|
|
54
|
-
if (attrName !== "srcset") return isDangerousUrl(attrName, rawValue);
|
|
55
|
-
return rawValue.split(",").some((candidate) => isDangerousUrl("src", candidate.trim().split(/\s+/)[0] ?? ""));
|
|
56
|
-
}
|
|
57
|
-
function scrubElement(root) {
|
|
58
|
-
root.querySelectorAll(DISALLOWED_SELECTOR).forEach((el) => el.remove());
|
|
59
|
-
const elements = [root, ...Array.from(root.querySelectorAll("*"))];
|
|
60
|
-
for (const el of elements) {
|
|
61
|
-
for (const attr of Array.from(el.attributes)) {
|
|
62
|
-
const name = attr.name.toLowerCase();
|
|
63
|
-
if (name.startsWith("on") || name === "srcdoc") {
|
|
64
|
-
el.removeAttribute(attr.name);
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
if (URL_ATTRS.has(name) && hasDangerousUrl(name, attr.value)) {
|
|
68
|
-
el.removeAttribute(attr.name);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
var VISIBLE_EMPTY_SELECTOR = "img, hr, video, svg, picture, canvas";
|
|
74
|
-
function splitProseBlocks(html) {
|
|
75
|
-
if (!html.trim()) return [];
|
|
76
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
77
|
-
const blocks = [];
|
|
78
|
-
for (const node of Array.from(doc.body.childNodes)) {
|
|
79
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
80
|
-
const el = node;
|
|
81
|
-
if (DISALLOWED_TAGS.has(el.tagName.toLowerCase())) continue;
|
|
82
|
-
scrubElement(el);
|
|
83
|
-
if ((el.textContent ?? "").trim() || el.matches(VISIBLE_EMPTY_SELECTOR) || el.querySelector(VISIBLE_EMPTY_SELECTOR)) {
|
|
84
|
-
blocks.push(el.outerHTML);
|
|
85
|
-
}
|
|
86
|
-
} else if (node.nodeType === Node.TEXT_NODE) {
|
|
87
|
-
const text = (node.textContent ?? "").trim();
|
|
88
|
-
if (text) {
|
|
89
|
-
const p = doc.createElement("p");
|
|
90
|
-
p.textContent = text;
|
|
91
|
-
blocks.push(p.outerHTML);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return blocks;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// src/document/engine/harvest.ts
|
|
99
|
-
function str(v) {
|
|
100
|
-
return typeof v === "string" ? v : "";
|
|
101
|
-
}
|
|
102
|
-
function asRecord(v) {
|
|
103
|
-
return v && typeof v === "object" ? v : {};
|
|
104
|
-
}
|
|
105
|
-
function harvestInto(target, type, content, imagesById) {
|
|
106
|
-
const c = asRecord(content);
|
|
107
|
-
switch (type) {
|
|
108
|
-
case "sub_heading":
|
|
109
|
-
case "link_heading":
|
|
110
|
-
target.textBlocks.push({ kind: "heading", level: 2, text: str(c.heading) });
|
|
111
|
-
break;
|
|
112
|
-
case "sub_sub_heading":
|
|
113
|
-
target.textBlocks.push({ kind: "heading", level: 3, text: str(c.heading) });
|
|
114
|
-
break;
|
|
115
|
-
case "prose":
|
|
116
|
-
for (const html of splitProseBlocks(str(c.body))) {
|
|
117
|
-
target.textBlocks.push({ kind: "prose", html });
|
|
118
|
-
}
|
|
119
|
-
break;
|
|
120
|
-
case "media": {
|
|
121
|
-
const ref = asRecord(c.ref);
|
|
122
|
-
const image = imagesById[str(ref.imageId)];
|
|
123
|
-
if (image) target.images.push(image);
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
case "container": {
|
|
127
|
-
const children = Array.isArray(c.children) ? c.children : [];
|
|
128
|
-
for (const child of children) {
|
|
129
|
-
const cc = asRecord(child);
|
|
130
|
-
if (typeof cc.type === "string") {
|
|
131
|
-
harvestInto(target, cc.type, cc.content, imagesById);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
default:
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function harvest(sections, pageTitle, imagesById, splitAtFor = () => "none") {
|
|
141
|
-
const chunks = [];
|
|
142
|
-
const preamble = { id: PREAMBLE_ID, title: pageTitle, textBlocks: [], images: [] };
|
|
143
|
-
let parent = preamble;
|
|
144
|
-
let current = preamble;
|
|
145
|
-
let splitAt = splitAtFor(PREAMBLE_ID);
|
|
146
|
-
for (const section of sections) {
|
|
147
|
-
const heading = str(asRecord(section.content).heading);
|
|
148
|
-
if (section.type === "link_heading") {
|
|
149
|
-
parent = { id: section.id, title: heading, textBlocks: [], images: [] };
|
|
150
|
-
current = parent;
|
|
151
|
-
splitAt = splitAtFor(section.id);
|
|
152
|
-
chunks.push(parent);
|
|
153
|
-
} else if (section.type === "sub_heading" && splitAt === "sub_heading") {
|
|
154
|
-
current = { id: section.id, title: heading, textBlocks: [], images: [], parentId: parent.id, kicker: parent.title, depth: 1 };
|
|
155
|
-
chunks.push(current);
|
|
156
|
-
} else {
|
|
157
|
-
harvestInto(current, section.type, section.content, imagesById);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
const keepPreamble = preamble.textBlocks.length > 0 || preamble.images.length > 0 || chunks.some((c) => c.parentId === PREAMBLE_ID);
|
|
161
|
-
return keepPreamble ? [preamble, ...chunks] : chunks;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/document/engine/masonry.ts
|
|
165
|
-
var EPS = 1e-6;
|
|
166
|
-
var effectiveAspect = (im, fit) => {
|
|
167
|
-
if (fit === "cover") return 1;
|
|
168
|
-
const aspect = im.width / im.height;
|
|
169
|
-
return Number.isFinite(aspect) && aspect > 0 ? aspect : 1;
|
|
170
|
-
};
|
|
171
|
-
function layoutRows(images, o, fits) {
|
|
172
|
-
const asp = images.map((im, i2) => effectiveAspect(im, fits[i2]));
|
|
173
|
-
const boxes = [];
|
|
174
|
-
let y = 0, i = 0;
|
|
175
|
-
let used = null;
|
|
176
|
-
while (i < images.length) {
|
|
177
|
-
const row = [];
|
|
178
|
-
let natW = 0;
|
|
179
|
-
while (i + row.length < images.length) {
|
|
180
|
-
row.push(i + row.length);
|
|
181
|
-
const gaps2 = o.gapIn * (row.length - 1);
|
|
182
|
-
natW = row.reduce((s, idx) => s + asp[idx] * o.targetRowHeightIn, 0) + gaps2;
|
|
183
|
-
if (natW >= o.bodyWIn) break;
|
|
184
|
-
}
|
|
185
|
-
const gaps = o.gapIn * (row.length - 1);
|
|
186
|
-
const sumAspect = row.reduce((s, idx) => s + asp[idx], 0);
|
|
187
|
-
const isFull = natW >= o.bodyWIn;
|
|
188
|
-
const rowH = isFull ? (o.bodyWIn - gaps) / sumAspect : o.targetRowHeightIn;
|
|
189
|
-
if (used === null && y + rowH > o.bodyHIn + EPS && boxes.length > 0) used = boxes.length;
|
|
190
|
-
let x = 0;
|
|
191
|
-
for (const idx of row) {
|
|
192
|
-
const w = asp[idx] * rowH;
|
|
193
|
-
boxes.push({ asset: images[idx], xIn: x, yIn: y, wIn: w, hIn: rowH });
|
|
194
|
-
x += w + o.gapIn;
|
|
195
|
-
}
|
|
196
|
-
y += rowH + o.gapIn;
|
|
197
|
-
i += row.length;
|
|
198
|
-
}
|
|
199
|
-
return { boxes, used: used ?? images.length, endY: y };
|
|
200
|
-
}
|
|
201
|
-
function layoutForcedRows(images, o, fits, n) {
|
|
202
|
-
const asp = images.map((im, i2) => effectiveAspect(im, fits[i2]));
|
|
203
|
-
const count = Math.min(n, images.length);
|
|
204
|
-
const rows = [];
|
|
205
|
-
let i = 0;
|
|
206
|
-
for (let r = 0; r < count; r++) {
|
|
207
|
-
const remainingRows = count - r;
|
|
208
|
-
const target = asp.slice(i).reduce((s, a) => s + a, 0) / remainingRows;
|
|
209
|
-
const row = [];
|
|
210
|
-
let sum = 0;
|
|
211
|
-
while (i < asp.length) {
|
|
212
|
-
if (row.length > 0) {
|
|
213
|
-
if (asp.length - (i + 1) < remainingRows - 1) break;
|
|
214
|
-
if (sum >= target - EPS) break;
|
|
215
|
-
}
|
|
216
|
-
row.push(i);
|
|
217
|
-
sum += asp[i];
|
|
218
|
-
i++;
|
|
219
|
-
}
|
|
220
|
-
rows.push(row);
|
|
221
|
-
}
|
|
222
|
-
const rowMeta = rows.map((row) => {
|
|
223
|
-
const gaps = o.gapIn * (row.length - 1);
|
|
224
|
-
const sumAspect = row.reduce((s, a) => s + asp[a], 0);
|
|
225
|
-
return { row, gaps, sumAspect, hIn: (o.bodyWIn - gaps) / sumAspect };
|
|
226
|
-
});
|
|
227
|
-
const rowGaps = o.gapIn * (rowMeta.length - 1);
|
|
228
|
-
const totalH = rowMeta.reduce((s, m) => s + m.hIn, 0);
|
|
229
|
-
const scale = totalH > 0 ? Math.min(1, Math.max(0, o.bodyHIn - rowGaps) / totalH) : 1;
|
|
230
|
-
const boxes = [];
|
|
231
|
-
let y = 0;
|
|
232
|
-
for (const m of rowMeta) {
|
|
233
|
-
const rowH = m.hIn * scale;
|
|
234
|
-
let x = 0;
|
|
235
|
-
for (const idx of m.row) {
|
|
236
|
-
const w = asp[idx] * rowH;
|
|
237
|
-
boxes.push({ asset: images[idx], xIn: x, yIn: y, wIn: w, hIn: rowH });
|
|
238
|
-
x += w + o.gapIn;
|
|
239
|
-
}
|
|
240
|
-
y += rowH + o.gapIn;
|
|
241
|
-
}
|
|
242
|
-
return { boxes, used: images.length, endY: y };
|
|
243
|
-
}
|
|
244
|
-
function layoutColumns(images, o, fits) {
|
|
245
|
-
const n = o.columns;
|
|
246
|
-
const colW = (o.bodyWIn - o.gapIn * (n - 1)) / n;
|
|
247
|
-
const colH = new Array(n).fill(0);
|
|
248
|
-
const boxes = [];
|
|
249
|
-
let used = null;
|
|
250
|
-
images.forEach((im, idx) => {
|
|
251
|
-
let c = 0;
|
|
252
|
-
for (let k = 1; k < n; k++) if (colH[k] < colH[c]) c = k;
|
|
253
|
-
const y = colH[c];
|
|
254
|
-
const h = colW / effectiveAspect(im, fits[idx]);
|
|
255
|
-
if (used === null && y + h > o.bodyHIn + EPS && idx > 0) used = idx;
|
|
256
|
-
boxes.push({ asset: im, xIn: c * (colW + o.gapIn), yIn: y, wIn: colW, hIn: h });
|
|
257
|
-
colH[c] = y + h + o.gapIn;
|
|
258
|
-
});
|
|
259
|
-
return { boxes, used: used ?? images.length, colHeights: colH, colW };
|
|
260
|
-
}
|
|
261
|
-
function layoutMasonryPage(images, o, fits = []) {
|
|
262
|
-
if (o.mode === "columns") {
|
|
263
|
-
const r2 = layoutColumns(images, o, fits);
|
|
264
|
-
return { boxes: r2.boxes, used: r2.used };
|
|
265
|
-
}
|
|
266
|
-
const r = typeof o.rows === "number" ? layoutForcedRows(images, o, fits, o.rows) : layoutRows(images, o, fits);
|
|
267
|
-
return { boxes: r.boxes, used: r.used };
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// src/document/engine/paginate.ts
|
|
271
|
-
var DOC_GEOM = {
|
|
272
|
-
bodyWIn: 15.8,
|
|
273
|
-
bodyHIn: 9.05,
|
|
274
|
-
titleBandIn: 0.9,
|
|
275
|
-
gapIn: 0.15,
|
|
276
|
-
leftColWIn: 4.6,
|
|
277
|
-
colGutterIn: 0.4,
|
|
278
|
-
minTextColIn: 1,
|
|
279
|
-
minImageRegionIn: 1.2,
|
|
280
|
-
masonryTargetRowIn: 2.6,
|
|
281
|
-
// Top text fills at most this fraction of the body height below the title
|
|
282
|
-
// band, so a text-heavy top section always leaves ≥ half the page for images.
|
|
283
|
-
topTextMaxFraction: 0.5
|
|
284
|
-
};
|
|
285
|
-
var EPS2 = 1e-6;
|
|
286
|
-
function fitImages(images, layout, region, geom) {
|
|
287
|
-
if (images.length === 0 || region.hIn < geom.minImageRegionIn) return { boxes: [], used: 0 };
|
|
288
|
-
if (layout.mode === "grid") {
|
|
289
|
-
const used = Math.min(layout.rows * layout.columns, images.length);
|
|
290
|
-
const cellW = (region.wIn - (layout.columns - 1) * geom.gapIn) / layout.columns;
|
|
291
|
-
const cellH = (region.hIn - (layout.rows - 1) * geom.gapIn) / layout.rows;
|
|
292
|
-
const boxes2 = images.slice(0, used).map((image, i) => {
|
|
293
|
-
const r2 = Math.floor(i / layout.columns);
|
|
294
|
-
const c = i % layout.columns;
|
|
295
|
-
return {
|
|
296
|
-
image,
|
|
297
|
-
xIn: region.xIn + c * (cellW + geom.gapIn),
|
|
298
|
-
yIn: region.yIn + r2 * (cellH + geom.gapIn),
|
|
299
|
-
wIn: cellW,
|
|
300
|
-
hIn: cellH,
|
|
301
|
-
fit: layout.fit
|
|
302
|
-
};
|
|
303
|
-
});
|
|
304
|
-
return { boxes: boxes2, used };
|
|
305
|
-
}
|
|
306
|
-
const r = layoutMasonryPage(images, {
|
|
307
|
-
mode: layout.flow,
|
|
308
|
-
columns: layout.columns,
|
|
309
|
-
rows: layout.rows,
|
|
310
|
-
bodyWIn: region.wIn,
|
|
311
|
-
bodyHIn: region.hIn,
|
|
312
|
-
gapIn: geom.gapIn,
|
|
313
|
-
targetRowHeightIn: geom.masonryTargetRowIn
|
|
314
|
-
});
|
|
315
|
-
const boxes = r.boxes.slice(0, r.used).map((b) => ({
|
|
316
|
-
image: b.asset,
|
|
317
|
-
xIn: region.xIn + b.xIn,
|
|
318
|
-
yIn: region.yIn + b.yIn,
|
|
319
|
-
wIn: b.wIn,
|
|
320
|
-
hIn: b.hIn,
|
|
321
|
-
fit: "contain"
|
|
322
|
-
}));
|
|
323
|
-
return { boxes, used: r.used };
|
|
324
|
-
}
|
|
325
|
-
function paginateChunk(chunk, settings, textHeightsIn, geom = DOC_GEOM, naturalTextWIn) {
|
|
326
|
-
if (settings.excluded) return [];
|
|
327
|
-
if (chunk.textBlocks.length !== textHeightsIn.length) {
|
|
328
|
-
throw new Error("paginateChunk: textHeightsIn must match chunk.textBlocks");
|
|
329
|
-
}
|
|
330
|
-
if (chunk.textBlocks.length === 0 && chunk.images.length === 0) return [];
|
|
331
|
-
const colWIn = naturalTextWIn === void 0 ? geom.leftColWIn : Math.min(geom.leftColWIn, Math.max(geom.minTextColIn, naturalTextWIn + 0.05));
|
|
332
|
-
const pages = [];
|
|
333
|
-
let ti = 0;
|
|
334
|
-
let ii = 0;
|
|
335
|
-
const top = geom.titleBandIn;
|
|
336
|
-
while (ti < chunk.textBlocks.length || ii < chunk.images.length) {
|
|
337
|
-
const cont = pages.length > 0;
|
|
338
|
-
const warnings = [];
|
|
339
|
-
const textW = settings.textPlacement === "top" ? geom.bodyWIn : colWIn;
|
|
340
|
-
const capY = settings.textPlacement === "top" && ii < chunk.images.length ? geom.titleBandIn + (geom.bodyHIn - geom.titleBandIn) * geom.topTextMaxFraction : geom.bodyHIn;
|
|
341
|
-
const placed = [];
|
|
342
|
-
let textEnd = top;
|
|
343
|
-
while (ti < chunk.textBlocks.length) {
|
|
344
|
-
const h = textHeightsIn[ti];
|
|
345
|
-
const yAfter = placed.length === 0 ? top + h : textEnd + geom.gapIn + h;
|
|
346
|
-
if (yAfter <= capY + EPS2) {
|
|
347
|
-
placed.push(chunk.textBlocks[ti]);
|
|
348
|
-
textEnd = yAfter;
|
|
349
|
-
ti++;
|
|
350
|
-
} else if (placed.length === 0) {
|
|
351
|
-
placed.push(chunk.textBlocks[ti]);
|
|
352
|
-
textEnd = capY;
|
|
353
|
-
ti++;
|
|
354
|
-
warnings.push("A text block is taller than the page and was clipped.");
|
|
355
|
-
break;
|
|
356
|
-
} else {
|
|
357
|
-
break;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
if (!cont && settings.dropTextOverflow && ti < chunk.textBlocks.length) {
|
|
361
|
-
const dropped = chunk.textBlocks.length - ti;
|
|
362
|
-
ti = chunk.textBlocks.length;
|
|
363
|
-
warnings.push(`${dropped} text block(s) hidden (overflow dropped)`);
|
|
364
|
-
}
|
|
365
|
-
const textRegion = placed.length > 0 ? { xIn: 0, yIn: top, wIn: textW, hIn: textEnd - top } : null;
|
|
366
|
-
let region;
|
|
367
|
-
if (settings.textPlacement === "leftColumn" && settings.imagePlacement === "right" && placed.length > 0) {
|
|
368
|
-
region = {
|
|
369
|
-
xIn: colWIn + geom.colGutterIn,
|
|
370
|
-
yIn: top,
|
|
371
|
-
wIn: geom.bodyWIn - colWIn - geom.colGutterIn,
|
|
372
|
-
hIn: geom.bodyHIn - top
|
|
373
|
-
};
|
|
374
|
-
} else {
|
|
375
|
-
const startY = placed.length > 0 ? textEnd + geom.gapIn : top;
|
|
376
|
-
region = { xIn: 0, yIn: startY, wIn: geom.bodyWIn, hIn: Math.max(0, geom.bodyHIn - startY) };
|
|
377
|
-
}
|
|
378
|
-
const { boxes, used } = fitImages(chunk.images.slice(ii), settings.imageLayout, region, geom);
|
|
379
|
-
ii += used;
|
|
380
|
-
if (boxes.some((b) => b.yIn + b.hIn > region.yIn + region.hIn + 0.01)) {
|
|
381
|
-
warnings.push("An image overflows the page and is clipped.");
|
|
382
|
-
}
|
|
383
|
-
if (placed.length === 0 && used === 0) {
|
|
384
|
-
warnings.push("Pagination could not place remaining content.");
|
|
385
|
-
pages.push({
|
|
386
|
-
id: `${chunk.id}#${pages.length}`,
|
|
387
|
-
chunkId: chunk.id,
|
|
388
|
-
title: cont ? `${chunk.title} Cont.` : chunk.title,
|
|
389
|
-
cont,
|
|
390
|
-
kicker: chunk.kicker,
|
|
391
|
-
depth: chunk.depth,
|
|
392
|
-
textBlocks: placed,
|
|
393
|
-
textRegion,
|
|
394
|
-
imageBoxes: boxes,
|
|
395
|
-
warnings
|
|
396
|
-
});
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
pages.push({
|
|
400
|
-
id: `${chunk.id}#${pages.length}`,
|
|
401
|
-
chunkId: chunk.id,
|
|
402
|
-
title: cont ? `${chunk.title} Cont.` : chunk.title,
|
|
403
|
-
cont,
|
|
404
|
-
kicker: chunk.kicker,
|
|
405
|
-
depth: chunk.depth,
|
|
406
|
-
textBlocks: placed,
|
|
407
|
-
textRegion,
|
|
408
|
-
imageBoxes: boxes,
|
|
409
|
-
warnings
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
return pages;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// src/document/components/Wordmark.tsx
|
|
416
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
417
|
-
function Wordmark({ className }) {
|
|
418
|
-
return /* @__PURE__ */ jsxs(
|
|
419
|
-
"svg",
|
|
420
|
-
{
|
|
421
|
-
viewBox: "0 0 360 154.474",
|
|
422
|
-
fill: "currentColor",
|
|
423
|
-
role: "img",
|
|
424
|
-
"aria-label": "Drawn",
|
|
425
|
-
className,
|
|
426
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
427
|
-
children: [
|
|
428
|
-
/* @__PURE__ */ jsx("path", { d: "M93.211 18.436c-2.177.868 2.024 1.375 6.374 5.14 3.913 3.392 5.542 6.526 8.126 5.794l.084-.019c15.002-4.018 30.605-4.343 45.642-3.985 37.577.895 76.5 13.868 127.052 10.736 52.074-3.226 64.063-33.293 64.423-35.34.335-1.903-4.473.223-6.71 1.341-2.461 1.23-12.375 22.056-56.817 24.605-54.58 3.13-76.949-13.42-127.948-16.105-24.157-1.272-44.308 1.912-60.225 7.832ZM353.301 104.05c-3.497-.813-8.22-.393-14.355 3.083a42.817 42.817 0 0 0-1.464.863l-.646.396c-.153.094-.302.192-.452.286-.185.121-.375.239-.56.36-.158.1-.315.202-.47.305-.18.119-.36.234-.539.354-.177.118-.353.235-.53.35l-.557.373c-.113.076-.23.15-.344.225-2.209 1.475-4.596 3.046-7.903 4.822l-.002-.001c-.178.093-.354.189-.534.285-.25.132-.504.264-.764.398-.28.145-.574.292-.87.442-.268.133-.537.269-.817.403-.32.16-.653.319-.988.477-.282.136-.561.27-.857.407a124.187 124.187 0 0 1-4.258 1.882c-22.372 9.426-46.637 12.894-83.75 9.349-37.286-3.562-76.22-13.87-126.593-10.74-51.887 3.228-63.837 33.296-64.195 35.346-.336 1.898 4.455-.225 6.685-1.345 2.45-1.228 12.332-22.055 56.612-24.603 54.385-3.132 84.076 13.469 131.52 17.447 34.494 2.89 59.914-3.453 77.117-14.422 3.42-2.183 6.945-4.758 10.342-7.353.093-.067.176-.134.264-.202.111-.085.217-.168.329-.25.563-.434 1.122-.87 1.68-1.302.098-.077.2-.152.3-.23 1.027-.8 2.038-1.593 3.021-2.37 2.518-1.98 4.866-3.835 6.939-5.395l.823-.614.382-.28c.344-.251.675-.49.999-.718a42.728 42.728 0 0 1 1.547-1.058c.07-.047.14-.084.206-.13.31-.197.608-.379.89-.544.094-.054.189-.11.281-.16a12.3 12.3 0 0 1 .933-.486c4.427-2.017 8.968-2.27 9.22 1.837.124 2.074-1.999 4.029-5.691 4.449-2.565.292-6.454.442-9.699-.803-.026-.012-.048-.012-.077-.023-.5-.17-1.841 1.036-2.762 2-.922.966-2.05 1.673-1.084 2.163 4.29 2.29 8.832 3.056 11.611 3.137 8.07.221 14.336-1.887 15.567-8.04.93-4.653-1.559-9.227-6.507-10.371Z" }),
|
|
429
|
-
/* @__PURE__ */ jsx("path", { d: "M340.048 55.675c-3.094-2.81-8.125-2.34-11.568-2.069-5.92.466-11.54 3.713-15.45 6.582-.477-3.394-1.684-5.828-3.908-6.64-6.393-2.34-11.45 2.035-16.42 5.387-1.95 1.254-4.322-4.012-5.878-4.895-1.55-.882-4.995-1.347-7.803.126-4.404 2.305-7.465 5.91-7.21 8.136.257 2.297 4.149 4.28 4.065 6.879-.13 4.019-2.04 7.87-4.668 13.225-1.998 4.068-4.108 7.762-6.38 10.711-1.537 1.954-3.631 4.144-6.278 5.748-.514.277-1.04.496-1.57.685-3.299.82-4.712-3.26-3.843-8.882 1.006-6.444 9.235-29.756 9.738-30.966.502-1.21-.382-1.121-2.396-1.49-2.015-.37-6.724-.041-8.45.241-1.727.279-5.21 15.477-7.354 22.253-2.143 6.778-5.96 14.898-8.942 17.284-2.568 2.058-4.896 3.11-7.137 2.31-6.262-2.243-2.25-19.315 1.117-28.63 3.801-10.515 9.353-20.009 6.934-19.91-5.368.224-11.976 2.01-13.28 4.058-2.33 3.673-8.074 21.308-9.999 26.677-1.072 2.989-1.506 6.316-1.412 9.579-1.124.544-6.17 6.036-12.888 5.767-7.49-.303 4.697-29.98 5.369-31.32.67-1.342-11.354-1.567-12.026-.222-.668 1.34-6.037 31.487-20.409 31.487-10.457 0-5.145-25.45 7.604-34.614 10.985-7.9 25.36-2.188 26.924-2.862 1.565-.668 4.17-9.668 4.17-10.786s-4.698-1.119-18.792-.222c-14.09.893-21.92 7.38-30.195 20.69-8.278 13.31-10.068 26.73-19.412 26.73-9.22 0-1.169-18.788 3.082-27.738 4.248-8.946 6.937-17.895 5.592-19.907-1.343-2.014-16.332-.46-17.673-1.58-1.344-1.119 1.121-3.12.45-4.913-.67-1.787-10.515-1.787-14.205 0-1.887.916-2.185 3.287-2.021 5.893 1.254 7.163 1.232 14.979-.318 22.603.064.302.197.384.438.138 2.586-2.63 8.876-11.227 9.55-12.12.669-.897 8.836-.71 9.239.043.645 1.203-6.796 17.224-8.723 22.59-3.61 10.057-2.573 16.894 2.973 20.234 4.967 2.996 9.777 2.584 16.73-1.624 6.977-4.222 9.599-6.526 9.599-6.526s0 14.087 15.437 14.087c11.406 0 14.089-8.048 14.089-8.048s1.797 10.698 12.414 9.087c6.176-.937 11.652-9.47 13.41-12.763 1.045 6.066 3.97 11.25 8.174 12.625 5.887 1.922 13.06.388 19.818-4.645a15.195 15.195 0 0 0 2.495-2.362c2.356 5.703 5.865 9.538 9.681 10.008 19.478 2.399 28.458-19.807 33.299-34.217.993-2.955 1.71-5.846 2.654-9.364.268-1.007 1.183-2.504 2.994-2.939 4.188-.933 7.848-1.282 8.583.371 3.784 8.503-13.171 43.36-10.747 43.36 3.3 0 10.047-1.037 12.48-4.353 4.145-5.64 10.948-25.812 11.45-39.149 2.636-2.101 5.458-3.664 8.179-3.883 9.395-.757 6.167 14.162 3.22 22.537-4.906 13.966-3.351 22.982.632 28.735.709.9 1.775-.014 3.49-.917 1.718-.906 2.7-1.413 2.527-2.26-.011-.062-.019-.12-.029-.183-1.323-5.592 3.407-13.519 7.318-24.085 3.762-10.158 7.001-24.749 1.465-29.782ZM46.09 89.63c1.282-2.736 2.616-5.56 4.002-8.468C56.528 67.684 66.09 53.946 75.049 46.32a80.636 80.636 0 0 1 14.747-9.98c.07-.044.148-.092.221-.132 1.173-.631 1.17-1.394-.013-3.301-1.354-2.185-3.87-4.955-8.296-7.144-1.703-.842-3.224-.362-4.618.396-4.817 2.932-9.012 6.161-12.569 9.6C46.448 53.23 37.23 76.32 33.231 88.318l-1.407 4.22c-.406 1.22-.8 2.397-1.185 3.546l-.149.437c-.38 1.13-.748 2.214-1.11 3.27-.008.02-.014.043-.022.061-.993 2.89-1.932 5.525-2.846 7.885h-.01c-.22.568-.44 1.153-.66 1.689l-.006.015a79.329 79.329 0 0 1-1.105 2.609 51.44 51.44 0 0 1-1.022 2.16l-.106.22c-2.926 5.805-5.963 8.77-10.193 8.77-8.5 0-6.377-11.156 6.71-15.516a18.611 18.611 0 0 1 3.791-.83c.064-.01.118-.024.188-.035 1.761-.268 1.54-1.49 2.059-3.246.376-1.273 1.282-2.543-.193-2.404a57.899 57.899 0 0 0-6.293 1.147c-23.152 5.477-24.366 25.123-11.446 28.413 9.656 2.457 17.26-3.099 23.006-11.475.24-.356.493-.743.75-1.154.084-.132.173-.28.26-.42.177-.29.354-.584.54-.901.102-.175.208-.362.313-.545.176-.305.355-.623.537-.95.11-.198.22-.393.33-.598.198-.364.4-.74.604-1.122.098-.188.197-.368.294-.557.304-.578.614-1.173.93-1.796.028-.052.055-.112.083-.164l.337-.668c1.406-2.791 2.94-5.988 4.603-9.504 1.64-3.475 3.4-7.248 5.277-11.245Z" }),
|
|
430
|
-
/* @__PURE__ */ jsx("path", { d: "M79.206 111.375c35.531-11.52 39.87-52.054 28.828-74.15a34.694 34.694 0 0 0-2.573-4.302c-4.379-6.306-10.605-10.865-17.802-14.027-5.346-2.35-11.22-3.94-17.254-4.914C43.94 9.708 6.14 18.749 5.74 39.95 5.354 60.374 30.548 57.9 32.533 58.025c2.247.14 1.678-1.678-.67-4.028-2.35-2.347-7.946-7.147-7.382-15.433.844-12.415 17.78-22.482 44.612-18.03 3.758.625 6.956 1.438 9.75 2.425 8.204 2.907 12.703 7.418 16.072 13.73a55.714 55.714 0 0 1 2.154 4.559c8.11 19.313-4.926 52.567-24.438 59.737-14.466 5.317-21.625 3.08-29.713 1.281-1.304-.287-1.495 1.185-2.543 3.446-1.047 2.264-2.092 3.906-1.052 4.293 9.395 3.44 20.77 7.563 39.883 1.37Z" })
|
|
431
|
-
]
|
|
432
|
-
}
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// src/document/components/DocPage.tsx
|
|
437
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
438
|
-
function DocPage({
|
|
439
|
-
meta,
|
|
440
|
-
bleed = false,
|
|
441
|
-
chrome = true,
|
|
442
|
-
children
|
|
443
|
-
}) {
|
|
444
|
-
const crumb = [meta.client, meta.project, meta.dateLabel].map((s) => s.trim().toUpperCase()).filter(Boolean).join(" :: ");
|
|
445
|
-
return /* @__PURE__ */ jsxs2("section", { className: "deck-page", children: [
|
|
446
|
-
bleed ? /* @__PURE__ */ jsx2("div", { className: "deck-bleed", children }) : null,
|
|
447
|
-
chrome ? /* @__PURE__ */ jsxs2("header", { className: "deck-chrome", children: [
|
|
448
|
-
/* @__PURE__ */ jsx2("span", { className: "deck-crumb", children: crumb }),
|
|
449
|
-
/* @__PURE__ */ jsx2("div", { className: "deck-wordmark-clip", children: /* @__PURE__ */ jsx2(Wordmark, { className: "deck-wordmark" }) })
|
|
450
|
-
] }) : null,
|
|
451
|
-
!bleed ? /* @__PURE__ */ jsx2("div", { className: "deck-body", children }) : null
|
|
452
|
-
] });
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// src/document/components/DocSectionPage.tsx
|
|
456
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
457
|
-
var inch = (v) => `${v}in`;
|
|
458
|
-
function DocSectionPage({ page, meta, host }) {
|
|
459
|
-
return /* @__PURE__ */ jsxs3(DocPage, { meta, children: [
|
|
460
|
-
/* @__PURE__ */ jsxs3("h2", { className: "pdoc-title", children: [
|
|
461
|
-
page.kicker ? /* @__PURE__ */ jsx3("span", { className: "pdoc-kicker", "aria-hidden": "true", children: page.kicker }) : null,
|
|
462
|
-
page.title
|
|
463
|
-
] }),
|
|
464
|
-
page.textRegion ? /* @__PURE__ */ jsx3(
|
|
465
|
-
"div",
|
|
466
|
-
{
|
|
467
|
-
className: "pdoc-text",
|
|
468
|
-
style: { left: inch(page.textRegion.xIn), top: inch(page.textRegion.yIn), width: inch(page.textRegion.wIn) },
|
|
469
|
-
children: page.textBlocks.map((b, i) => {
|
|
470
|
-
const spacing = i > 0 ? { marginTop: inch(0.15) } : void 0;
|
|
471
|
-
if (b.kind === "heading") {
|
|
472
|
-
return b.level === 2 ? /* @__PURE__ */ jsx3("h3", { className: "pdoc-h2", style: spacing, children: b.text }, i) : /* @__PURE__ */ jsx3("h4", { className: "pdoc-h3", style: spacing, children: b.text }, i);
|
|
473
|
-
}
|
|
474
|
-
return /* @__PURE__ */ jsx3("div", { className: "pdoc-prose", style: spacing, dangerouslySetInnerHTML: { __html: b.html } }, i);
|
|
475
|
-
})
|
|
476
|
-
}
|
|
477
|
-
) : null,
|
|
478
|
-
page.imageBoxes.map((box, i) => /* @__PURE__ */ jsx3(
|
|
479
|
-
"div",
|
|
480
|
-
{
|
|
481
|
-
className: "pdoc-img",
|
|
482
|
-
style: { left: inch(box.xIn), top: inch(box.yIn), width: inch(box.wIn), height: inch(box.hIn) },
|
|
483
|
-
children: /* @__PURE__ */ jsx3("img", { src: host.imageSrc(box.image, host.variant), alt: box.image.alt, style: { objectFit: box.fit } })
|
|
484
|
-
},
|
|
485
|
-
`${box.image.imageId}-${i}`
|
|
486
|
-
))
|
|
487
|
-
] });
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// src/document/components/DocCoverPage.tsx
|
|
491
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
492
|
-
function DocCoverPage({
|
|
493
|
-
cover,
|
|
494
|
-
meta,
|
|
495
|
-
image,
|
|
496
|
-
host
|
|
497
|
-
}) {
|
|
498
|
-
return /* @__PURE__ */ jsx4(DocPage, { meta, bleed: true, chrome: false, children: /* @__PURE__ */ jsxs4("div", { className: "layout-titlecard", style: { background: cover.bgColor }, children: [
|
|
499
|
-
/* @__PURE__ */ jsxs4("header", { className: "layout-titlecard__masthead", children: [
|
|
500
|
-
/* @__PURE__ */ jsx4(Wordmark, { className: "layout-titlecard__wordmark" }),
|
|
501
|
-
/* @__PURE__ */ jsx4("span", { className: "layout-titlecard__rule" })
|
|
502
|
-
] }),
|
|
503
|
-
image && host ? /* @__PURE__ */ jsx4("div", { className: "layout-titlecard__image", children: /* @__PURE__ */ jsx4("img", { src: host.imageSrc(image, host.variant), alt: image.alt }) }) : null,
|
|
504
|
-
/* @__PURE__ */ jsxs4("div", { className: "layout-titlecard__lockup", style: { color: cover.accentColor }, children: [
|
|
505
|
-
/* @__PURE__ */ jsx4("h1", { className: "layout-titlecard__title", children: cover.title }),
|
|
506
|
-
/* @__PURE__ */ jsx4("span", { className: "layout-titlecard__titlerule", style: { background: cover.accentColor } }),
|
|
507
|
-
/* @__PURE__ */ jsx4("p", { className: "layout-titlecard__label", children: cover.label }),
|
|
508
|
-
/* @__PURE__ */ jsx4("p", { className: "layout-titlecard__date", children: cover.date || meta.dateLabel })
|
|
509
|
-
] })
|
|
510
|
-
] }) });
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// src/document/components/useDocPages.ts
|
|
514
|
-
import { useMemo as useMemo2 } from "react";
|
|
515
|
-
|
|
516
|
-
// src/document/components/measure.tsx
|
|
517
|
-
import { useEffect, useLayoutEffect, useMemo, useState } from "react";
|
|
518
|
-
var PX_PER_IN = 96;
|
|
519
|
-
function widthInFor(settings) {
|
|
520
|
-
return settings?.textPlacement === "leftColumn" ? DOC_GEOM.leftColWIn : DOC_GEOM.bodyWIn;
|
|
521
|
-
}
|
|
522
|
-
function blockClassName(block) {
|
|
523
|
-
if (block.kind === "heading") return block.level === 2 ? "pdoc-h2" : "pdoc-h3";
|
|
524
|
-
return "pdoc-prose";
|
|
525
|
-
}
|
|
526
|
-
function signatureFor(chunks, settingsMap) {
|
|
527
|
-
return JSON.stringify(
|
|
528
|
-
chunks.map((c) => [
|
|
529
|
-
c.id,
|
|
530
|
-
widthInFor(settingsMap[c.id]),
|
|
531
|
-
c.textBlocks.map((b) => b.kind === "heading" ? ["h", b.level, b.text] : ["p", b.html])
|
|
532
|
-
])
|
|
533
|
-
);
|
|
534
|
-
}
|
|
535
|
-
function useTextMeasurements(chunks, settingsMap) {
|
|
536
|
-
const [heights, setHeights] = useState(null);
|
|
537
|
-
const [textWidths, setTextWidths] = useState(null);
|
|
538
|
-
const [fontsReady, setFontsReady] = useState(false);
|
|
539
|
-
useEffect(() => {
|
|
540
|
-
let cancelled = false;
|
|
541
|
-
const markReady = () => {
|
|
542
|
-
if (!cancelled) setFontsReady(true);
|
|
543
|
-
};
|
|
544
|
-
Promise.resolve(document.fonts?.ready).then(markReady).catch(markReady);
|
|
545
|
-
return () => {
|
|
546
|
-
cancelled = true;
|
|
547
|
-
};
|
|
548
|
-
}, []);
|
|
549
|
-
const signature = useMemo(() => signatureFor(chunks, settingsMap), [chunks, settingsMap]);
|
|
550
|
-
useLayoutEffect(() => {
|
|
551
|
-
if (!fontsReady) return;
|
|
552
|
-
const containers = [];
|
|
553
|
-
const next = {};
|
|
554
|
-
const nextW = {};
|
|
555
|
-
const pending = [];
|
|
556
|
-
for (const chunk of chunks) {
|
|
557
|
-
if (chunk.textBlocks.length === 0) {
|
|
558
|
-
next[chunk.id] = [];
|
|
559
|
-
nextW[chunk.id] = 0;
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
|
-
const container = document.createElement("div");
|
|
563
|
-
container.className = "pdoc-measure";
|
|
564
|
-
container.style.width = `${widthInFor(settingsMap[chunk.id])}in`;
|
|
565
|
-
document.body.appendChild(container);
|
|
566
|
-
containers.push(container);
|
|
567
|
-
const wrappers = [];
|
|
568
|
-
for (const block of chunk.textBlocks) {
|
|
569
|
-
const wrapper = document.createElement("div");
|
|
570
|
-
wrapper.className = blockClassName(block);
|
|
571
|
-
if (block.kind === "heading") {
|
|
572
|
-
wrapper.textContent = block.text;
|
|
573
|
-
} else {
|
|
574
|
-
wrapper.innerHTML = block.html;
|
|
575
|
-
}
|
|
576
|
-
wrapper.style.width = "max-content";
|
|
577
|
-
wrapper.style.maxWidth = "100%";
|
|
578
|
-
container.appendChild(wrapper);
|
|
579
|
-
wrappers.push(wrapper);
|
|
580
|
-
}
|
|
581
|
-
pending.push({ chunkId: chunk.id, wrappers });
|
|
582
|
-
}
|
|
583
|
-
for (const { chunkId, wrappers } of pending) {
|
|
584
|
-
const measured = [];
|
|
585
|
-
let wMax = 0;
|
|
586
|
-
for (const wrapper of wrappers) {
|
|
587
|
-
measured.push(wrapper.offsetHeight / PX_PER_IN);
|
|
588
|
-
wMax = Math.max(wMax, wrapper.getBoundingClientRect().width / PX_PER_IN);
|
|
589
|
-
}
|
|
590
|
-
next[chunkId] = measured;
|
|
591
|
-
nextW[chunkId] = wMax;
|
|
592
|
-
}
|
|
593
|
-
setHeights(next);
|
|
594
|
-
setTextWidths(nextW);
|
|
595
|
-
return () => {
|
|
596
|
-
for (const container of containers) container.remove();
|
|
597
|
-
};
|
|
598
|
-
}, [signature, fontsReady]);
|
|
599
|
-
return { heights, textWidths };
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
// src/document/components/useDocPages.ts
|
|
603
|
-
function useDocPages(input) {
|
|
604
|
-
const { source, sections } = input;
|
|
605
|
-
const splitSig = useMemo2(() => {
|
|
606
|
-
const m = {};
|
|
607
|
-
for (const id of Object.keys(sections ?? {})) {
|
|
608
|
-
const v = settingsFor(sections, id).splitAt;
|
|
609
|
-
if (v !== "none") m[id] = v;
|
|
610
|
-
}
|
|
611
|
-
return JSON.stringify(m);
|
|
612
|
-
}, [sections]);
|
|
613
|
-
const splitAtFor = useMemo2(() => {
|
|
614
|
-
const m = JSON.parse(splitSig);
|
|
615
|
-
return (id) => m[id] ?? "none";
|
|
616
|
-
}, [splitSig]);
|
|
617
|
-
const chunks = useMemo2(
|
|
618
|
-
() => source ? harvest(source.sections, source.pageTitle, source.images, splitAtFor) : [],
|
|
619
|
-
[source, splitAtFor]
|
|
620
|
-
);
|
|
621
|
-
const settingsMap = useMemo2(() => {
|
|
622
|
-
const map = {};
|
|
623
|
-
for (const c of chunks) map[c.id] = settingsFor(sections, c.id);
|
|
624
|
-
return map;
|
|
625
|
-
}, [chunks, sections]);
|
|
626
|
-
const { heights, textWidths } = useTextMeasurements(chunks, settingsMap);
|
|
627
|
-
const pages = useMemo2(() => {
|
|
628
|
-
return chunks.flatMap((c) => {
|
|
629
|
-
const h = heights?.[c.id];
|
|
630
|
-
if (c.textBlocks.length > 0 && (!h || h.length !== c.textBlocks.length)) return [];
|
|
631
|
-
return paginateChunk(c, settingsMap[c.id], h ?? [], DOC_GEOM, textWidths?.[c.id]);
|
|
632
|
-
});
|
|
633
|
-
}, [chunks, settingsMap, heights, textWidths]);
|
|
634
|
-
const measuring = useMemo2(
|
|
635
|
-
() => chunks.some((c) => {
|
|
636
|
-
if (c.textBlocks.length === 0) return false;
|
|
637
|
-
const h = heights?.[c.id];
|
|
638
|
-
return !h || h.length !== c.textBlocks.length;
|
|
639
|
-
}),
|
|
640
|
-
[chunks, heights]
|
|
641
|
-
);
|
|
642
|
-
const warningsByChunk = useMemo2(() => {
|
|
643
|
-
const map = {};
|
|
644
|
-
for (const c of chunks) {
|
|
645
|
-
const noContent = c.textBlocks.length === 0 && c.images.length === 0;
|
|
646
|
-
const pageWarnings = pages.filter((p) => p.chunkId === c.id).flatMap((p) => p.warnings);
|
|
647
|
-
const rejected = settingsIssuesFor(sections, c.id);
|
|
648
|
-
const settingWarnings = rejected.length > 0 ? [`Unrecognised value reset to default: ${rejected.join(", ")}`] : [];
|
|
649
|
-
const warnings = noContent ? ["Section has no content", ...settingWarnings, ...pageWarnings] : [...settingWarnings, ...pageWarnings];
|
|
650
|
-
if (warnings.length > 0) map[c.id] = warnings;
|
|
651
|
-
}
|
|
652
|
-
return map;
|
|
653
|
-
}, [chunks, pages, sections]);
|
|
654
|
-
return { chunks, pages, measuring, warningsByChunk };
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// src/document/components/DocViewer.tsx
|
|
658
|
-
import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState3 } from "react";
|
|
659
|
-
|
|
660
|
-
// src/document/components/DocRail.tsx
|
|
661
|
-
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
662
|
-
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
663
|
-
var PAGE_W = 1632;
|
|
664
|
-
var PAGE_H = 1056;
|
|
665
|
-
function entryId(entry) {
|
|
666
|
-
if (entry.kind === "cover") return "cover";
|
|
667
|
-
if (entry.kind === "page") return entry.page.id;
|
|
668
|
-
return `ghost:${entry.chunkId}`;
|
|
669
|
-
}
|
|
670
|
-
var INDENT = ["", "pl-4", "pl-8"];
|
|
671
|
-
var indentClass = (level) => INDENT[Math.min(level, INDENT.length - 1)] || void 0;
|
|
672
|
-
function ThumbButton({
|
|
673
|
-
id,
|
|
674
|
-
selectedId,
|
|
675
|
-
scale,
|
|
676
|
-
label,
|
|
677
|
-
indentLevel,
|
|
678
|
-
onSelect,
|
|
679
|
-
children
|
|
680
|
-
}) {
|
|
681
|
-
const liRef = useRef(null);
|
|
682
|
-
const [shown, setShown] = useState2(typeof IntersectionObserver === "undefined");
|
|
683
|
-
useEffect2(() => {
|
|
684
|
-
if (shown) return;
|
|
685
|
-
const el = liRef.current;
|
|
686
|
-
if (!el) return;
|
|
687
|
-
const obs = new IntersectionObserver(
|
|
688
|
-
(entries) => {
|
|
689
|
-
if (entries.some((e) => e.isIntersecting)) {
|
|
690
|
-
setShown(true);
|
|
691
|
-
obs.disconnect();
|
|
692
|
-
}
|
|
693
|
-
},
|
|
694
|
-
{ rootMargin: "200% 0px" }
|
|
695
|
-
);
|
|
696
|
-
obs.observe(el);
|
|
697
|
-
return () => obs.disconnect();
|
|
698
|
-
}, [shown]);
|
|
699
|
-
return /* @__PURE__ */ jsx5("li", { ref: liRef, className: indentClass(indentLevel ?? 0), children: /* @__PURE__ */ jsxs5(
|
|
700
|
-
"button",
|
|
701
|
-
{
|
|
702
|
-
type: "button",
|
|
703
|
-
onClick: () => onSelect(id),
|
|
704
|
-
className: `relative block w-full rounded border-2 bg-white ${id === selectedId ? "border-teal-600" : "border-neutral-200 hover:border-neutral-300"}`,
|
|
705
|
-
children: [
|
|
706
|
-
/* @__PURE__ */ jsx5("span", { className: "pointer-events-none block w-full overflow-hidden aspect-[17/11]", children: /* @__PURE__ */ jsx5(
|
|
707
|
-
"span",
|
|
708
|
-
{
|
|
709
|
-
className: "block origin-top-left",
|
|
710
|
-
style: { transform: `scale(${scale})`, width: PAGE_W, height: PAGE_H },
|
|
711
|
-
children: shown ? children : null
|
|
712
|
-
}
|
|
713
|
-
) }),
|
|
714
|
-
/* @__PURE__ */ jsx5("span", { className: "absolute bottom-0.5 left-1 max-w-[90%] truncate text-[10px] text-neutral-400", children: label })
|
|
715
|
-
]
|
|
716
|
-
}
|
|
717
|
-
) });
|
|
718
|
-
}
|
|
719
|
-
function DocRail({
|
|
720
|
-
entries,
|
|
721
|
-
selectedId,
|
|
722
|
-
meta,
|
|
723
|
-
cover,
|
|
724
|
-
coverImage,
|
|
725
|
-
host,
|
|
726
|
-
onSelect,
|
|
727
|
-
onCollapse
|
|
728
|
-
}) {
|
|
729
|
-
const listRef = useRef(null);
|
|
730
|
-
const [scale, setScale] = useState2(0.11);
|
|
731
|
-
useEffect2(() => {
|
|
732
|
-
const el = listRef.current;
|
|
733
|
-
if (!el || typeof ResizeObserver === "undefined") return;
|
|
734
|
-
const obs = new ResizeObserver(() => {
|
|
735
|
-
const w = el.clientWidth - 4;
|
|
736
|
-
if (w > 0) setScale(w / PAGE_W);
|
|
737
|
-
});
|
|
738
|
-
obs.observe(el);
|
|
739
|
-
return () => obs.disconnect();
|
|
740
|
-
}, []);
|
|
741
|
-
return /* @__PURE__ */ jsxs5(
|
|
742
|
-
"nav",
|
|
743
|
-
{
|
|
744
|
-
"data-testid": "doc-rail",
|
|
745
|
-
className: "flex w-52 shrink-0 flex-col overflow-y-auto border-r border-neutral-200 bg-neutral-50 p-3",
|
|
746
|
-
children: [
|
|
747
|
-
/* @__PURE__ */ jsxs5(
|
|
748
|
-
"button",
|
|
749
|
-
{
|
|
750
|
-
type: "button",
|
|
751
|
-
"aria-label": "Collapse page rail",
|
|
752
|
-
onClick: onCollapse,
|
|
753
|
-
className: "mb-2 flex w-full items-center justify-between rounded px-2 py-1.5 text-sm font-medium text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900",
|
|
754
|
-
children: [
|
|
755
|
-
/* @__PURE__ */ jsx5("span", { children: "Pages" }),
|
|
756
|
-
/* @__PURE__ */ jsx5("span", { "aria-hidden": "true", className: "text-lg leading-none", children: "\u2039" })
|
|
757
|
-
]
|
|
758
|
-
}
|
|
759
|
-
),
|
|
760
|
-
/* @__PURE__ */ jsx5("ol", { ref: listRef, className: "flex flex-col gap-2", children: entries.map((entry) => {
|
|
761
|
-
const id = entryId(entry);
|
|
762
|
-
if (entry.kind === "cover") {
|
|
763
|
-
return /* @__PURE__ */ jsx5(ThumbButton, { id, selectedId, scale, label: "Cover", onSelect, children: /* @__PURE__ */ jsx5(DocCoverPage, { cover, meta, image: coverImage, host }) }, id);
|
|
764
|
-
}
|
|
765
|
-
if (entry.kind === "page") {
|
|
766
|
-
return /* @__PURE__ */ jsx5(
|
|
767
|
-
ThumbButton,
|
|
768
|
-
{
|
|
769
|
-
id,
|
|
770
|
-
selectedId,
|
|
771
|
-
scale,
|
|
772
|
-
label: entry.page.title,
|
|
773
|
-
indentLevel: (entry.page.depth ?? 0) + (entry.page.cont ? 1 : 0),
|
|
774
|
-
onSelect,
|
|
775
|
-
children: /* @__PURE__ */ jsx5(DocSectionPage, { page: entry.page, meta, host })
|
|
776
|
-
},
|
|
777
|
-
id
|
|
778
|
-
);
|
|
779
|
-
}
|
|
780
|
-
return /* @__PURE__ */ jsx5("li", { className: indentClass(entry.depth ?? 0), children: /* @__PURE__ */ jsxs5(
|
|
781
|
-
"button",
|
|
782
|
-
{
|
|
783
|
-
type: "button",
|
|
784
|
-
onClick: () => onSelect(id),
|
|
785
|
-
className: `flex w-full items-center justify-between gap-2 rounded border px-2 py-2 text-left text-xs ${id === selectedId ? "border-teal-600 bg-white" : "border-dashed border-neutral-300 bg-neutral-50 hover:border-neutral-400"}`,
|
|
786
|
-
children: [
|
|
787
|
-
/* @__PURE__ */ jsx5("span", { className: "truncate text-neutral-400", children: entry.title }),
|
|
788
|
-
/* @__PURE__ */ jsx5("span", { className: "shrink-0 rounded bg-neutral-200 px-1 text-[10px] uppercase tracking-wide text-neutral-500", children: entry.reason })
|
|
789
|
-
]
|
|
790
|
-
}
|
|
791
|
-
) }, id);
|
|
792
|
-
}) })
|
|
793
|
-
]
|
|
794
|
-
}
|
|
795
|
-
);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// src/document/components/DocViewer.tsx
|
|
799
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
800
|
-
var PAGE_W2 = 1632;
|
|
801
|
-
var PAGE_H2 = 1056;
|
|
802
|
-
function chunkIdOf(id) {
|
|
803
|
-
if (id === "cover") return null;
|
|
804
|
-
if (id.startsWith("ghost:")) return id.slice("ghost:".length);
|
|
805
|
-
if (id.includes("#")) return id.slice(0, id.lastIndexOf("#"));
|
|
806
|
-
return id;
|
|
807
|
-
}
|
|
808
|
-
function DocViewer({
|
|
809
|
-
source,
|
|
810
|
-
document: doc,
|
|
811
|
-
host,
|
|
812
|
-
mode,
|
|
813
|
-
selectedChunkId,
|
|
814
|
-
onSelectChunk,
|
|
815
|
-
onClose,
|
|
816
|
-
downloadHref,
|
|
817
|
-
onDocState
|
|
818
|
-
}) {
|
|
819
|
-
const { chunks, pages, measuring, warningsByChunk } = useDocPages({ source, sections: doc.sections });
|
|
820
|
-
const [activeId, setActiveId] = useState3("cover");
|
|
821
|
-
const [railOpen, setRailOpen] = useState3(true);
|
|
822
|
-
const coverImage = doc.cover.imageId ? source?.images[doc.cover.imageId] ?? null : null;
|
|
823
|
-
const onDocStateRef = useRef2(onDocState);
|
|
824
|
-
onDocStateRef.current = onDocState;
|
|
825
|
-
const lastEmitRef = useRef2(null);
|
|
826
|
-
useEffect3(() => {
|
|
827
|
-
if (lastEmitRef.current?.chunks === chunks && lastEmitRef.current?.warningsByChunk === warningsByChunk) return;
|
|
828
|
-
lastEmitRef.current = { chunks, warningsByChunk };
|
|
829
|
-
onDocStateRef.current?.({ chunks, warningsByChunk });
|
|
830
|
-
}, [chunks, warningsByChunk]);
|
|
831
|
-
const entries = useMemo3(() => {
|
|
832
|
-
const list = [{ kind: "cover" }];
|
|
833
|
-
for (const chunk of chunks) {
|
|
834
|
-
const s = settingsFor(doc.sections, chunk.id);
|
|
835
|
-
const empty = chunk.textBlocks.length === 0 && chunk.images.length === 0;
|
|
836
|
-
if (s.excluded || empty) {
|
|
837
|
-
if (mode === "edit") {
|
|
838
|
-
list.push({ kind: "ghost", chunkId: chunk.id, title: chunk.title, reason: s.excluded ? "excluded" : "empty", depth: chunk.depth });
|
|
839
|
-
}
|
|
840
|
-
} else {
|
|
841
|
-
for (const page of pages.filter((p) => p.chunkId === chunk.id)) list.push({ kind: "page", page });
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
return list;
|
|
845
|
-
}, [chunks, pages, doc.sections, mode]);
|
|
846
|
-
const selectEntry = useCallback(
|
|
847
|
-
(id) => {
|
|
848
|
-
setActiveId(id);
|
|
849
|
-
if (mode === "edit") onSelectChunk?.(chunkIdOf(id));
|
|
850
|
-
},
|
|
851
|
-
[mode, onSelectChunk]
|
|
852
|
-
);
|
|
853
|
-
useEffect3(() => {
|
|
854
|
-
if (measuring) return;
|
|
855
|
-
if (entries.some((e) => entryId(e) === activeId)) return;
|
|
856
|
-
const chunkId = chunkIdOf(activeId);
|
|
857
|
-
const ghost = entries.find((e) => e.kind === "ghost" && e.chunkId === chunkId);
|
|
858
|
-
setActiveId(ghost ? entryId(ghost) : "cover");
|
|
859
|
-
}, [entries, activeId, measuring]);
|
|
860
|
-
useEffect3(() => {
|
|
861
|
-
if (mode !== "edit" || selectedChunkId === void 0) return;
|
|
862
|
-
if (chunkIdOf(activeId) === selectedChunkId) return;
|
|
863
|
-
if (selectedChunkId === null) {
|
|
864
|
-
setActiveId("cover");
|
|
865
|
-
return;
|
|
866
|
-
}
|
|
867
|
-
const match = entries.find(
|
|
868
|
-
(e) => e.kind === "page" && e.page.chunkId === selectedChunkId || e.kind === "ghost" && e.chunkId === selectedChunkId
|
|
869
|
-
);
|
|
870
|
-
if (match) setActiveId(entryId(match));
|
|
871
|
-
}, [selectedChunkId, mode, entries, activeId]);
|
|
872
|
-
const activeIdRef = useRef2(activeId);
|
|
873
|
-
activeIdRef.current = activeId;
|
|
874
|
-
useEffect3(() => {
|
|
875
|
-
if (mode !== "present") return;
|
|
876
|
-
const onKey = (e) => {
|
|
877
|
-
const t = e.target;
|
|
878
|
-
if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.tagName === "SELECT" || t.isContentEditable)) return;
|
|
879
|
-
let dir = 0;
|
|
880
|
-
if (e.key === "ArrowRight" || e.key === "ArrowDown") dir = 1;
|
|
881
|
-
else if (e.key === "ArrowLeft" || e.key === "ArrowUp") dir = -1;
|
|
882
|
-
else return;
|
|
883
|
-
e.preventDefault();
|
|
884
|
-
const ids = entries.map(entryId);
|
|
885
|
-
const cur = Math.max(0, ids.indexOf(activeIdRef.current));
|
|
886
|
-
const next = Math.min(ids.length - 1, Math.max(0, cur + dir));
|
|
887
|
-
if (ids[next] !== activeIdRef.current) selectEntry(ids[next]);
|
|
888
|
-
};
|
|
889
|
-
window.addEventListener("keydown", onKey);
|
|
890
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
891
|
-
}, [entries, selectEntry, mode]);
|
|
892
|
-
const active = entries.find((e) => entryId(e) === activeId) ?? null;
|
|
893
|
-
return (
|
|
894
|
-
// min-w-0 (here and on the rail/canvas row): without it these flex items
|
|
895
|
-
// refuse to shrink below their content width, and opening the rail shoves
|
|
896
|
-
// the overlay's inspector off the right edge instead of narrowing the
|
|
897
|
-
// canvas.
|
|
898
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex h-full min-h-0 min-w-0 flex-1 flex-col", children: [
|
|
899
|
-
mode === "present" ? /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between border-b border-base-200 bg-base px-4 py-2", children: [
|
|
900
|
-
/* @__PURE__ */ jsx6("span", { className: "text-sm font-medium text-base-contrast", children: source?.pageTitle ?? "Document" }),
|
|
901
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
902
|
-
downloadHref ? /* @__PURE__ */ jsx6(
|
|
903
|
-
"a",
|
|
904
|
-
{
|
|
905
|
-
href: downloadHref,
|
|
906
|
-
download: true,
|
|
907
|
-
"aria-label": "Download PDF",
|
|
908
|
-
className: "rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30",
|
|
909
|
-
children: "Download PDF"
|
|
910
|
-
}
|
|
911
|
-
) : null,
|
|
912
|
-
onClose ? /* @__PURE__ */ jsx6(
|
|
913
|
-
"button",
|
|
914
|
-
{
|
|
915
|
-
type: "button",
|
|
916
|
-
"aria-label": "Close",
|
|
917
|
-
onClick: onClose,
|
|
918
|
-
className: "rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30",
|
|
919
|
-
children: "\u2715"
|
|
920
|
-
}
|
|
921
|
-
) : null
|
|
922
|
-
] })
|
|
923
|
-
] }) : null,
|
|
924
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex min-h-0 min-w-0 flex-1", children: [
|
|
925
|
-
railOpen ? /* @__PURE__ */ jsx6(
|
|
926
|
-
DocRail,
|
|
927
|
-
{
|
|
928
|
-
entries,
|
|
929
|
-
selectedId: activeId,
|
|
930
|
-
meta: doc.meta,
|
|
931
|
-
cover: doc.cover,
|
|
932
|
-
coverImage,
|
|
933
|
-
host,
|
|
934
|
-
onSelect: selectEntry,
|
|
935
|
-
onCollapse: () => setRailOpen(false)
|
|
936
|
-
}
|
|
937
|
-
) : /* @__PURE__ */ jsx6("div", { className: "flex w-10 shrink-0 flex-col border-r border-neutral-200 bg-neutral-50", children: /* @__PURE__ */ jsx6(
|
|
938
|
-
"button",
|
|
939
|
-
{
|
|
940
|
-
type: "button",
|
|
941
|
-
"aria-label": "Expand page rail",
|
|
942
|
-
onClick: () => setRailOpen(true),
|
|
943
|
-
className: "px-2 py-3 text-lg leading-none text-neutral-500 hover:text-neutral-800",
|
|
944
|
-
children: "\u203A"
|
|
945
|
-
}
|
|
946
|
-
) }),
|
|
947
|
-
/* @__PURE__ */ jsx6(
|
|
948
|
-
DocCanvas,
|
|
949
|
-
{
|
|
950
|
-
active,
|
|
951
|
-
cover: doc.cover,
|
|
952
|
-
coverImage,
|
|
953
|
-
meta: doc.meta,
|
|
954
|
-
host,
|
|
955
|
-
measuring,
|
|
956
|
-
noContent: chunks.length === 0
|
|
957
|
-
}
|
|
958
|
-
)
|
|
959
|
-
] })
|
|
960
|
-
] })
|
|
961
|
-
);
|
|
962
|
-
}
|
|
963
|
-
function DocCanvas({
|
|
964
|
-
active,
|
|
965
|
-
cover,
|
|
966
|
-
coverImage,
|
|
967
|
-
meta,
|
|
968
|
-
host,
|
|
969
|
-
measuring,
|
|
970
|
-
noContent
|
|
971
|
-
}) {
|
|
972
|
-
const containerRef = useRef2(null);
|
|
973
|
-
const [scale, setScale] = useState3(0.4);
|
|
974
|
-
useEffect3(() => {
|
|
975
|
-
const el = containerRef.current;
|
|
976
|
-
if (!el || typeof ResizeObserver === "undefined") return;
|
|
977
|
-
const observer = new ResizeObserver(() => {
|
|
978
|
-
const availW = el.clientWidth - 48;
|
|
979
|
-
const availH = el.clientHeight - 48;
|
|
980
|
-
setScale(Math.max(0.15, Math.min(availW / PAGE_W2, availH / PAGE_H2)));
|
|
981
|
-
});
|
|
982
|
-
observer.observe(el);
|
|
983
|
-
return () => observer.disconnect();
|
|
984
|
-
}, []);
|
|
985
|
-
const note = (text) => /* @__PURE__ */ jsx6("p", { className: "text-sm text-neutral-400", children: text });
|
|
986
|
-
let body;
|
|
987
|
-
if (active?.kind === "cover") {
|
|
988
|
-
body = noContent ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center gap-4", children: [
|
|
989
|
-
/* @__PURE__ */ jsx6(Scaled, { scale, children: /* @__PURE__ */ jsx6(DocCoverPage, { cover, meta, image: coverImage, host }) }),
|
|
990
|
-
/* @__PURE__ */ jsx6("p", { className: "text-sm text-neutral-400", children: "This page has no displayable content." })
|
|
991
|
-
] }) : /* @__PURE__ */ jsx6(Scaled, { scale, children: /* @__PURE__ */ jsx6(DocCoverPage, { cover, meta, image: coverImage, host }) });
|
|
992
|
-
} else if (active?.kind === "page") {
|
|
993
|
-
body = /* @__PURE__ */ jsx6(Scaled, { scale, children: /* @__PURE__ */ jsx6(DocSectionPage, { page: active.page, meta, host }) });
|
|
994
|
-
} else if (active?.kind === "ghost") {
|
|
995
|
-
body = note(active.reason === "excluded" ? "Excluded \u2014 re-include from the inspector" : "No displayable content");
|
|
996
|
-
} else {
|
|
997
|
-
body = measuring ? note("Laying out\u2026") : note("This page has no displayable content.");
|
|
998
|
-
}
|
|
999
|
-
return /* @__PURE__ */ jsx6(
|
|
1000
|
-
"div",
|
|
1001
|
-
{
|
|
1002
|
-
ref: containerRef,
|
|
1003
|
-
"data-testid": "doc-canvas",
|
|
1004
|
-
className: "flex min-h-0 min-w-0 flex-1 overflow-auto bg-neutral-100 p-6",
|
|
1005
|
-
children: /* @__PURE__ */ jsx6("div", { className: "m-auto", children: body })
|
|
1006
|
-
}
|
|
1007
|
-
);
|
|
1008
|
-
}
|
|
1009
|
-
function Scaled({ scale, children }) {
|
|
1010
|
-
return /* @__PURE__ */ jsx6("div", { className: "shrink-0 overflow-hidden shadow-lg", style: { width: PAGE_W2 * scale, height: PAGE_H2 * scale }, children: /* @__PURE__ */ jsx6("div", { className: "origin-top-left", style: { transform: `scale(${scale})`, width: PAGE_W2, height: PAGE_H2 }, children }) });
|
|
1011
|
-
}
|
|
1012
|
-
export {
|
|
1013
|
-
DOC_GEOM,
|
|
1014
|
-
DocCoverPage,
|
|
1015
|
-
DocPage,
|
|
1016
|
-
DocRail,
|
|
1017
|
-
DocSectionPage,
|
|
1018
|
-
DocViewer,
|
|
1019
|
-
PREAMBLE_ID,
|
|
1020
|
-
documentOptionsSchema,
|
|
1021
|
-
entryId,
|
|
1022
|
-
harvest,
|
|
1023
|
-
layoutMasonryPage,
|
|
1024
|
-
paginateChunk,
|
|
1025
|
-
sectionSettingsSchema,
|
|
1026
|
-
settingsFor,
|
|
1027
|
-
settingsIssuesFor,
|
|
1028
|
-
splitProseBlocks,
|
|
1029
|
-
useDocPages
|
|
1030
|
-
};
|