@drawnagency/primitives 0.1.98 → 0.1.100
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-EUSWEVOA.js → chunk-3TO4RRHY.js} +12 -1
- package/dist/{chunk-KP4DWTPR.js → chunk-72FMQQIA.js} +246 -3
- package/dist/chunk-BS5AQHZG.js +45 -0
- package/dist/{chunk-NA5EJM6Z.js → chunk-CZLYECHC.js} +19 -8
- package/dist/{chunk-HKHEAH5F.js → chunk-GOCFTXR3.js} +8 -60
- package/dist/{chunk-GYCBWGVW.js → chunk-LBHQWIVL.js} +79 -24
- package/dist/{chunk-HJSE6SK5.js → chunk-REDDTTGJ.js} +3 -3
- package/dist/collab/rebase.d.ts.map +1 -1
- package/dist/collab/rebase.js +3 -1
- package/dist/components/chat/ChatPanel.d.ts.map +1 -1
- package/dist/components/docfile/DocFileOverlay.d.ts +12 -0
- package/dist/components/docfile/DocFileOverlay.d.ts.map +1 -0
- package/dist/components/docfile/DocFilePane.d.ts +17 -0
- package/dist/components/docfile/DocFilePane.d.ts.map +1 -0
- package/dist/components/docfile/doc-file-state.d.ts +33 -0
- package/dist/components/docfile/doc-file-state.d.ts.map +1 -0
- package/dist/components/editor/SettingsForm.d.ts.map +1 -1
- package/dist/components/editor/index.js +1 -1
- package/dist/components/sections/Document/index.d.ts +18 -0
- package/dist/components/sections/Document/index.d.ts.map +1 -0
- package/dist/components/sections/all-sections.d.ts +10 -0
- package/dist/components/sections/all-sections.d.ts.map +1 -1
- package/dist/components/sections/brand-guide.d.ts +10 -0
- package/dist/components/sections/brand-guide.d.ts.map +1 -1
- package/dist/components/sections/brand-guide.js +3 -1
- package/dist/components/sections/register-schemas.js +5 -3
- package/dist/components/sections/register.js +5 -3
- package/dist/components/shared/DocumentSourceField.d.ts +13 -0
- package/dist/components/shared/DocumentSourceField.d.ts.map +1 -0
- package/dist/components/shared/Navigation.d.ts.map +1 -1
- package/dist/components/shell/EditorModal.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/MediaBreadcrumb.d.ts.map +1 -1
- package/dist/components/shell/MediaFolderTile.d.ts +3 -1
- package/dist/components/shell/MediaFolderTile.d.ts.map +1 -1
- package/dist/components/shell/MediaFolderTree.d.ts +3 -0
- package/dist/components/shell/MediaFolderTree.d.ts.map +1 -1
- package/dist/components/shell/MediaLibraryContext.d.ts +18 -1
- package/dist/components/shell/MediaLibraryContext.d.ts.map +1 -1
- package/dist/components/shell/MediaLibraryModal.d.ts +21 -1
- package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
- package/dist/hooks/useDocumentUploads.d.ts +32 -0
- package/dist/hooks/useDocumentUploads.d.ts.map +1 -0
- package/dist/hooks/useEditorPublish.d.ts +23 -1
- package/dist/hooks/useEditorPublish.d.ts.map +1 -1
- package/dist/hooks/useMediaPipeline.d.ts +14 -1
- package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
- package/dist/hooks/useResolvedDocument.d.ts +12 -0
- package/dist/hooks/useResolvedDocument.d.ts.map +1 -0
- package/dist/index.js +60 -34
- package/dist/lib/block-move.d.ts.map +1 -1
- package/dist/lib/dexie.d.ts +11 -0
- package/dist/lib/dexie.d.ts.map +1 -1
- package/dist/lib/dexie.js +32 -0
- package/dist/lib/document-refs.d.ts +22 -0
- package/dist/lib/document-refs.d.ts.map +1 -0
- package/dist/lib/document-uploads.d.ts +38 -0
- package/dist/lib/document-uploads.d.ts.map +1 -0
- package/dist/lib/documents.d.ts +65 -0
- package/dist/lib/documents.d.ts.map +1 -0
- package/dist/lib/index-ops.d.ts +1 -0
- package/dist/lib/index-ops.d.ts.map +1 -1
- package/dist/lib/index-ops.js +13 -1
- package/dist/lib/index.js +6 -6
- package/dist/lib/loader.d.ts +6 -0
- package/dist/lib/loader.d.ts.map +1 -1
- package/dist/lib/media-folders.d.ts +8 -0
- package/dist/lib/media-folders.d.ts.map +1 -1
- package/dist/lib/media-folders.js +2 -0
- package/dist/lib/nav.d.ts +29 -1
- package/dist/lib/nav.d.ts.map +1 -1
- package/dist/lib/pages.d.ts +18 -0
- package/dist/lib/pages.d.ts.map +1 -1
- package/dist/lib/platform-broker.d.ts +12 -0
- package/dist/lib/platform-broker.d.ts.map +1 -1
- package/dist/lib/platform-broker.js +12 -3
- package/dist/lib/registry.d.ts +10 -0
- package/dist/lib/registry.d.ts.map +1 -1
- package/dist/lib/save-chunks.d.ts +15 -0
- package/dist/lib/save-chunks.d.ts.map +1 -1
- package/dist/lib/scroll-lock.d.ts +2 -0
- package/dist/lib/scroll-lock.d.ts.map +1 -0
- package/dist/schemas/documents.d.ts +80 -0
- package/dist/schemas/documents.d.ts.map +1 -0
- package/dist/schemas/documents.js +25 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +24 -2
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +5 -1
- package/dist/storage/types.d.ts +69 -5
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/types/database.d.ts +14 -0
- package/dist/types/database.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/collab/rebase.ts +15 -0
- package/src/components/chat/ChatPanel.tsx +5 -4
- package/src/components/docfile/DocFileOverlay.tsx +54 -0
- package/src/components/docfile/DocFilePane.tsx +129 -0
- package/src/components/docfile/doc-file-state.ts +180 -0
- package/src/components/editor/SettingsForm.tsx +10 -0
- package/src/components/sections/Document/index.tsx +163 -0
- package/src/components/sections/brand-guide.ts +2 -1
- package/src/components/shared/DocumentSourceField.tsx +51 -0
- package/src/components/shared/Navigation.tsx +53 -10
- package/src/components/shell/EditorModal.tsx +2 -5
- package/src/components/shell/EditorShell.tsx +154 -10
- package/src/components/shell/MediaBreadcrumb.tsx +14 -1
- package/src/components/shell/MediaFolderTile.tsx +4 -2
- package/src/components/shell/MediaFolderTree.tsx +20 -3
- package/src/components/shell/MediaLibraryContext.tsx +18 -1
- package/src/components/shell/MediaLibraryModal.tsx +223 -45
- package/src/hooks/useDocumentUploads.ts +330 -0
- package/src/hooks/useEditorPublish.ts +197 -11
- package/src/hooks/useMediaPipeline.ts +136 -5
- package/src/hooks/useResolvedDocument.ts +25 -0
- package/src/lib/block-move.ts +15 -4
- package/src/lib/dexie.ts +54 -0
- package/src/lib/document-refs.ts +83 -0
- package/src/lib/document-uploads.ts +66 -0
- package/src/lib/documents.ts +138 -0
- package/src/lib/index-ops.ts +16 -0
- package/src/lib/loader.ts +32 -11
- package/src/lib/media-folders.ts +9 -0
- package/src/lib/nav.ts +46 -2
- package/src/lib/pages.ts +48 -0
- package/src/lib/platform-broker.ts +18 -3
- package/src/lib/registry.ts +9 -0
- package/src/lib/save-chunks.ts +42 -0
- package/src/lib/scroll-lock.ts +27 -0
- package/src/schemas/documents.ts +82 -0
- package/src/schemas/index.ts +1 -0
- package/src/schemas/nav.ts +3 -3
- package/src/storage/index.ts +2 -2
- package/src/storage/types.ts +71 -5
- package/src/types/database.ts +14 -0
- /package/dist/{chunk-FOY5TF7D.js → chunk-ZDQ3TT47.js} +0 -0
|
@@ -7,6 +7,14 @@ var StorageConflictError = class extends Error {
|
|
|
7
7
|
}
|
|
8
8
|
currentVersion;
|
|
9
9
|
};
|
|
10
|
+
var IdempotencyLookupUnavailableError = class extends Error {
|
|
11
|
+
constructor(cause) {
|
|
12
|
+
super("Could not search draft history for the idempotency key");
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
this.name = "IdempotencyLookupUnavailableError";
|
|
15
|
+
}
|
|
16
|
+
cause;
|
|
17
|
+
};
|
|
10
18
|
var IDEMPOTENCY_TRAILER = "Idempotency-Key";
|
|
11
19
|
var IDEMPOTENCY_KEY_RE = /^[A-Za-z0-9._:-]{8,200}$/;
|
|
12
20
|
function withIdempotencyTrailer(subject, key) {
|
|
@@ -19,11 +27,14 @@ function withIdempotencyTrailer(subject, key) {
|
|
|
19
27
|
${IDEMPOTENCY_TRAILER}: ${key}`;
|
|
20
28
|
}
|
|
21
29
|
var ASSET_CACHE_CONTROL = "max-age=31536000, immutable";
|
|
30
|
+
var DOCUMENT_CACHE_CONTROL = "private, max-age=31536000, immutable";
|
|
22
31
|
|
|
23
32
|
export {
|
|
24
33
|
StorageConflictError,
|
|
34
|
+
IdempotencyLookupUnavailableError,
|
|
25
35
|
IDEMPOTENCY_TRAILER,
|
|
26
36
|
IDEMPOTENCY_KEY_RE,
|
|
27
37
|
withIdempotencyTrailer,
|
|
28
|
-
ASSET_CACHE_CONTROL
|
|
38
|
+
ASSET_CACHE_CONTROL,
|
|
39
|
+
DOCUMENT_CACHE_CONTROL
|
|
29
40
|
};
|
|
@@ -24,6 +24,9 @@ import {
|
|
|
24
24
|
curatedIcons,
|
|
25
25
|
getIcon
|
|
26
26
|
} from "./chunk-WDSVHKAH.js";
|
|
27
|
+
import {
|
|
28
|
+
createEvent
|
|
29
|
+
} from "./chunk-PTOLUMGV.js";
|
|
27
30
|
import {
|
|
28
31
|
cn
|
|
29
32
|
} from "./chunk-7EOSDFS3.js";
|
|
@@ -65,9 +68,9 @@ function getContrastClass(hex) {
|
|
|
65
68
|
const h = hex.replace("#", "");
|
|
66
69
|
if (h.length < 6) return "text-white";
|
|
67
70
|
const r = parseInt(h.substring(0, 2), 16);
|
|
68
|
-
const
|
|
71
|
+
const g2 = parseInt(h.substring(2, 4), 16);
|
|
69
72
|
const b = parseInt(h.substring(4, 6), 16);
|
|
70
|
-
const yiq = (r * 299 +
|
|
73
|
+
const yiq = (r * 299 + g2 * 587 + b * 114) / 1e3;
|
|
71
74
|
return yiq >= 128 ? "text-black" : "text-white";
|
|
72
75
|
}
|
|
73
76
|
var createColorItem = () => ({
|
|
@@ -1295,13 +1298,253 @@ var DoDontMedia_default = defineSection({
|
|
|
1295
1298
|
]
|
|
1296
1299
|
});
|
|
1297
1300
|
|
|
1301
|
+
// src/components/sections/Document/index.tsx
|
|
1302
|
+
import { useEffect as useEffect5, useState as useState6 } from "react";
|
|
1303
|
+
import { z as z5 } from "zod";
|
|
1304
|
+
import { ExternalLink, FileText } from "lucide-react";
|
|
1305
|
+
|
|
1306
|
+
// src/lib/container-ops.ts
|
|
1307
|
+
function getContainerChildren(block) {
|
|
1308
|
+
const content = block.content;
|
|
1309
|
+
return Array.isArray(content?.children) ? content.children : [];
|
|
1310
|
+
}
|
|
1311
|
+
function withChildren(container, children) {
|
|
1312
|
+
return { ...container, content: { ...container.content, children } };
|
|
1313
|
+
}
|
|
1314
|
+
function containerColumns(container) {
|
|
1315
|
+
const n = container.content?.columns;
|
|
1316
|
+
return typeof n === "number" && n >= 1 ? n : 1;
|
|
1317
|
+
}
|
|
1318
|
+
function removeChildAt(container, index) {
|
|
1319
|
+
const children = getContainerChildren(container);
|
|
1320
|
+
if (index < 0 || index >= children.length) return { container, removed: null };
|
|
1321
|
+
const next = [...children];
|
|
1322
|
+
const [removed] = next.splice(index, 1);
|
|
1323
|
+
return { container: withChildren(container, next), removed };
|
|
1324
|
+
}
|
|
1325
|
+
function duplicateChildAt(container, index, newId) {
|
|
1326
|
+
const children = getContainerChildren(container);
|
|
1327
|
+
if (index < 0 || index >= children.length) return container;
|
|
1328
|
+
const clone = { ...JSON.parse(JSON.stringify(children[index])), id: newId() };
|
|
1329
|
+
const next = [...children];
|
|
1330
|
+
next.splice(index + 1, 0, clone);
|
|
1331
|
+
return withChildren(container, next);
|
|
1332
|
+
}
|
|
1333
|
+
function setChildColSpan(container, index, span) {
|
|
1334
|
+
const children = getContainerChildren(container);
|
|
1335
|
+
if (index < 0 || index >= children.length) return container;
|
|
1336
|
+
const clamped = Math.max(1, Math.min(span, containerColumns(container)));
|
|
1337
|
+
const next = children.map((child, i) => {
|
|
1338
|
+
if (i !== index) return child;
|
|
1339
|
+
if (clamped <= 1) {
|
|
1340
|
+
const { layout: _drop, ...rest } = child;
|
|
1341
|
+
return rest;
|
|
1342
|
+
}
|
|
1343
|
+
return { ...child, layout: { ...child.layout, colSpan: clamped } };
|
|
1344
|
+
});
|
|
1345
|
+
return withChildren(container, next);
|
|
1346
|
+
}
|
|
1347
|
+
function effectiveSpan(child, columns) {
|
|
1348
|
+
return isSpacer(child) ? 1 : Math.min(child.layout?.colSpan ?? 1, columns);
|
|
1349
|
+
}
|
|
1350
|
+
function isSpacer(child) {
|
|
1351
|
+
return child.type === "spacer";
|
|
1352
|
+
}
|
|
1353
|
+
function occupiedColumns(children, columns) {
|
|
1354
|
+
return children.reduce((sum, c) => sum + effectiveSpan(c, columns), 0);
|
|
1355
|
+
}
|
|
1356
|
+
function trimTrailingSpacers(container) {
|
|
1357
|
+
const children = getContainerChildren(container);
|
|
1358
|
+
let end = children.length;
|
|
1359
|
+
while (end > 0 && isSpacer(children[end - 1])) end--;
|
|
1360
|
+
if (end === children.length) return container;
|
|
1361
|
+
return withChildren(container, children.slice(0, end));
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// src/lib/documents.ts
|
|
1365
|
+
function formatDocSize(bytes) {
|
|
1366
|
+
if (!Number.isFinite(bytes) || bytes < 0) return "";
|
|
1367
|
+
if (bytes < 1024) return `${Math.round(bytes)} B`;
|
|
1368
|
+
const units = ["KB", "MB", "GB"];
|
|
1369
|
+
let value = bytes / 1024;
|
|
1370
|
+
let unit = 0;
|
|
1371
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
1372
|
+
value /= 1024;
|
|
1373
|
+
unit++;
|
|
1374
|
+
}
|
|
1375
|
+
return `${value >= 100 ? Math.round(value) : Number(value.toFixed(1))} ${units[unit]}`;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
// src/components/docfile/doc-file-state.ts
|
|
1379
|
+
var DOC_OPEN_CLASS = "bp-doc-open";
|
|
1380
|
+
var DOC_DESKTOP_QUERY = "(min-width: 1024px)";
|
|
1381
|
+
var docFileOpenEvent = createEvent("bp-doc-file-open");
|
|
1382
|
+
var STORE_KEY = /* @__PURE__ */ Symbol.for("@drawnagency/primitives/doc-file-state");
|
|
1383
|
+
var g = globalThis;
|
|
1384
|
+
function store() {
|
|
1385
|
+
let s = g[STORE_KEY];
|
|
1386
|
+
if (!s) {
|
|
1387
|
+
s = { open: null, docs: null, openListeners: /* @__PURE__ */ new Set(), docsListeners: /* @__PURE__ */ new Set(), teardown: null };
|
|
1388
|
+
g[STORE_KEY] = s;
|
|
1389
|
+
}
|
|
1390
|
+
return s;
|
|
1391
|
+
}
|
|
1392
|
+
function isDocDesktop() {
|
|
1393
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return true;
|
|
1394
|
+
return window.matchMedia(DOC_DESKTOP_QUERY).matches;
|
|
1395
|
+
}
|
|
1396
|
+
function apply(sectionId) {
|
|
1397
|
+
const s = store();
|
|
1398
|
+
if (s.open === sectionId) return;
|
|
1399
|
+
s.open = sectionId;
|
|
1400
|
+
if (typeof document !== "undefined") {
|
|
1401
|
+
document.documentElement.classList.toggle(DOC_OPEN_CLASS, sectionId !== null);
|
|
1402
|
+
}
|
|
1403
|
+
for (const listener of [...s.openListeners]) listener(sectionId);
|
|
1404
|
+
}
|
|
1405
|
+
function openDocFile(sectionId) {
|
|
1406
|
+
if (typeof window !== "undefined") {
|
|
1407
|
+
const hash = `#doc=${encodeURIComponent(sectionId)}`;
|
|
1408
|
+
if (window.location.hash !== hash) {
|
|
1409
|
+
window.history.pushState(null, "", hash);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
apply(sectionId);
|
|
1413
|
+
docFileOpenEvent.dispatch({ sectionId });
|
|
1414
|
+
}
|
|
1415
|
+
function getSiteDocuments() {
|
|
1416
|
+
return store().docs;
|
|
1417
|
+
}
|
|
1418
|
+
function subscribeSiteDocuments(cb) {
|
|
1419
|
+
const s = store();
|
|
1420
|
+
s.docsListeners.add(cb);
|
|
1421
|
+
return () => {
|
|
1422
|
+
s.docsListeners.delete(cb);
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// src/components/sections/Document/index.tsx
|
|
1427
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1428
|
+
var schema4 = z5.object({
|
|
1429
|
+
type: z5.literal("document"),
|
|
1430
|
+
content: z5.object({
|
|
1431
|
+
title: z5.string().describe("Row title. Leave it blank to show the file name without its extension; type a title to override that."),
|
|
1432
|
+
doc: z5.object({
|
|
1433
|
+
documentId: z5.string().default("").describe(
|
|
1434
|
+
"Hash key into the document manifest (src/content/document-manifest.json). Deliberately NOT `imageId`: documents are not resolved by the media ref-baker."
|
|
1435
|
+
)
|
|
1436
|
+
}),
|
|
1437
|
+
showInDocumentsNav: z5.boolean().default(true).describe(
|
|
1438
|
+
"When true, this document also appears in the auto-derived Documents group at the bottom of the left navigation, openable from any page."
|
|
1439
|
+
)
|
|
1440
|
+
}),
|
|
1441
|
+
options: z5.object({}).default({})
|
|
1442
|
+
});
|
|
1443
|
+
function useSiteDocument(sectionId) {
|
|
1444
|
+
const [docs, setDocs] = useState6(null);
|
|
1445
|
+
useEffect5(() => {
|
|
1446
|
+
setDocs(getSiteDocuments());
|
|
1447
|
+
return subscribeSiteDocuments(setDocs);
|
|
1448
|
+
}, []);
|
|
1449
|
+
return {
|
|
1450
|
+
doc: docs ? docs.find((d) => d.sectionId === sectionId) ?? null : null,
|
|
1451
|
+
resolved: docs !== null
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
function DocumentRow({
|
|
1455
|
+
sectionId,
|
|
1456
|
+
title,
|
|
1457
|
+
isEditMode
|
|
1458
|
+
}) {
|
|
1459
|
+
const { doc, resolved } = useSiteDocument(sectionId);
|
|
1460
|
+
if (resolved && !doc && !isEditMode) return null;
|
|
1461
|
+
const label = doc?.title ?? title;
|
|
1462
|
+
function handleClick() {
|
|
1463
|
+
if (!doc) return;
|
|
1464
|
+
if (doc.kind === "pdf" && !isDocDesktop()) {
|
|
1465
|
+
window.open(doc.url, "_blank", "noopener,noreferrer");
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
openDocFile(sectionId);
|
|
1469
|
+
}
|
|
1470
|
+
return /* @__PURE__ */ jsxs9(
|
|
1471
|
+
"button",
|
|
1472
|
+
{
|
|
1473
|
+
type: "button",
|
|
1474
|
+
onClick: handleClick,
|
|
1475
|
+
disabled: !doc,
|
|
1476
|
+
"aria-label": doc ? `Open ${label}` : void 0,
|
|
1477
|
+
className: cn(
|
|
1478
|
+
"flex w-full min-w-0 items-center gap-3 rounded-outer border border-base-200 bg-base px-4 py-3 text-left transition-colors",
|
|
1479
|
+
doc ? "cursor-pointer hover:bg-base-accent" : "cursor-default opacity-60"
|
|
1480
|
+
),
|
|
1481
|
+
children: [
|
|
1482
|
+
/* @__PURE__ */ jsx13(FileText, { size: 18, "aria-hidden": "true", className: "shrink-0 text-base-contrast/60" }),
|
|
1483
|
+
/* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
|
|
1484
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1485
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate text-sm font-medium text-base-contrast", children: label }),
|
|
1486
|
+
doc && /* @__PURE__ */ jsx13("span", { className: "shrink-0 rounded bg-base-100 px-1.5 py-0.5 text-xs font-medium text-base-contrast", children: doc.kind === "pdf" ? "PDF" : "HTML" })
|
|
1487
|
+
] }),
|
|
1488
|
+
/* @__PURE__ */ jsx13("div", { className: "truncate text-xs text-base-contrast/70", children: doc ? `${doc.filename} \xB7 ${formatDocSize(doc.size)}` : resolved ? "File missing" : "\xA0" })
|
|
1489
|
+
] }),
|
|
1490
|
+
doc && /* @__PURE__ */ jsx13(ExternalLink, { size: 16, "aria-hidden": "true", className: "shrink-0 text-base-contrast/50" })
|
|
1491
|
+
]
|
|
1492
|
+
}
|
|
1493
|
+
);
|
|
1494
|
+
}
|
|
1495
|
+
var Document_default = defineSection({
|
|
1496
|
+
type: "document",
|
|
1497
|
+
category: "brand-guide",
|
|
1498
|
+
label: "Document",
|
|
1499
|
+
icon: /* @__PURE__ */ jsx13(FileText, { size: 18 }),
|
|
1500
|
+
schema: schema4,
|
|
1501
|
+
// The row reads the client-side document registry and opens the overlay, so
|
|
1502
|
+
// the viewer hydrates it as an island rather than emitting static HTML.
|
|
1503
|
+
interactive: true,
|
|
1504
|
+
authoringNote: "One downloadable/viewable file \u2014 a PDF or a single self-contained HTML file \u2014 presented as a clickable row. Clicking opens it in a full-viewport preview overlay without leaving the page; on phones a PDF opens in the OS viewer instead. Pick the file from the media library (documents tab); leave the title blank to show the file name without its extension, or type one to override it. Leave 'Show in Documents menu' on for anything a viewer should be able to reach from any page \u2014 those entries collect into a derived Documents group at the bottom of the left nav. Use one section per file; for a set of downloads, place several document sections in a container.",
|
|
1505
|
+
component: ({ content, isEditMode }) => /* @__PURE__ */ jsx13(
|
|
1506
|
+
DocumentRow,
|
|
1507
|
+
{
|
|
1508
|
+
sectionId: content.id ?? "",
|
|
1509
|
+
title: content.content.title,
|
|
1510
|
+
isEditMode
|
|
1511
|
+
}
|
|
1512
|
+
),
|
|
1513
|
+
defaults: () => ({
|
|
1514
|
+
type: "document",
|
|
1515
|
+
content: { title: "", doc: { documentId: "" }, showInDocumentsNav: true },
|
|
1516
|
+
options: {}
|
|
1517
|
+
}),
|
|
1518
|
+
getLabel: (content) => content.content.title || "Document",
|
|
1519
|
+
settings: {
|
|
1520
|
+
doc: { type: "document-source", label: "File", target: "content", default: { documentId: "" } },
|
|
1521
|
+
title: { type: "text", label: "Title", target: "content", default: "", placeholder: "Document title" },
|
|
1522
|
+
showInDocumentsNav: {
|
|
1523
|
+
type: "checkbox",
|
|
1524
|
+
label: "Show in Documents menu",
|
|
1525
|
+
target: "content",
|
|
1526
|
+
default: true
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
settingsTabs: [
|
|
1530
|
+
{ label: "File", fields: ["doc", "title"] },
|
|
1531
|
+
{ label: "Display", fields: ["showInDocumentsNav"] }
|
|
1532
|
+
]
|
|
1533
|
+
});
|
|
1534
|
+
|
|
1298
1535
|
// src/components/sections/brand-guide.ts
|
|
1299
|
-
var brandGuideSectionDefs = [Colors_default, IconList_default, DoDontMedia_default];
|
|
1536
|
+
var brandGuideSectionDefs = [Colors_default, IconList_default, DoDontMedia_default, Document_default];
|
|
1300
1537
|
|
|
1301
1538
|
export {
|
|
1302
1539
|
stripHtmlToPlainText,
|
|
1303
1540
|
truncate,
|
|
1304
1541
|
pluralize,
|
|
1542
|
+
removeChildAt,
|
|
1543
|
+
duplicateChildAt,
|
|
1544
|
+
setChildColSpan,
|
|
1545
|
+
isSpacer,
|
|
1546
|
+
occupiedColumns,
|
|
1547
|
+
trimTrailingSpacers,
|
|
1305
1548
|
ColorSpaceSchema,
|
|
1306
1549
|
ColorItemSchema,
|
|
1307
1550
|
brandGuideSectionDefs
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// src/schemas/documents.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var DOCUMENT_MANIFEST_PATH = "src/content/document-manifest.json";
|
|
4
|
+
var DOCUMENT_GIT_MAX_BYTES = 2621440;
|
|
5
|
+
var DOCUMENT_BUCKET_MAX_BYTES = 209715200;
|
|
6
|
+
var DOCUMENT_MIME_TO_EXT = {
|
|
7
|
+
"application/pdf": "pdf",
|
|
8
|
+
"text/html": "html"
|
|
9
|
+
};
|
|
10
|
+
var DOCUMENT_KIND_TO_MIME = {
|
|
11
|
+
pdf: "application/pdf",
|
|
12
|
+
html: "text/html"
|
|
13
|
+
};
|
|
14
|
+
var DocumentManifestEntrySchema = z.object({
|
|
15
|
+
filename: z.string(),
|
|
16
|
+
size: z.number().int().positive(),
|
|
17
|
+
kind: z.enum(["pdf", "html"]),
|
|
18
|
+
storage: z.enum(["git", "bucket"]),
|
|
19
|
+
/** git: repo path under assets/documents/…; bucket: site-relative object key. */
|
|
20
|
+
path: z.string()
|
|
21
|
+
});
|
|
22
|
+
var DocumentManifestSchema = z.record(z.string(), DocumentManifestEntrySchema);
|
|
23
|
+
function documentFileUrl(documentId, filename, opts = {}) {
|
|
24
|
+
const base = `/api/document-file/${documentId}/${encodeURIComponent(filename)}`;
|
|
25
|
+
return opts.download ? `${base}?download=1` : base;
|
|
26
|
+
}
|
|
27
|
+
function documentGitPath(slugName, hash, kind) {
|
|
28
|
+
return `assets/documents/${slugName}-${hash}/original.${kind}`;
|
|
29
|
+
}
|
|
30
|
+
function documentBucketPath(documentId, kind) {
|
|
31
|
+
return `documents/${documentId}/original.${kind}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
DOCUMENT_MANIFEST_PATH,
|
|
36
|
+
DOCUMENT_GIT_MAX_BYTES,
|
|
37
|
+
DOCUMENT_BUCKET_MAX_BYTES,
|
|
38
|
+
DOCUMENT_MIME_TO_EXT,
|
|
39
|
+
DOCUMENT_KIND_TO_MIME,
|
|
40
|
+
DocumentManifestEntrySchema,
|
|
41
|
+
DocumentManifestSchema,
|
|
42
|
+
documentFileUrl,
|
|
43
|
+
documentGitPath,
|
|
44
|
+
documentBucketPath
|
|
45
|
+
};
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
upgradeLegacySection
|
|
6
6
|
} from "./chunk-5BM2Y3NJ.js";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
} from "./chunk-
|
|
8
|
+
NavEntrySchema
|
|
9
|
+
} from "./chunk-REDDTTGJ.js";
|
|
10
10
|
import {
|
|
11
11
|
getSectionSchema
|
|
12
12
|
} from "./chunk-TZQPOR5A.js";
|
|
@@ -153,13 +153,23 @@ function safeRedirect(url, fallback) {
|
|
|
153
153
|
|
|
154
154
|
// src/lib/loader.ts
|
|
155
155
|
function parseNavFile(navFile) {
|
|
156
|
-
if (!navFile) return [];
|
|
157
|
-
const
|
|
158
|
-
if (!
|
|
156
|
+
if (!navFile) return { entries: [], degraded: false };
|
|
157
|
+
const rawEntries = navFile.entries;
|
|
158
|
+
if (!Array.isArray(rawEntries)) {
|
|
159
159
|
console.warn("Invalid nav.json, falling back to a flat navigation");
|
|
160
|
-
return [];
|
|
160
|
+
return { entries: [], degraded: true };
|
|
161
161
|
}
|
|
162
|
-
|
|
162
|
+
const entries = [];
|
|
163
|
+
let dropped = 0;
|
|
164
|
+
for (const raw of rawEntries) {
|
|
165
|
+
const result = NavEntrySchema.safeParse(raw);
|
|
166
|
+
if (result.success) entries.push(result.data);
|
|
167
|
+
else dropped++;
|
|
168
|
+
}
|
|
169
|
+
if (dropped > 0) {
|
|
170
|
+
console.warn(`nav.json: dropped ${dropped} entr${dropped === 1 ? "y" : "ies"} this package version cannot represent; navigation is degraded`);
|
|
171
|
+
}
|
|
172
|
+
return { entries, degraded: dropped > 0 };
|
|
163
173
|
}
|
|
164
174
|
function mergeSiteContent(index, sectionFiles, navFile) {
|
|
165
175
|
const sections = [];
|
|
@@ -192,7 +202,8 @@ function mergeSiteContent(index, sectionFiles, navFile) {
|
|
|
192
202
|
sections.push({ section: raw, meta });
|
|
193
203
|
}
|
|
194
204
|
}
|
|
195
|
-
|
|
205
|
+
const nav = parseNavFile(navFile);
|
|
206
|
+
return { sections, index: { ...index, nav: nav.entries }, navDegraded: nav.degraded };
|
|
196
207
|
}
|
|
197
208
|
function loadStaticSiteContent(index, sectionGlob, navFile) {
|
|
198
209
|
const sectionFiles = {};
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
brandGuideSectionDefs,
|
|
3
|
+
duplicateChildAt,
|
|
4
|
+
isSpacer,
|
|
5
|
+
occupiedColumns,
|
|
3
6
|
pluralize,
|
|
7
|
+
removeChildAt,
|
|
8
|
+
setChildColSpan,
|
|
4
9
|
stripHtmlToPlainText,
|
|
10
|
+
trimTrailingSpacers,
|
|
5
11
|
truncate
|
|
6
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-72FMQQIA.js";
|
|
7
13
|
import {
|
|
8
14
|
DeleteButton,
|
|
9
15
|
DragHandle,
|
|
@@ -17,7 +23,7 @@ import {
|
|
|
17
23
|
buildBlockDropData,
|
|
18
24
|
canDropBlock,
|
|
19
25
|
isBlockDragData
|
|
20
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-LBHQWIVL.js";
|
|
21
27
|
import {
|
|
22
28
|
EditableRichText,
|
|
23
29
|
defineHeadingSection
|
|
@@ -717,64 +723,6 @@ function useBlockDropZone({ containerId, index, toColumn, allowedEdges, enabled
|
|
|
717
723
|
return { dropRef, closestEdge };
|
|
718
724
|
}
|
|
719
725
|
|
|
720
|
-
// src/lib/container-ops.ts
|
|
721
|
-
function getContainerChildren(block) {
|
|
722
|
-
const content = block.content;
|
|
723
|
-
return Array.isArray(content?.children) ? content.children : [];
|
|
724
|
-
}
|
|
725
|
-
function withChildren(container, children) {
|
|
726
|
-
return { ...container, content: { ...container.content, children } };
|
|
727
|
-
}
|
|
728
|
-
function containerColumns(container) {
|
|
729
|
-
const n = container.content?.columns;
|
|
730
|
-
return typeof n === "number" && n >= 1 ? n : 1;
|
|
731
|
-
}
|
|
732
|
-
function removeChildAt(container, index) {
|
|
733
|
-
const children = getContainerChildren(container);
|
|
734
|
-
if (index < 0 || index >= children.length) return { container, removed: null };
|
|
735
|
-
const next = [...children];
|
|
736
|
-
const [removed] = next.splice(index, 1);
|
|
737
|
-
return { container: withChildren(container, next), removed };
|
|
738
|
-
}
|
|
739
|
-
function duplicateChildAt(container, index, newId2) {
|
|
740
|
-
const children = getContainerChildren(container);
|
|
741
|
-
if (index < 0 || index >= children.length) return container;
|
|
742
|
-
const clone = { ...JSON.parse(JSON.stringify(children[index])), id: newId2() };
|
|
743
|
-
const next = [...children];
|
|
744
|
-
next.splice(index + 1, 0, clone);
|
|
745
|
-
return withChildren(container, next);
|
|
746
|
-
}
|
|
747
|
-
function setChildColSpan(container, index, span) {
|
|
748
|
-
const children = getContainerChildren(container);
|
|
749
|
-
if (index < 0 || index >= children.length) return container;
|
|
750
|
-
const clamped = Math.max(1, Math.min(span, containerColumns(container)));
|
|
751
|
-
const next = children.map((child, i) => {
|
|
752
|
-
if (i !== index) return child;
|
|
753
|
-
if (clamped <= 1) {
|
|
754
|
-
const { layout: _drop, ...rest } = child;
|
|
755
|
-
return rest;
|
|
756
|
-
}
|
|
757
|
-
return { ...child, layout: { ...child.layout, colSpan: clamped } };
|
|
758
|
-
});
|
|
759
|
-
return withChildren(container, next);
|
|
760
|
-
}
|
|
761
|
-
function effectiveSpan(child, columns) {
|
|
762
|
-
return isSpacer(child) ? 1 : Math.min(child.layout?.colSpan ?? 1, columns);
|
|
763
|
-
}
|
|
764
|
-
function isSpacer(child) {
|
|
765
|
-
return child.type === "spacer";
|
|
766
|
-
}
|
|
767
|
-
function occupiedColumns(children, columns) {
|
|
768
|
-
return children.reduce((sum, c) => sum + effectiveSpan(c, columns), 0);
|
|
769
|
-
}
|
|
770
|
-
function trimTrailingSpacers(container) {
|
|
771
|
-
const children = getContainerChildren(container);
|
|
772
|
-
let end = children.length;
|
|
773
|
-
while (end > 0 && isSpacer(children[end - 1])) end--;
|
|
774
|
-
if (end === children.length) return container;
|
|
775
|
-
return withChildren(container, children.slice(0, end));
|
|
776
|
-
}
|
|
777
|
-
|
|
778
726
|
// src/components/sections/Container/Container.tsx
|
|
779
727
|
import { jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
780
728
|
var ROW_EDGES = ["left", "right"];
|