camox 0.65.1 → 0.67.0

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 (42) hide show
  1. package/dist/features/canvas/CamoxCanvas.js +195 -173
  2. package/dist/features/canvas/canvasFrameCapture.js +5 -12
  3. package/dist/features/canvas/canvasFrameDocument.js +90 -29
  4. package/dist/features/canvas/canvasItems.js +22 -6
  5. package/dist/features/canvas/sidebar/ContentSidebar.js +19 -21
  6. package/dist/features/canvas/sidebar/LayoutPageOverview.js +22 -49
  7. package/dist/features/canvas/sidebar/LayoutPageSeo.js +73 -76
  8. package/dist/features/canvas/sidebar/PageInspector.js +61 -50
  9. package/dist/features/canvas/sidebar/PageInspectorSkeleton.js +4 -4
  10. package/dist/features/canvas/useCanvasCamera.js +22 -5
  11. package/dist/features/content/components/MissingFromLocale.js +1 -1
  12. package/dist/features/page/UnplacedLayoutContent.js +141 -0
  13. package/dist/features/preview/components/ItemFieldsEditor.js +50 -44
  14. package/dist/features/preview/components/PageInfo.js +103 -100
  15. package/dist/features/preview/components/SelectionEditor.js +284 -231
  16. package/dist/features/preview/components/contentFieldSchema.js +5 -1
  17. package/dist/features/runtime/RuntimeChrome.js +66 -40
  18. package/dist/features/runtime/pageApp.js +24 -10
  19. package/dist/features/runtime/runtime.d.ts +13 -0
  20. package/dist/features/runtime/runtime.js +58 -2
  21. package/dist/features/studio/components/AgentSidebar.js +3 -3
  22. package/dist/features/studio/components/ChatWidget.js +34 -29
  23. package/dist/features/studio/components/ContentFindings.js +397 -0
  24. package/dist/features/studio/components/DraftsControl.js +172 -159
  25. package/dist/features/studio/components/Patrol.js +449 -426
  26. package/dist/features/studio/components/ReviewDraftSheet.js +231 -192
  27. package/dist/features/studio/components/Squareling.js +0 -9
  28. package/dist/features/studio/components/ThreadComposer.js +183 -121
  29. package/dist/features/studio/components/ThreadMessages.js +19 -11
  30. package/dist/features/studio/components/UnnamedDraftBar.js +349 -0
  31. package/dist/features/studio/findingSentence.js +3 -5
  32. package/dist/features/studio/patrollerBio.js +39 -0
  33. package/dist/features/studio/reportSentence.js +0 -5
  34. package/dist/features/studio/studioStore.js +13 -0
  35. package/dist/features/studio/workingSentence.js +2 -11
  36. package/dist/lib/revisions.js +25 -3
  37. package/dist/lib/use-thread.js +1 -1
  38. package/dist/package.js +1 -1
  39. package/dist/studio.css +1 -1
  40. package/package.json +4 -4
  41. package/dist/features/canvas/sidebar/DerivedPageInspector.js +0 -49
  42. package/dist/features/canvas/sidebar/SingletonPageInspector.js +0 -39
@@ -14,24 +14,83 @@ function studioStyle(doc, css) {
14
14
  style.textContent = css;
15
15
  return style;
16
16
  }
17
- /** Set by the camera on elements that hold Canvas frames: see `canvasBlockOverlap`. */
18
- const BLOCK_OVERLAP_ATTRIBUTE = "data-canvas-block-overlap";
17
+ /** Set by the camera on elements that hold Canvas frames: see `canvasSeamCover`. */
18
+ const SEAM_COVER_ATTRIBUTE = "data-canvas-seam-cover";
19
19
  const BLOCK = "[data-camox-viewport-block]";
