@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.
Files changed (138) hide show
  1. package/dist/{chunk-EUSWEVOA.js → chunk-3TO4RRHY.js} +12 -1
  2. package/dist/{chunk-KP4DWTPR.js → chunk-72FMQQIA.js} +246 -3
  3. package/dist/chunk-BS5AQHZG.js +45 -0
  4. package/dist/{chunk-NA5EJM6Z.js → chunk-CZLYECHC.js} +19 -8
  5. package/dist/{chunk-HKHEAH5F.js → chunk-GOCFTXR3.js} +8 -60
  6. package/dist/{chunk-GYCBWGVW.js → chunk-LBHQWIVL.js} +79 -24
  7. package/dist/{chunk-HJSE6SK5.js → chunk-REDDTTGJ.js} +3 -3
  8. package/dist/collab/rebase.d.ts.map +1 -1
  9. package/dist/collab/rebase.js +3 -1
  10. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  11. package/dist/components/docfile/DocFileOverlay.d.ts +12 -0
  12. package/dist/components/docfile/DocFileOverlay.d.ts.map +1 -0
  13. package/dist/components/docfile/DocFilePane.d.ts +17 -0
  14. package/dist/components/docfile/DocFilePane.d.ts.map +1 -0
  15. package/dist/components/docfile/doc-file-state.d.ts +33 -0
  16. package/dist/components/docfile/doc-file-state.d.ts.map +1 -0
  17. package/dist/components/editor/SettingsForm.d.ts.map +1 -1
  18. package/dist/components/editor/index.js +1 -1
  19. package/dist/components/sections/Document/index.d.ts +18 -0
  20. package/dist/components/sections/Document/index.d.ts.map +1 -0
  21. package/dist/components/sections/all-sections.d.ts +10 -0
  22. package/dist/components/sections/all-sections.d.ts.map +1 -1
  23. package/dist/components/sections/brand-guide.d.ts +10 -0
  24. package/dist/components/sections/brand-guide.d.ts.map +1 -1
  25. package/dist/components/sections/brand-guide.js +3 -1
  26. package/dist/components/sections/register-schemas.js +5 -3
  27. package/dist/components/sections/register.js +5 -3
  28. package/dist/components/shared/DocumentSourceField.d.ts +13 -0
  29. package/dist/components/shared/DocumentSourceField.d.ts.map +1 -0
  30. package/dist/components/shared/Navigation.d.ts.map +1 -1
  31. package/dist/components/shell/EditorModal.d.ts.map +1 -1
  32. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  33. package/dist/components/shell/MediaBreadcrumb.d.ts.map +1 -1
  34. package/dist/components/shell/MediaFolderTile.d.ts +3 -1
  35. package/dist/components/shell/MediaFolderTile.d.ts.map +1 -1
  36. package/dist/components/shell/MediaFolderTree.d.ts +3 -0
  37. package/dist/components/shell/MediaFolderTree.d.ts.map +1 -1
  38. package/dist/components/shell/MediaLibraryContext.d.ts +18 -1
  39. package/dist/components/shell/MediaLibraryContext.d.ts.map +1 -1
  40. package/dist/components/shell/MediaLibraryModal.d.ts +21 -1
  41. package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
  42. package/dist/hooks/useDocumentUploads.d.ts +32 -0
  43. package/dist/hooks/useDocumentUploads.d.ts.map +1 -0
  44. package/dist/hooks/useEditorPublish.d.ts +23 -1
  45. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  46. package/dist/hooks/useMediaPipeline.d.ts +14 -1
  47. package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
  48. package/dist/hooks/useResolvedDocument.d.ts +12 -0
  49. package/dist/hooks/useResolvedDocument.d.ts.map +1 -0
  50. package/dist/index.js +60 -34
  51. package/dist/lib/block-move.d.ts.map +1 -1
  52. package/dist/lib/dexie.d.ts +11 -0
  53. package/dist/lib/dexie.d.ts.map +1 -1
  54. package/dist/lib/dexie.js +32 -0
  55. package/dist/lib/document-refs.d.ts +22 -0
  56. package/dist/lib/document-refs.d.ts.map +1 -0
  57. package/dist/lib/document-uploads.d.ts +38 -0
  58. package/dist/lib/document-uploads.d.ts.map +1 -0
  59. package/dist/lib/documents.d.ts +65 -0
  60. package/dist/lib/documents.d.ts.map +1 -0
  61. package/dist/lib/index-ops.d.ts +1 -0
  62. package/dist/lib/index-ops.d.ts.map +1 -1
  63. package/dist/lib/index-ops.js +13 -1
  64. package/dist/lib/index.js +6 -6
  65. package/dist/lib/loader.d.ts +6 -0
  66. package/dist/lib/loader.d.ts.map +1 -1
  67. package/dist/lib/media-folders.d.ts +8 -0
  68. package/dist/lib/media-folders.d.ts.map +1 -1
  69. package/dist/lib/media-folders.js +2 -0
  70. package/dist/lib/nav.d.ts +29 -1
  71. package/dist/lib/nav.d.ts.map +1 -1
  72. package/dist/lib/pages.d.ts +18 -0
  73. package/dist/lib/pages.d.ts.map +1 -1
  74. package/dist/lib/platform-broker.d.ts +12 -0
  75. package/dist/lib/platform-broker.d.ts.map +1 -1
  76. package/dist/lib/platform-broker.js +12 -3
  77. package/dist/lib/registry.d.ts +10 -0
  78. package/dist/lib/registry.d.ts.map +1 -1
  79. package/dist/lib/save-chunks.d.ts +15 -0
  80. package/dist/lib/save-chunks.d.ts.map +1 -1
  81. package/dist/lib/scroll-lock.d.ts +2 -0
  82. package/dist/lib/scroll-lock.d.ts.map +1 -0
  83. package/dist/schemas/documents.d.ts +80 -0
  84. package/dist/schemas/documents.d.ts.map +1 -0
  85. package/dist/schemas/documents.js +25 -0
  86. package/dist/schemas/index.d.ts +1 -0
  87. package/dist/schemas/index.d.ts.map +1 -1
  88. package/dist/schemas/index.js +24 -2
  89. package/dist/storage/index.d.ts +2 -2
  90. package/dist/storage/index.d.ts.map +1 -1
  91. package/dist/storage/index.js +5 -1
  92. package/dist/storage/types.d.ts +69 -5
  93. package/dist/storage/types.d.ts.map +1 -1
  94. package/dist/types/database.d.ts +14 -0
  95. package/dist/types/database.d.ts.map +1 -1
  96. package/package.json +5 -1
  97. package/src/collab/rebase.ts +15 -0
  98. package/src/components/chat/ChatPanel.tsx +5 -4
  99. package/src/components/docfile/DocFileOverlay.tsx +54 -0
  100. package/src/components/docfile/DocFilePane.tsx +129 -0
  101. package/src/components/docfile/doc-file-state.ts +180 -0
  102. package/src/components/editor/SettingsForm.tsx +10 -0
  103. package/src/components/sections/Document/index.tsx +163 -0
  104. package/src/components/sections/brand-guide.ts +2 -1
  105. package/src/components/shared/DocumentSourceField.tsx +51 -0
  106. package/src/components/shared/Navigation.tsx +53 -10
  107. package/src/components/shell/EditorModal.tsx +2 -5
  108. package/src/components/shell/EditorShell.tsx +154 -10
  109. package/src/components/shell/MediaBreadcrumb.tsx +14 -1
  110. package/src/components/shell/MediaFolderTile.tsx +4 -2
  111. package/src/components/shell/MediaFolderTree.tsx +20 -3
  112. package/src/components/shell/MediaLibraryContext.tsx +18 -1
  113. package/src/components/shell/MediaLibraryModal.tsx +223 -45
  114. package/src/hooks/useDocumentUploads.ts +330 -0
  115. package/src/hooks/useEditorPublish.ts +197 -11
  116. package/src/hooks/useMediaPipeline.ts +136 -5
  117. package/src/hooks/useResolvedDocument.ts +25 -0
  118. package/src/lib/block-move.ts +15 -4
  119. package/src/lib/dexie.ts +54 -0
  120. package/src/lib/document-refs.ts +83 -0
  121. package/src/lib/document-uploads.ts +66 -0
  122. package/src/lib/documents.ts +138 -0
  123. package/src/lib/index-ops.ts +16 -0
  124. package/src/lib/loader.ts +32 -11
  125. package/src/lib/media-folders.ts +9 -0
  126. package/src/lib/nav.ts +46 -2
  127. package/src/lib/pages.ts +48 -0
  128. package/src/lib/platform-broker.ts +18 -3
  129. package/src/lib/registry.ts +9 -0
  130. package/src/lib/save-chunks.ts +42 -0
  131. package/src/lib/scroll-lock.ts +27 -0
  132. package/src/schemas/documents.ts +82 -0
  133. package/src/schemas/index.ts +1 -0
  134. package/src/schemas/nav.ts +3 -3
  135. package/src/storage/index.ts +2 -2
  136. package/src/storage/types.ts +71 -5
  137. package/src/types/database.ts +14 -0
  138. /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 g = parseInt(h.substring(2, 4), 16);
71
+ const g2 = parseInt(h.substring(2, 4), 16);
69
72
  const b = parseInt(h.substring(4, 6), 16);
70
- const yiq = (r * 299 + g * 587 + b * 114) / 1e3;
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
- NavFileSchema
9
- } from "./chunk-HJSE6SK5.js";
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 result = NavFileSchema.safeParse(navFile);
158
- if (!result.success) {
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
- return result.data.entries;
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
- return { sections, index: { ...index, nav: parseNavFile(navFile) } };
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-KP4DWTPR.js";
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-GYCBWGVW.js";
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"];