20
- /** Every block after the first, in its container or a later one, covers the end of the one before. */
21
- const BLOCK_OVERLAP_SELECTOR = `:is(${BLOCK}, :has(${BLOCK})) ~ ${BLOCK}, :is(${BLOCK}, :has(${BLOCK})) ~ * ${BLOCK}`;
22
- const BLOCK_OVERLAP_STYLE = `${BLOCK_OVERLAP_SELECTOR} { margin-top: calc(-1 * var(--camox-block-overlap, 0px)); }`;
20
+ /** Set on a block whose bottom edge needs covering, to the color to cover it in. */
21
+ const SEAM_COLOR_PROPERTY = "--camox-seam-color";
23
22
  /**
24
- * How far, in CSS pixels, each block in a Canvas frame overlaps the one before it.
25
- * Where two blocks meet partway through a screen pixel, each covers only part of
26
- * it, and whatever is under both (the site's background, often unlike either
27
- * block) shows through as a light seam. Zoomed out, an overlap of at least a
28
- * device pixel covers it, at the cost of about as much of a block's bottom edge. From
29
- * 100%, where seams are rare, borders stay exact. Powers of two change a page's
30
- * height only at a few zooms.
23
+ * A band in a block's seam color across its bottom edge, from `--camox-seam-cover` above it to
24
+ * as far below. It's the block's border image, which it doesn't otherwise have: that paints
25
+ * under the block's content and under the next block, and moves nothing.
31
26
  */
32
- function canvasBlockOverlap(scale, pixelRatio) {
33
- if (scale >= 1) return 0;
34
- return 2 ** Math.max(0, Math.ceil(Math.log2(1 / (scale * pixelRatio))));
27
+ const SEAM_STYLE = `${BLOCK}[style*="${SEAM_COLOR_PROPERTY}"] { border-image: linear-gradient(var(${SEAM_COLOR_PROPERTY}), var(${SEAM_COLOR_PROPERTY})) 0 0 1 0 / 0 0 calc(2 * var(--camox-seam-cover, 0px)) 0 / 0 0 var(--camox-seam-cover, 0px) 0 stretch; }`;
28
+ /**
29
+ * How far, in CSS pixels, the band under each seam between blocks in a Canvas frame
30
+ * reaches to either side of it. Where two blocks meet partway through a screen pixel,
31
+ * each covers only part of it, and whatever is under both (the site's background,
32
+ * often unlike either block) shows through as a light seam. A band in the blocks'
33
+ * color under that pixel covers it. Chromium rasters layers at scales slightly off the
34
+ * camera's, so the band reaches three device pixels: fewer leave some seams.
35
+ */
36
+ function canvasSeamCover(scale, pixelRatio) {
37
+ return 3 / (scale * pixelRatio);
38
+ }
39
+ /**
40
+ * Gives each block a seam color where it meets the next one and both paint their side of
41
+ * the edge, so that the band under the edge hides the seam (see `SEAM_STYLE`). Where
42
+ * either side is see-through, nothing shows through the edge but what's already there,
43
+ * and a band would show.
44
+ */
45
+ function colorSeams(doc) {
46
+ const view = doc.defaultView;
47
+ if (!view || !doc.elementsFromPoint) return;
48
+ const blocks = Array.from(doc.querySelectorAll(BLOCK));
49
+ blocks.forEach((block, index) => {
50
+ const next = blocks[index + 1];
51
+ const color = next ? seamColor(view, block, next) : null;
52
+ if (color) {
53
+ if (block.style.getPropertyValue(SEAM_COLOR_PROPERTY) !== color) block.style.setProperty(SEAM_COLOR_PROPERTY, color);
54
+ } else if (block.style.getPropertyValue(SEAM_COLOR_PROPERTY)) block.style.removeProperty(SEAM_COLOR_PROPERTY);
55
+ });
56
+ }
57
+ function seamColor(view, above, below) {
58
+ const top = above.getBoundingClientRect();
59
+ const bottom = below.getBoundingClientRect();
60
+ if (Math.abs(top.bottom - bottom.top) > 1) return null;
61
+ const x = (Math.max(top.left, bottom.left) + Math.min(top.right, bottom.right)) / 2;
62
+ const aboveColor = paintAt(view, above, x, top.bottom - .5);
63
+ const belowColor = paintAt(view, below, x, bottom.top + .5);
64
+ if (aboveColor === null || belowColor === null) return null;
65
+ return aboveColor || belowColor || null;
66
+ }
67
+ const PAINTED_ELEMENTS = /* @__PURE__ */ new Set([
68
+ "img",
69
+ "picture",
70
+ "video",
71
+ "canvas",
72
+ "svg",
73
+ "iframe"
74
+ ]);
75
+ /**
76
+ * What a block paints at a point: `null` where nothing does, its background color, or an
77
+ * empty string for an image or other painting of no one color.
78
+ */
79
+ function paintAt(view, block, x, y) {
80
+ for (const element of block.ownerDocument.elementsFromPoint(x, y)) {
81
+ if (!block.contains(element)) continue;
82
+ const style = view.getComputedStyle(element);
83
+ const color = isTransparent(style.backgroundColor) ? "" : style.backgroundColor;
84
+ if (style.backgroundImage && style.backgroundImage !== "none" || PAINTED_ELEMENTS.has(element.localName)) return color;
85
+ if (color) return color;
86
+ }
87
+ return null;
88
+ }
89
+ /** Whether a computed color is fully transparent: only an alpha of 0 is. */
90
+ function isTransparent(color) {
91
+ if (!color || color === "transparent") return true;
92
+ const alpha = /^rgba\(.*,\s*([\d.]+)\)$/.exec(color)?.[1] ?? /\/\s*([\d.]+)%?\s*\)$/.exec(color)?.[1];
93
+ return alpha !== void 0 && parseFloat(alpha) === 0;
35
94
  }
36
95
  function canvasPageHref(input) {
37
96
  return new URL(`${input.runtimeBasePath.replace(/\/$/, "")}/${input.pathname.replace(/^\//, "")}`, input.href).href;
@@ -207,19 +266,19 @@ function observeCanvasDocument(iframe, root, viewportHeight, suspended = () => f
207
266
  doc.documentElement.style.setProperty("--camox-viewport-height", `${baseline}px`);
208
267
  doc.documentElement.style.setProperty("overflow", "hidden", "important");
209
268
  doc.body.style.setProperty("overflow", "hidden", "important");
210
- const overlapStyle = studioStyle(doc, BLOCK_OVERLAP_STYLE);
211
- doc.head.appendChild(overlapStyle);
212
- const followOverlap = () => {
213
- const overlap = iframe.closest(`[${BLOCK_OVERLAP_ATTRIBUTE}]`);
214
- const pixels = Number(overlap?.getAttribute(BLOCK_OVERLAP_ATTRIBUTE)) || 0;
215
- doc.documentElement.style.setProperty("--camox-block-overlap", `${pixels}px`);
269
+ const seamStyle = studioStyle(doc, SEAM_STYLE);
270
+ doc.head.appendChild(seamStyle);
271
+ const followSeamCover = () => {
272
+ const holder = iframe.closest(`[${SEAM_COVER_ATTRIBUTE}]`);
273
+ const pixels = Number(holder?.getAttribute(SEAM_COVER_ATTRIBUTE)) || 0;
274
+ doc.documentElement.style.setProperty("--camox-seam-cover", `${pixels}px`);
216
275
  };
217
- followOverlap();
218
- const overlapChanges = new MutationObserver(followOverlap);
219
- overlapChanges.observe(iframe.ownerDocument.documentElement, {
276
+ followSeamCover();
277
+ const seamCoverChanges = new MutationObserver(followSeamCover);
278
+ seamCoverChanges.observe(iframe.ownerDocument.documentElement, {
220
279
  subtree: true,
221
280
  attributes: true,
222
- attributeFilter: [BLOCK_OVERLAP_ATTRIBUTE]
281
+ attributeFilter: [SEAM_COVER_ATTRIBUTE]
223
282
  });
224
283
  let frame = 0;
225
284
  let disposed = false;
@@ -235,6 +294,7 @@ function observeCanvasDocument(iframe, root, viewportHeight, suspended = () => f
235
294
  frame = 0;
236
295
  if (suspended()) return;
237
296
  measureCanvasDocument(iframe, root, baseline);
297
+ colorSeams(doc);
238
298
  const elements = /* @__PURE__ */ new Set([
239
299
  doc.body,
240
300
  root,
@@ -295,9 +355,10 @@ function observeCanvasDocument(iframe, root, viewportHeight, suspended = () => f
295
355
  cancelAnimationFrame(frame);
296
356
  resize.disconnect();
297
357
  mutations.disconnect();
298
- overlapChanges.disconnect();
299
- overlapStyle.remove();
300
- doc.documentElement.style.removeProperty("--camox-block-overlap");
358
+ seamCoverChanges.disconnect();
359
+ seamStyle.remove();
360
+ doc.documentElement.style.removeProperty("--camox-seam-cover");
361
+ for (const block of doc.querySelectorAll(BLOCK)) block.style.removeProperty(SEAM_COLOR_PROPERTY);
301
362
  doc.removeEventListener("load", contentChanged, true);
302
363
  doc.removeEventListener("error", contentChanged, true);
303
364
  doc.fonts?.removeEventListener("loadingdone", contentChanged);
@@ -306,4 +367,4 @@ function observeCanvasDocument(iframe, root, viewportHeight, suspended = () => f
306
367
  }
307
368
 
308
369
  //#endregion
309
- export { BLOCK_OVERLAP_SELECTOR, adaptCanvasStyleSheets, adoptCanvasDocument, canvasBlockOverlap, canvasPageHref, createCanvasDocument, logicalViewportValue, measureCanvasDocument, observeCanvasDocument, pauseCanvasDocument };
370
+ export { adaptCanvasStyleSheets, adoptCanvasDocument, canvasPageHref, canvasSeamCover, createCanvasDocument, logicalViewportValue, measureCanvasDocument, observeCanvasDocument, pauseCanvasDocument };
@@ -1,21 +1,37 @@
1
+ import { fitCanvasPage } from "./canvasCamera.js";
1
2
  import { CANVAS_DEVICES } from "./canvasPages.js";
2
3
 
3
4
  //#region src/features/canvas/canvasItems.ts
4
- const CANVAS_ITEM_GAP = 240;
5
5
  const CANVAS_SLOT_WIDTH = CANVAS_DEVICES.desktop.width;
6
+ /** World-space bounds of the gap, so very narrow or wide canvases still space Pages alike. */
7
+ const MIN_CANVAS_ITEM_GAP = 96;
8
+ const MAX_CANVAS_ITEM_GAP = 320;
9
+ /**
10
+ * The world-space gap between Pages that, with a Page snapped, starts the next one halfway
11
+ * across the sidebar laid over the working area's edge. The snapped zoom follows the working
12
+ * area's width, so the gap does too.
13
+ */
14
+ function canvasItemGap(workingArea, sidebarWidth) {
15
+ const fit = fitCanvasPage(workingArea, {
16
+ left: 0,
17
+ width: CANVAS_SLOT_WIDTH
18
+ });
19
+ const gap = ((workingArea.width - CANVAS_SLOT_WIDTH * fit.scale) / 2 + sidebarWidth / 2) / fit.scale;
20
+ return Math.min(320, Math.max(96, gap));
21
+ }
6
22
  /**
7
23
  * World-space positions of the Canvas row, matching its flex layout: every Page
8
- * side by side, in Canvas order.
24
+ * side by side, in Canvas order, a gap apart.
9
25
  */
10
- function positionCanvasPages(pages) {
26
+ function positionCanvasPages(pages, gap) {
11
27
  return {
12
28
  items: pages.map((page, index) => ({
13
29
  key: page.key,
14
30
  page,
15
- left: index * (CANVAS_SLOT_WIDTH + 240),
31
+ left: index * (CANVAS_SLOT_WIDTH + gap),
16
32
  width: CANVAS_SLOT_WIDTH
17
33
  })),
18
- width: Math.max(0, pages.length * (CANVAS_SLOT_WIDTH + 240) - 240)
34
+ width: Math.max(0, pages.length * (CANVAS_SLOT_WIDTH + gap) - gap)
19
35
  };
20
36
  }
21
37
  function canvasSnapTargets(items) {
@@ -27,4 +43,4 @@ function canvasSnapTargets(items) {
27
43
  }
28
44
 
29
45
  //#endregion
30
- export { CANVAS_SLOT_WIDTH, canvasSnapTargets, positionCanvasPages };
46
+ export { CANVAS_SLOT_WIDTH, canvasItemGap, canvasSnapTargets, positionCanvasPages };
@@ -13,8 +13,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
13
13
  * Navigator, then the Canvas Inspector of the selected Page laid over it, if any.
14
14
  */
15
15
  function ContentSidebar(t0) {
16
- const $ = c(16);
17
- const { page, navigator, onShowWholeCanvas, owner: t1, pageRecord, runtimeBasePath } = t0;
16
+ const $ = c(15);
17
+ const { page, navigator, onShowWholeCanvas, owner: t1, runtimeBasePath } = t0;
18
18
  const owner = t1 === void 0 ? null : t1;
19
19
  const t2 = page?.title ?? "Canvas navigator";
20
20
  const t3 = page != null;
@@ -29,11 +29,10 @@ function ContentSidebar(t0) {
29
29
  $[2] = t4;
30
30
  } else t4 = $[2];
31
31
  let t5;
32
- if ($[3] !== navigator || $[4] !== owner || $[5] !== page || $[6] !== pageRecord || $[7] !== runtimeBasePath) {
32
+ if ($[3] !== navigator || $[4] !== owner || $[5] !== page || $[6] !== runtimeBasePath) {
33
33
  t5 = page ? /* @__PURE__ */ jsx(PageInspector, {
34
34
  page,
35
35
  owner,
36
- pageRecord,
37
36
  runtimeBasePath
38
37
  }) : /* @__PURE__ */ jsx(SidebarStackView, {
39
38
  depth: 0,
@@ -43,32 +42,31 @@ function ContentSidebar(t0) {
43
42
  $[3] = navigator;
44
43
  $[4] = owner;
45
44
  $[5] = page;
46
- $[6] = pageRecord;
47
- $[7] = runtimeBasePath;
48
- $[8] = t5;
49
- } else t5 = $[8];
45
+ $[6] = runtimeBasePath;
46
+ $[7] = t5;
47
+ } else t5 = $[7];
50
48
  let t6;
51
- if ($[9] !== t4 || $[10] !== t5) {
49
+ if ($[8] !== t4 || $[9] !== t5) {
52
50
  t6 = /* @__PURE__ */ jsxs(SidebarStack, { children: [t4, t5] });
53
- $[9] = t4;
54
- $[10] = t5;
55
- $[11] = t6;
56
- } else t6 = $[11];
51
+ $[8] = t4;
52
+ $[9] = t5;
53
+ $[10] = t6;
54
+ } else t6 = $[10];
57
55
  let t7;
58
- if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
56
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
59
57
  t7 = /* @__PURE__ */ jsx(CreatePageModal, {});
60
- $[12] = t7;
61
- } else t7 = $[12];
58
+ $[11] = t7;
59
+ } else t7 = $[11];
62
60
  let t8;
63
- if ($[13] !== t2 || $[14] !== t6) {
61
+ if ($[12] !== t2 || $[13] !== t6) {
64
62
  t8 = /* @__PURE__ */ jsxs(ContentSidebarFrame, {
65
63
  label: t2,
66
64
  children: [t6, t7]
67
65
  });
68
- $[13] = t2;
69
- $[14] = t6;
70
- $[15] = t8;
71
- } else t8 = $[15];
66
+ $[12] = t2;
67
+ $[13] = t6;
68
+ $[14] = t8;
69
+ } else t8 = $[14];
72
70
  return t8;
73
71
  }
74
72
 
@@ -5,16 +5,15 @@ import { LayoutPageBlocks } from "./LayoutPageBlocks.js";
5
5
  import { LayoutPageSeo } from "./LayoutPageSeo.js";
6
6
  import { c } from "react/compiler-runtime";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
- import { Alert, AlertDescription, AlertTitle } from "@camox/ui/alert";
9
8
 
10
9
  //#region src/features/canvas/sidebar/LayoutPageOverview.tsx
11
10
  /**
12
- * A layout page's overview: its layout's blocks, then a notice, which a singleton and a
13
- * derived page word for themselves, then its SEO and Markdown, which its code builds.
11
+ * A singleton or derived page's overview: its layout's blocks, then its SEO and Markdown, which
12
+ * its code builds.
14
13
  */
15
14
  function LayoutPageOverview(t0) {
16
- const $ = c(20);
17
- const { layoutId, notice, target } = t0;
15
+ const $ = c(10);
16
+ const { layoutId, target } = t0;
18
17
  const projectUuid = useProjectUuid();
19
18
  let t1;
20
19
  if ($[0] !== layoutId || $[1] !== projectUuid) {
@@ -29,59 +28,33 @@ function LayoutPageOverview(t0) {
29
28
  const layout = useRead(t1);
30
29
  let t2;
31
30
  if ($[3] !== layout) {
32
- t2 = /* @__PURE__ */ jsx(LayoutPageBlocks, { layout });
31
+ t2 = /* @__PURE__ */ jsx("div", {
32
+ className: "px-2 pt-5",
33
+ children: /* @__PURE__ */ jsx(LayoutPageBlocks, { layout })
34
+ });
33
35
  $[3] = layout;
34
36
  $[4] = t2;
35
37
  } else t2 = $[4];
36
38
  let t3;
37
- if ($[5] !== notice.title) {
38
- t3 = /* @__PURE__ */ jsx(AlertTitle, { children: notice.title });
39
- $[5] = notice.title;
40
- $[6] = t3;
41
- } else t3 = $[6];
42
- let t4;
43
- if ($[7] !== notice.description) {
44
- t4 = /* @__PURE__ */ jsx(AlertDescription, { children: notice.description });
45
- $[7] = notice.description;
46
- $[8] = t4;
47
- } else t4 = $[8];
48
- let t5;
49
- if ($[9] !== t3 || $[10] !== t4) {
50
- t5 = /* @__PURE__ */ jsxs(Alert, { children: [t3, t4] });
51
- $[9] = t3;
52
- $[10] = t4;
53
- $[11] = t5;
54
- } else t5 = $[11];
55
- let t6;
56
- if ($[12] !== t2 || $[13] !== t5) {
57
- t6 = /* @__PURE__ */ jsxs("div", {
58
- className: "flex flex-col gap-4 px-2 pt-5",
59
- children: [t2, t5]
60
- });
61
- $[12] = t2;
62
- $[13] = t5;
63
- $[14] = t6;
64
- } else t6 = $[14];
65
- let t7;
66
- if ($[15] !== target) {
67
- t7 = /* @__PURE__ */ jsx("div", {
39
+ if ($[5] !== target) {
40
+ t3 = /* @__PURE__ */ jsx("div", {
68
41
  className: "space-y-4 p-2 pt-4",
69
42
  children: /* @__PURE__ */ jsx(LayoutPageSeo, { target })
70
43
  });
71
- $[15] = target;
72
- $[16] = t7;
73
- } else t7 = $[16];
74
- let t8;
75
- if ($[17] !== t6 || $[18] !== t7) {
76
- t8 = /* @__PURE__ */ jsx(PageOverview, { children: /* @__PURE__ */ jsxs("div", {
44
+ $[5] = target;
45
+ $[6] = t3;
46
+ } else t3 = $[6];
47
+ let t4;
48
+ if ($[7] !== t2 || $[8] !== t3) {
49
+ t4 = /* @__PURE__ */ jsx(PageOverview, { children: /* @__PURE__ */ jsxs("div", {
77
50
  className: "flex min-h-0 flex-1 flex-col overflow-auto",
78
- children: [t6, t7]
51
+ children: [t2, t3]
79
52
  }) });
80
- $[17] = t6;
81
- $[18] = t7;
82
- $[19] = t8;
83
- } else t8 = $[19];
84
- return t8;
53
+ $[7] = t2;
54
+ $[8] = t3;
55
+ $[9] = t4;
56
+ } else t4 = $[9];
57
+ return t4;
85
58
  }
86
59
 
87
60
  //#endregion
@@ -2,6 +2,7 @@ import { useOptionalDraftScope } from "../../../lib/draft-scope.js";
2
2
  import { useLocation } from "../../navigation/navigation.js";
3
3
  import { useProjectUuid } from "../../../lib/auth.js";
4
4
  import { reads, useReadQuery } from "../../../lib/studio-reads.js";
5
+ import { useLatestRevision } from "../../../lib/revisions.js";
5
6
  import { pageImageUrl } from "../../og/pageImage.js";
6
7
  import { ShikiMarkdown } from "../../preview/components/ShikiMarkdown.js";
7
8
  import { PageDiscoverabilityButtons, PageMarkdownSheetFrame, PageSeoSheetFrame, SearchEnginePreview, SocialPreviewCard, SocialPreviewImage } from "../../preview/components/PageInfo.js";
@@ -105,7 +106,8 @@ function LayoutPageSeoContent(t0) {
105
106
  const { target } = t0;
106
107
  const projectUuid = useProjectUuid();
107
108
  const { pathname } = useLocation();
108
- const { scope } = useOptionalDraftScope();
109
+ const { scope, draftId } = useOptionalDraftScope();
110
+ const revision = useLatestRevision(draftId);
109
111
  let t1;
110
112
  if ($[0] !== pathname || $[1] !== projectUuid || $[2] !== target) {
111
113
  t1 = reads.canvasFrame({
@@ -148,67 +150,63 @@ function LayoutPageSeoContent(t0) {
148
150
  const { title, description } = t2;
149
151
  let t3;
150
152
  let t4;
151
- if ($[9] !== description || $[10] !== pathname || $[11] !== title) {
152
- const version = new URLSearchParams({ v: `${title}|${description}` });
153
- if ($[14] !== pathname) {
153
+ if ($[9] !== description || $[10] !== pathname || $[11] !== revision || $[12] !== title) {
154
+ const version = new URLSearchParams({ v: `${title}|${description}|${revision ?? ""}` });
155
+ if ($[15] !== pathname) {
154
156
  t3 = pageImageUrl({
155
157
  origin: "",
156
158
  path: pathname
157
159
  });
158
- $[14] = pathname;
159
- $[15] = t3;
160
- } else t3 = $[15];
160
+ $[15] = pathname;
161
+ $[16] = t3;
162
+ } else t3 = $[16];
161
163
  t4 = version.toString();
162
164
  $[9] = description;
163
165
  $[10] = pathname;
164
- $[11] = title;
165
- $[12] = t3;
166
- $[13] = t4;
166
+ $[11] = revision;
167
+ $[12] = title;
168
+ $[13] = t3;
169
+ $[14] = t4;
167
170
  } else {
168
- t3 = $[12];
169
- t4 = $[13];
171
+ t3 = $[13];
172
+ t4 = $[14];
170
173
  }
171
174
  const image = `${t3}&${t4}`;
172
175
  const origin = typeof window !== "undefined" ? window.location.origin : "";
173
176
  let t5;
174
- if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
175
- t5 = /* @__PURE__ */ jsxs(Alert, { children: [/* @__PURE__ */ jsx(AlertTitle, { children: "Set in code" }), /* @__PURE__ */ jsx(AlertDescription, { children: "This page’s title and description come from its layout’s code, built from the content it shows." })] });
176
- $[16] = t5;
177
- } else t5 = $[16];
178
- let t6;
179
177
  if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
180
- t6 = /* @__PURE__ */ jsx(Label, {
178
+ t5 = /* @__PURE__ */ jsx(Label, {
181
179
  htmlFor: "layout-page-title",
182
180
  children: "Page title"
183
181
  });
184
- $[17] = t6;
185
- } else t6 = $[17];
186
- let t7;
182
+ $[17] = t5;
183
+ } else t5 = $[17];
184
+ let t6;
187
185
  if ($[18] !== title) {
188
- t7 = /* @__PURE__ */ jsxs("div", {
186
+ t6 = /* @__PURE__ */ jsxs("div", {
189
187
  className: "space-y-2",
190
- children: [t6, /* @__PURE__ */ jsx(Input, {
188
+ children: [t5, /* @__PURE__ */ jsx(Input, {
191
189
  id: "layout-page-title",
192
190
  value: title,
193
191
  readOnly: true
194
192
  })]
195
193
  });
196
194
  $[18] = title;
197
- $[19] = t7;
198
- } else t7 = $[19];
199
- let t8;
195
+ $[19] = t6;
196
+ } else t6 = $[19];
197
+ let t7;
200
198
  if ($[20] === Symbol.for("react.memo_cache_sentinel")) {
201
- t8 = /* @__PURE__ */ jsx(Label, {
199
+ t7 = /* @__PURE__ */ jsx(Label, {
202
200
  htmlFor: "layout-page-description",
203
201
  children: "Page description"
204
202
  });
205
- $[20] = t8;
206
- } else t8 = $[20];
207
- let t9;
203
+ $[20] = t7;
204
+ } else t7 = $[20];
205
+ let t8;
208
206
  if ($[21] !== description) {
209
- t9 = /* @__PURE__ */ jsxs("div", {
207
+ t8 = /* @__PURE__ */ jsxs("div", {
210
208
  className: "space-y-2",
211
- children: [t8, /* @__PURE__ */ jsx(Textarea, {
209
+ children: [t7, /* @__PURE__ */ jsx(Textarea, {
212
210
  id: "layout-page-description",
213
211
  value: description,
214
212
  placeholder: "No description",
@@ -217,11 +215,11 @@ function LayoutPageSeoContent(t0) {
217
215
  })]
218
216
  });
219
217
  $[21] = description;
220
- $[22] = t9;
221
- } else t9 = $[22];
222
- let t10;
218
+ $[22] = t8;
219
+ } else t8 = $[22];
220
+ let t9;
223
221
  if ($[23] !== description || $[24] !== pathname || $[25] !== title) {
224
- t10 = /* @__PURE__ */ jsx(SearchEnginePreview, {
222
+ t9 = /* @__PURE__ */ jsx(SearchEnginePreview, {
225
223
  path: pathname,
226
224
  metaTitle: title,
227
225
  metaDescription: description
@@ -229,63 +227,62 @@ function LayoutPageSeoContent(t0) {
229
227
  $[23] = description;
230
228
  $[24] = pathname;
231
229
  $[25] = title;
232
- $[26] = t10;
233
- } else t10 = $[26];
234
- let t11;
230
+ $[26] = t9;
231
+ } else t9 = $[26];
232
+ let t10;
235
233
  if ($[27] === Symbol.for("react.memo_cache_sentinel")) {
236
- t11 = /* @__PURE__ */ jsx(Label, { children: "Social preview" });
237
- $[27] = t11;
238
- } else t11 = $[27];
239
- let t12;
234
+ t10 = /* @__PURE__ */ jsx(Label, { children: "Social preview" });
235
+ $[27] = t10;
236
+ } else t10 = $[27];
237
+ let t11;
240
238
  if ($[28] !== image || $[29] !== scope) {
241
- t12 = scope?.hrefFor(image) ?? image;
239
+ t11 = scope?.hrefFor(image) ?? image;
242
240
  $[28] = image;
243
241
  $[29] = scope;
244
- $[30] = t12;
245
- } else t12 = $[30];
246
- let t13;
247
- if ($[31] !== t12) {
248
- t13 = /* @__PURE__ */ jsx(SocialPreviewImage, { src: t12 });
249
- $[31] = t12;
250
- $[32] = t13;
251
- } else t13 = $[32];
252
- const t14 = `${origin}${pathname}`;
253
- let t15;
254
- if ($[33] !== description || $[34] !== t13 || $[35] !== t14 || $[36] !== title) {
255
- t15 = /* @__PURE__ */ jsxs("div", {
242
+ $[30] = t11;
243
+ } else t11 = $[30];
244
+ let t12;
245
+ if ($[31] !== t11) {
246
+ t12 = /* @__PURE__ */ jsx(SocialPreviewImage, { src: t11 });
247
+ $[31] = t11;
248
+ $[32] = t12;
249
+ } else t12 = $[32];
250
+ const t13 = `${origin}${pathname}`;
251
+ let t14;
252
+ if ($[33] !== description || $[34] !== t12 || $[35] !== t13 || $[36] !== title) {
253
+ t14 = /* @__PURE__ */ jsxs("div", {
256
254
  className: "space-y-2 pt-2",
257
- children: [t11, /* @__PURE__ */ jsx(SocialPreviewCard, {
258
- image: t13,
255
+ children: [t10, /* @__PURE__ */ jsx(SocialPreviewCard, {
256
+ image: t12,
259
257
  metaTitle: title,
260
258
  metaDescription: description,
261
- url: t14
259
+ url: t13
262
260
  })]
263
261
  });
264
262
  $[33] = description;
265
- $[34] = t13;
266
- $[35] = t14;
263
+ $[34] = t12;
264
+ $[35] = t13;
267
265
  $[36] = title;
268
- $[37] = t15;
269
- } else t15 = $[37];
270
- let t16;
271
- if ($[38] !== t10 || $[39] !== t15 || $[40] !== t7 || $[41] !== t9) {
272
- t16 = /* @__PURE__ */ jsxs("div", {
266
+ $[37] = t14;
267
+ } else t14 = $[37];
268
+ let t15;
269
+ if ($[38] !== t14 || $[39] !== t6 || $[40] !== t8 || $[41] !== t9) {
270
+ t15 = /* @__PURE__ */ jsxs("div", {
273
271
  className: "space-y-4",
274
272
  children: [
275
- t5,
276
- t7,
273
+ t6,
274
+ t8,
277
275
  t9,
278
- t10,
279
- t15
276
+ t14
280
277
  ]
281
278
  });
282
- $[38] = t10;
283
- $[39] = t15;
284
- $[40] = t7;
279
+ $[38] = t14;
280
+ $[39] = t6;
281
+ $[40] = t8;
285
282
  $[41] = t9;
286
- $[42] = t16;
287
- } else t16 = $[42];
288
- return t16;
283
+ $[42] = t15;
284
+ } else t15 = $[42];
285
+ return t15;
289
286
  }
290
287
  function LayoutPageMarkdown(t0) {
291
288
  const $ = c(11);