camox 0.47.0 → 0.48.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 (75) hide show
  1. package/dist/core/createApp.d.ts +19 -6
  2. package/dist/core/createApp.js +7 -2
  3. package/dist/core/createBlock.js +54 -43
  4. package/dist/core/createCollection.d.ts +25 -7
  5. package/dist/core/createCollection.js +28 -9
  6. package/dist/core/createLayout.d.ts +98 -71
  7. package/dist/core/createLayout.js +10 -16
  8. package/dist/core/derivedRoutes.js +1 -1
  9. package/dist/core/editing/BlockEditingRuntime.d.ts +3 -2
  10. package/dist/core/editing/CompleteBlockEditingRuntime.js +2 -1
  11. package/dist/core/editing/createEditableBlock.d.ts +59 -19
  12. package/dist/core/editing/createEditableBlock.js +162 -151
  13. package/dist/core/editing/useLatestRecord.js +7 -7
  14. package/dist/core/layoutContext.d.ts +54 -0
  15. package/dist/core/layoutContext.js +66 -0
  16. package/dist/core/lib/contentType.d.ts +91 -4
  17. package/dist/core/lib/contentType.js +84 -7
  18. package/dist/core/lib/recordScope.js +19 -17
  19. package/dist/core/lib/reference.d.ts +6 -2
  20. package/dist/core/recordItem.js +55 -2
  21. package/dist/core/requestContext.d.ts +18 -0
  22. package/dist/core/structuredData.d.ts +126 -0
  23. package/dist/core/structuredData.js +40 -0
  24. package/dist/features/canvas/canvasCamera.js +1 -1
  25. package/dist/features/canvas/sidebar/CanvasSidebarFrame.js +1 -1
  26. package/dist/features/content/ContentCollection.js +13 -7
  27. package/dist/features/content/collection-form.js +6 -2
  28. package/dist/features/content/components/MissingFromLocale.js +1 -1
  29. package/dist/features/og/pageImage.js +89 -0
  30. package/dist/features/page/CuratedPageContent.js +45 -32
  31. package/dist/features/page/DerivedPageContent.js +49 -22
  32. package/dist/features/page/SharedLayoutContent.js +26 -22
  33. package/dist/features/preview/CamoxPreview.js +40 -26
  34. package/dist/features/preview/components/AddBlockSheet.js +1 -0
  35. package/dist/features/preview/components/BlockActionsPopover.js +8 -6
  36. package/dist/features/preview/components/PageInfo.js +244 -264
  37. package/dist/features/preview/components/PageTree.js +63 -53
  38. package/dist/features/preview/components/RecordCard.js +50 -34
  39. package/dist/features/preview/components/RecordCombobox.js +12 -5
  40. package/dist/features/preview/components/ReferenceFieldEditor.js +4 -2
  41. package/dist/features/preview/components/ReferenceListFieldEditor.js +24 -19
  42. package/dist/features/preview/components/RepeatableItemsList.js +62 -46
  43. package/dist/features/preview/components/SelectionEditor.js +3 -2
  44. package/dist/features/preview/components/useFieldWriter.js +2 -4
  45. package/dist/features/preview/components/useRecordView.js +2 -2
  46. package/dist/features/preview/entityName.js +11 -0
  47. package/dist/features/preview/pageRecord.js +17 -18
  48. package/dist/features/routes/pageRuntime.d.ts +15 -1
  49. package/dist/features/routes/pageRuntime.js +35 -38
  50. package/dist/features/runtime/RuntimeChrome.js +1 -1
  51. package/dist/features/runtime/breadcrumbs.js +68 -0
  52. package/dist/features/runtime/livePages.js +3 -2
  53. package/dist/features/runtime/pageGraph.js +92 -0
  54. package/dist/features/runtime/projectLogo.js +110 -0
  55. package/dist/features/runtime/runtime.d.ts +11 -6
  56. package/dist/features/runtime/runtime.js +278 -55
  57. package/dist/features/runtime/runtimeRoutes.d.ts +1 -0
  58. package/dist/features/runtime/runtimeRoutes.js +1 -0
  59. package/dist/features/runtime/structuredData.js +213 -0
  60. package/dist/features/studio/components/ChatSidebar.js +5 -5
  61. package/dist/features/studio/components/ProjectMenu.js +127 -100
  62. package/dist/features/studio/components/SocialProfilesDialog.js +342 -0
  63. package/dist/features/studio/components/ThreadMessages.js +2 -2
  64. package/dist/features/vite/blockBoilerplate.js +3 -2
  65. package/dist/features/vite/layoutGeneration.js +3 -2
  66. package/dist/features/vite/vite.js +1 -0
  67. package/dist/lib/queries.d.ts +4 -0
  68. package/dist/lib/queries.js +1 -0
  69. package/dist/lib/studio-reads.js +3 -1
  70. package/dist/package.js +1 -1
  71. package/dist/studio.css +1 -1
  72. package/package.json +5 -4
  73. package/skills/camox/references/block-definitions.md +105 -25
  74. package/skills/camox/references/layout-definitions.md +53 -17
  75. package/skills/camox/references/routed-layouts.md +17 -14
@@ -177,9 +177,15 @@ const ContentCollection = (t0) => {
177
177
  itemId: record.id
178
178
  }),
179
179
  className: "focus-visible:bg-accent flex min-w-0 flex-1 items-center gap-2 px-4 py-3 text-sm",
180
- children: [/* @__PURE__ */ jsx("span", {
181
- className: "truncate",
182
- children: record.label || "Untitled item"
180
+ children: [/* @__PURE__ */ jsxs("span", {
181
+ className: "flex min-w-0 flex-col items-start text-left",
182
+ children: [/* @__PURE__ */ jsx("span", {
183
+ className: "max-w-full truncate",
184
+ children: record.title || "Untitled item"
185
+ }), record.description && /* @__PURE__ */ jsx("span", {
186
+ className: "text-muted-foreground max-w-full truncate text-xs",
187
+ children: record.description
188
+ })]
183
189
  }), record.duplicatePageValue && /* @__PURE__ */ jsx("span", {
184
190
  className: "text-destructive shrink-0 text-xs",
185
191
  title: "Another item's page has the same URL. Change one of them before publishing.",
@@ -189,7 +195,7 @@ const ContentCollection = (t0) => {
189
195
  projectUuid,
190
196
  collectionId: collection.collectionId,
191
197
  id: record.id,
192
- label: record.label,
198
+ label: record.title,
193
199
  compact: true
194
200
  })]
195
201
  }, record.id)), /* @__PURE__ */ jsx("li", {
@@ -244,9 +250,9 @@ const ContentCollection = (t0) => {
244
250
  return t14;
245
251
  };
246
252
  const fieldLabel = (name, schema) => schema.title ?? name.replace(/([A-Z])/g, " $1").replace(/^./, (letter) => letter.toUpperCase());
247
- function CollectionItemForm({ contentSchema, label, projectUuid, collectionId, record, initialContent, onSaved }) {
253
+ function CollectionItemForm({ contentSchema, toTitle, projectUuid, collectionId, record, initialContent, onSaved }) {
248
254
  const studioCache = useStudioCache();
249
- const fields = collectionFormFields(contentSchema, label);
255
+ const fields = collectionFormFields(contentSchema, toTitle);
250
256
  const [savedRecord, setSavedRecord] = useState(record);
251
257
  const [error, setError] = useState(null);
252
258
  const create = useMutation(collectionMutations.create());
@@ -502,7 +508,7 @@ const ContentCollectionItemEditor = (t0) => {
502
508
  if ($[20] !== collectionId || $[21] !== definition || $[22] !== initialContent || $[23] !== itemId || $[24] !== onSaved || $[25] !== projectUuid || $[26] !== recordQuery) {
503
509
  t9 = definition && (!itemId || recordQuery.data) && /* @__PURE__ */ jsx(CollectionItemForm, {
504
510
  contentSchema: definition.contentSchema,
505
- label: definition.label,
511
+ toTitle: definition.toTitle,
506
512
  projectUuid,
507
513
  collectionId,
508
514
  record: itemId ? recordQuery.data : void 0,
@@ -1,8 +1,12 @@
1
1
  import { isLexicalState, lexicalStateToPlainText } from "../../core/lib/lexicalState.js";
2
+ import { titleField } from "../../core/recordItem.js";
2
3
 
3
4
  //#region src/features/content/collection-form.ts
4
- function collectionFormFields(contentSchema, label) {
5
- return Object.entries(contentSchema.properties).sort(([a], [b]) => Number(b === label) - Number(a === label));
5
+ /** The form's fields, the one the record's title starts with first. */
6
+ function collectionFormFields(contentSchema, toTitle) {
7
+ const schema = contentSchema;
8
+ const first = titleField(toTitle);
9
+ return Object.entries(schema.properties).sort(([a], [b]) => Number(b === first) - Number(a === first));
6
10
  }
7
11
  function collectionFormDefaults(fields, content = {}) {
8
12
  return Object.fromEntries(fields.map(([name, schema]) => {
@@ -144,7 +144,7 @@ function missingGroups(missing, collections) {
144
144
  entity: "record",
145
145
  id: record.id,
146
146
  collectionId: record.collectionId,
147
- name: record.label || "Untitled item"
147
+ name: record.title || "Untitled item"
148
148
  }))
149
149
  });
150
150
  }
@@ -0,0 +1,89 @@
1
+ import { c } from "react/compiler-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+
4
+ //#region src/features/og/pageImage.tsx
5
+ /** The size every page image renders at, which the page head states. */
6
+ const PAGE_IMAGE_SIZE = {
7
+ width: 1200,
8
+ height: 630
9
+ };
10
+ /**
11
+ * A page's image, chosen in order: the editor's custom image, else `/og` for the page, which
12
+ * renders its layout's `toImage` or Camox's default image. `/og` names the page by its path,
13
+ * with its locale's prefix.
14
+ */
15
+ function pageImageUrl({ origin, path, customImageUrl }) {
16
+ return customImageUrl || `${origin}/og?${new URLSearchParams({ path }).toString()}`;
17
+ }
18
+ /** Camox's default image, for a page whose layout has no `toImage`: its title and project. */
19
+ function DefaultPageImage(t0) {
20
+ const $ = c(9);
21
+ const { page, project } = t0;
22
+ let t1;
23
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
24
+ t1 = {
25
+ display: "flex",
26
+ flexDirection: "column",
27
+ justifyContent: "center",
28
+ width: "100%",
29
+ height: "100%",
30
+ backgroundColor: "#09090b",
31
+ padding: "60px 80px"
32
+ };
33
+ $[0] = t1;
34
+ } else t1 = $[0];
35
+ let t2;
36
+ if ($[1] !== project.name) {
37
+ t2 = project.name && /* @__PURE__ */ jsx("div", {
38
+ style: {
39
+ fontSize: 24,
40
+ color: "#a1a1aa",
41
+ marginBottom: 24,
42
+ textTransform: "uppercase",
43
+ letterSpacing: "0.1em"
44
+ },
45
+ children: project.name
46
+ });
47
+ $[1] = project.name;
48
+ $[2] = t2;
49
+ } else t2 = $[2];
50
+ let t3;
51
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
52
+ t3 = {
53
+ fontSize: 64,
54
+ fontWeight: 700,
55
+ color: "#fafafa",
56
+ lineHeight: 1.2
57
+ };
58
+ $[3] = t3;
59
+ } else t3 = $[3];
60
+ let t4;
61
+ if ($[4] !== page.title) {
62
+ t4 = /* @__PURE__ */ jsx("div", {
63
+ style: t3,
64
+ children: page.title
65
+ });
66
+ $[4] = page.title;
67
+ $[5] = t4;
68
+ } else t4 = $[5];
69
+ let t5;
70
+ if ($[6] !== t2 || $[7] !== t4) {
71
+ t5 = /* @__PURE__ */ jsxs("div", {
72
+ style: t1,
73
+ children: [t2, t4]
74
+ });
75
+ $[6] = t2;
76
+ $[7] = t4;
77
+ $[8] = t5;
78
+ } else t5 = $[8];
79
+ return t5;
80
+ }
81
+ /** Renders a page image as a PNG response. Server only. */
82
+ async function renderPageImage(element) {
83
+ if (import.meta.env?.SSR === false) throw new Error("OG images can only be rendered on the server.");
84
+ const { ImageResponse } = await import("camox/_internal/imageResponse");
85
+ return new ImageResponse(element, PAGE_IMAGE_SIZE);
86
+ }
87
+
88
+ //#endregion
89
+ export { DefaultPageImage, PAGE_IMAGE_SIZE, pageImageUrl, renderPageImage };
@@ -1,8 +1,10 @@
1
1
  import { useProjectUuid } from "../../lib/auth.js";
2
+ import { useViewLocale } from "../../lib/view-locale-context.js";
2
3
  import { useCamoxApp } from "../provider/components/CamoxAppContext.js";
3
4
  import { NormalizedDataProvider, usePageBlocks } from "../../lib/normalized-data.js";
4
5
  import { reads, useRead } from "../../lib/studio-reads.js";
5
6
  import { BlockErrorBoundary } from "../preview/components/BlockErrorBoundary.js";
7
+ import { curatedLayoutContext } from "../../core/layoutContext.js";
6
8
  import { useLocalePath } from "../../lib/view-locale.js";
7
9
  import { SharedLayoutContent } from "./SharedLayoutContent.js";
8
10
  import { c } from "react/compiler-runtime";
@@ -84,7 +86,7 @@ function PageBlock(t0) {
84
86
  }
85
87
  /** A curated page as visitors see it, without editing. */
86
88
  function CuratedPageContent() {
87
- const $ = c(19);
89
+ const $ = c(23);
88
90
  const pathname = useLocalePath();
89
91
  const projectUuid = useProjectUuid();
90
92
  const camoxApp = useCamoxApp();
@@ -108,49 +110,60 @@ function CuratedPageContent() {
108
110
  $[5] = t1;
109
111
  } else t1 = $[5];
110
112
  const layout = t1;
113
+ const { locale } = useViewLocale();
111
114
  let t2;
112
- if ($[6] !== pageBlocks) {
113
- t2 = pageBlocks.map(_temp);
114
- $[6] = pageBlocks;
115
- $[7] = t2;
116
- } else t2 = $[7];
117
- const pageBlocksContent = t2;
115
+ if ($[6] !== locale || $[7] !== pageData) {
116
+ t2 = curatedLayoutContext(pageData, locale);
117
+ $[6] = locale;
118
+ $[7] = pageData;
119
+ $[8] = t2;
120
+ } else t2 = $[8];
121
+ const context = t2;
122
+ let t3;
123
+ if ($[9] !== pageBlocks) {
124
+ t3 = pageBlocks.map(_temp);
125
+ $[9] = pageBlocks;
126
+ $[10] = t3;
127
+ } else t3 = $[10];
128
+ const pageBlocksContent = t3;
118
129
  if (!layout) {
119
- let t3;
120
- if ($[8] !== pageBlocksContent) {
121
- t3 = /* @__PURE__ */ jsx("main", {
130
+ let t4;
131
+ if ($[11] !== pageBlocksContent) {
132
+ t4 = /* @__PURE__ */ jsx("main", {
122
133
  className: "flex min-h-screen flex-col",
123
134
  children: pageBlocksContent
124
135
  });
125
- $[8] = pageBlocksContent;
126
- $[9] = t3;
127
- } else t3 = $[9];
128
- return t3;
136
+ $[11] = pageBlocksContent;
137
+ $[12] = t4;
138
+ } else t4 = $[12];
139
+ return t4;
129
140
  }
130
- let t3;
131
- if ($[10] !== afterBlocks || $[11] !== beforeBlocks) {
132
- t3 = [...beforeBlocks, ...afterBlocks];
133
- $[10] = afterBlocks;
134
- $[11] = beforeBlocks;
135
- $[12] = t3;
136
- } else t3 = $[12];
137
141
  let t4;
138
- if ($[13] !== layout || $[14] !== layoutFiles || $[15] !== layoutItems || $[16] !== pageBlocksContent || $[17] !== t3) {
139
- t4 = /* @__PURE__ */ jsx(SharedLayoutContent, {
142
+ if ($[13] !== afterBlocks || $[14] !== beforeBlocks) {
143
+ t4 = [...beforeBlocks, ...afterBlocks];
144
+ $[13] = afterBlocks;
145
+ $[14] = beforeBlocks;
146
+ $[15] = t4;
147
+ } else t4 = $[15];
148
+ let t5;
149
+ if ($[16] !== context || $[17] !== layout || $[18] !== layoutFiles || $[19] !== layoutItems || $[20] !== pageBlocksContent || $[21] !== t4) {
150
+ t5 = /* @__PURE__ */ jsx(SharedLayoutContent, {
140
151
  layout,
141
- blocks: t3,
152
+ context,
153
+ blocks: t4,
142
154
  files: layoutFiles,
143
155
  repeatableItems: layoutItems,
144
156
  children: pageBlocksContent
145
157
  });
146
- $[13] = layout;
147
- $[14] = layoutFiles;
148
- $[15] = layoutItems;
149
- $[16] = pageBlocksContent;
150
- $[17] = t3;
151
- $[18] = t4;
152
- } else t4 = $[18];
153
- return t4;
158
+ $[16] = context;
159
+ $[17] = layout;
160
+ $[18] = layoutFiles;
161
+ $[19] = layoutItems;
162
+ $[20] = pageBlocksContent;
163
+ $[21] = t4;
164
+ $[22] = t5;
165
+ } else t5 = $[22];
166
+ return t5;
154
167
  }
155
168
  function _temp(block) {
156
169
  return /* @__PURE__ */ jsx(BlockErrorBoundary, {
@@ -1,4 +1,7 @@
1
+ import { useViewLocale } from "../../lib/view-locale-context.js";
1
2
  import { usePageBlocks } from "../../lib/normalized-data.js";
3
+ import { asCollectionItem, recordPageValues } from "../../core/recordItem.js";
4
+ import { buildLayoutContext } from "../../core/layoutContext.js";
2
5
  import { SharedLayoutContent } from "./SharedLayoutContent.js";
3
6
  import { c } from "react/compiler-runtime";
4
7
  import { jsx } from "react/jsx-runtime";
@@ -6,7 +9,7 @@ import { jsx } from "react/jsx-runtime";
6
9
  //#region src/features/page/DerivedPageContent.tsx
7
10
  const EMPTY_PAGE = { blockIds: [] };
8
11
  function DerivedPageContent(t0) {
9
- const $ = c(14);
12
+ const $ = c(18);
10
13
  const { camoxApp, derived } = t0;
11
14
  let t1;
12
15
  if ($[0] !== derived.layout) {
@@ -18,38 +21,62 @@ function DerivedPageContent(t0) {
18
21
  $[1] = t1;
19
22
  } else t1 = $[1];
20
23
  const { beforeBlocks, afterBlocks, layoutFiles, layoutItems } = usePageBlocks(t1);
24
+ const { locale } = useViewLocale();
25
+ let layout;
26
+ let result;
21
27
  let t2;
22
- if ($[2] !== camoxApp || $[3] !== derived.layoutId) {
23
- t2 = camoxApp.getLayoutById(derived.layoutId);
28
+ if ($[2] !== camoxApp || $[3] !== derived || $[4] !== locale) {
29
+ layout = camoxApp.getLayoutById(derived.layoutId);
30
+ if (!layout) throw new Error(`Unknown derived layout: ${derived.layoutId}`);
31
+ const { page, result: t3 } = derived;
32
+ result = t3;
33
+ const record = asCollectionItem(result);
34
+ const collection = record && camoxApp.getCollectionById(record.collectionId);
35
+ t2 = buildLayoutContext(layout._internal, {
36
+ path: page?.path ?? "",
37
+ locale: locale.tag,
38
+ projectName: page?.projectName ?? "",
39
+ data: result?.data,
40
+ params: page?.params,
41
+ record: record && collection ? recordPageValues(collection, record) : void 0
42
+ });
24
43
  $[2] = camoxApp;
25
- $[3] = derived.layoutId;
26
- $[4] = t2;
27
- } else t2 = $[4];
28
- const layout = t2;
29
- if (!layout) throw new Error(`Unknown derived layout: ${derived.layoutId}`);
44
+ $[3] = derived;
45
+ $[4] = locale;
46
+ $[5] = layout;
47
+ $[6] = result;
48
+ $[7] = t2;
49
+ } else {
50
+ layout = $[5];
51
+ result = $[6];
52
+ t2 = $[7];
53
+ }
54
+ const context = t2;
30
55
  let t3;
31
- if ($[5] !== afterBlocks || $[6] !== beforeBlocks) {
56
+ if ($[8] !== afterBlocks || $[9] !== beforeBlocks) {
32
57
  t3 = [...beforeBlocks, ...afterBlocks];
33
- $[5] = afterBlocks;
34
- $[6] = beforeBlocks;
35
- $[7] = t3;
36
- } else t3 = $[7];
58
+ $[8] = afterBlocks;
59
+ $[9] = beforeBlocks;
60
+ $[10] = t3;
61
+ } else t3 = $[10];
37
62
  let t4;
38
- if ($[8] !== derived.result || $[9] !== layout || $[10] !== layoutFiles || $[11] !== layoutItems || $[12] !== t3) {
63
+ if ($[11] !== context || $[12] !== layout || $[13] !== layoutFiles || $[14] !== layoutItems || $[15] !== result || $[16] !== t3) {
39
64
  t4 = /* @__PURE__ */ jsx(SharedLayoutContent, {
40
65
  layout,
41
- result: derived.result,
66
+ context,
67
+ result,
42
68
  blocks: t3,
43
69
  files: layoutFiles,
44
70
  repeatableItems: layoutItems
45
71
  });
46
- $[8] = derived.result;
47
- $[9] = layout;
48
- $[10] = layoutFiles;
49
- $[11] = layoutItems;
50
- $[12] = t3;
51
- $[13] = t4;
52
- } else t4 = $[13];
72
+ $[11] = context;
73
+ $[12] = layout;
74
+ $[13] = layoutFiles;
75
+ $[14] = layoutItems;
76
+ $[15] = result;
77
+ $[16] = t3;
78
+ $[17] = t4;
79
+ } else t4 = $[17];
53
80
  return t4;
54
81
  }
55
82
 
@@ -6,8 +6,8 @@ import { jsx } from "react/jsx-runtime";
6
6
  //#region src/features/page/SharedLayoutContent.tsx
7
7
  /** Shared before/after rendering for both curated and data-derived pages. */
8
8
  function SharedLayoutContent(t0) {
9
- const $ = c(15);
10
- const { layout, blocks, files, repeatableItems, result, children } = t0;
9
+ const $ = c(16);
10
+ const { layout, context, blocks, files, repeatableItems, result, children } = t0;
11
11
  let result_0;
12
12
  if ($[0] !== blocks) {
13
13
  result_0 = {};
@@ -22,41 +22,45 @@ function SharedLayoutContent(t0) {
22
22
  $[1] = result_0;
23
23
  } else result_0 = $[1];
24
24
  const layoutBlocks = result_0;
25
- const Component = layout._internal.component;
25
+ const ToReact = layout._internal.toReact;
26
26
  let t1;
27
- if ($[2] !== Component || $[3] !== children) {
28
- t1 = /* @__PURE__ */ jsx(Component, { children });
29
- $[2] = Component;
27
+ if ($[2] !== ToReact || $[3] !== children || $[4] !== context) {
28
+ t1 = /* @__PURE__ */ jsx(ToReact, {
29
+ ...context,
30
+ children
31
+ });
32
+ $[2] = ToReact;
30
33
  $[3] = children;
31
- $[4] = t1;
32
- } else t1 = $[4];
34
+ $[4] = context;
35
+ $[5] = t1;
36
+ } else t1 = $[5];
33
37
  let t2;
34
- if ($[5] !== layout._internal.Provider || $[6] !== layoutBlocks || $[7] !== result || $[8] !== t1) {
38
+ if ($[6] !== layout._internal.Provider || $[7] !== layoutBlocks || $[8] !== result || $[9] !== t1) {
35
39
  t2 = /* @__PURE__ */ jsx(layout._internal.Provider, {
36
40
  layoutBlocks,
37
41
  result,
38
42
  children: t1
39
43
  });
40
- $[5] = layout._internal.Provider;
41
- $[6] = layoutBlocks;
42
- $[7] = result;
43
- $[8] = t1;
44
- $[9] = t2;
45
- } else t2 = $[9];
44
+ $[6] = layout._internal.Provider;
45
+ $[7] = layoutBlocks;
46
+ $[8] = result;
47
+ $[9] = t1;
48
+ $[10] = t2;
49
+ } else t2 = $[10];
46
50
  let t3;
47
- if ($[10] !== blocks || $[11] !== files || $[12] !== repeatableItems || $[13] !== t2) {
51
+ if ($[11] !== blocks || $[12] !== files || $[13] !== repeatableItems || $[14] !== t2) {
48
52
  t3 = /* @__PURE__ */ jsx(NormalizedDataProvider, {
49
53
  files,
50
54
  repeatableItems,
51
55
  blocks,
52
56
  children: t2
53
57
  });
54
- $[10] = blocks;
55
- $[11] = files;
56
- $[12] = repeatableItems;
57
- $[13] = t2;
58
- $[14] = t3;
59
- } else t3 = $[14];
58
+ $[11] = blocks;
59
+ $[12] = files;
60
+ $[13] = repeatableItems;
61
+ $[14] = t2;
62
+ $[15] = t3;
63
+ } else t3 = $[15];
60
64
  return t3;
61
65
  }
62
66
 
@@ -8,6 +8,7 @@ import { useCamoxApp } from "../provider/components/CamoxAppContext.js";
8
8
  import { NormalizedDataProvider, usePageBlocks } from "../../lib/normalized-data.js";
9
9
  import { reads, useRead, useStudioCache } from "../../lib/studio-reads.js";
10
10
  import { BlockErrorBoundary } from "./components/BlockErrorBoundary.js";
11
+ import { curatedLayoutContext } from "../../core/layoutContext.js";
11
12
  import { CollectionItemSheetProvider } from "../content/CollectionItemSheetContext.js";
12
13
  import { cn } from "../../lib/utils.js";
13
14
  import { ContentCollectionItemSheet } from "../content/ContentCollection.js";
@@ -164,10 +165,11 @@ const BlockRenderer = (t0) => {
164
165
  return t13;
165
166
  };
166
167
  const PageContent = () => {
167
- const $ = c(30);
168
+ const $ = c(34);
168
169
  const pageData = usePreviewedPage();
169
170
  const { pageBlocks, beforeBlocks, afterBlocks, layoutFiles, layoutItems } = usePageBlocks(pageData);
170
171
  const camoxApp = useCamoxApp();
172
+ const { locale } = useViewLocale();
171
173
  let layout;
172
174
  let layoutBlocksMap;
173
175
  let t0;
@@ -228,7 +230,7 @@ const PageContent = () => {
228
230
  } else t1 = $[12];
229
231
  const pageBlocksContent = t1;
230
232
  if (layout && layoutBlocksMap) {
231
- const LayoutComponent = layout._internal.component;
233
+ const ToReact = layout._internal.toReact;
232
234
  let t2;
233
235
  if ($[13] !== afterBlocks || $[14] !== beforeBlocks) {
234
236
  t2 = [...beforeBlocks, ...afterBlocks];
@@ -236,49 +238,61 @@ const PageContent = () => {
236
238
  $[14] = beforeBlocks;
237
239
  $[15] = t2;
238
240
  } else t2 = $[15];
241
+ const T0 = layout._internal.Provider;
239
242
  let t3;
240
- if ($[16] !== LayoutComponent || $[17] !== pageBlocksContent) {
241
- t3 = /* @__PURE__ */ jsx(LayoutComponent, { children: pageBlocksContent });
242
- $[16] = LayoutComponent;
243
- $[17] = pageBlocksContent;
243
+ if ($[16] !== locale || $[17] !== pageData) {
244
+ t3 = curatedLayoutContext(pageData, locale);
245
+ $[16] = locale;
246
+ $[17] = pageData;
244
247
  $[18] = t3;
245
248
  } else t3 = $[18];
246
249
  let t4;
247
- if ($[19] !== layout._internal.Provider || $[20] !== layoutBlocksMap || $[21] !== t3) {
248
- t4 = /* @__PURE__ */ jsx(layout._internal.Provider, {
249
- layoutBlocks: layoutBlocksMap,
250
- children: t3
250
+ if ($[19] !== ToReact || $[20] !== pageBlocksContent || $[21] !== t3) {
251
+ t4 = /* @__PURE__ */ jsx(ToReact, {
252
+ ...t3,
253
+ children: pageBlocksContent
251
254
  });
252
- $[19] = layout._internal.Provider;
253
- $[20] = layoutBlocksMap;
255
+ $[19] = ToReact;
256
+ $[20] = pageBlocksContent;
254
257
  $[21] = t3;
255
258
  $[22] = t4;
256
259
  } else t4 = $[22];
257
260
  let t5;
258
- if ($[23] !== layoutFiles || $[24] !== layoutItems || $[25] !== t2 || $[26] !== t4) {
259
- t5 = /* @__PURE__ */ jsx(NormalizedDataProvider, {
261
+ if ($[23] !== layout._internal.Provider || $[24] !== layoutBlocksMap || $[25] !== t4) {
262
+ t5 = /* @__PURE__ */ jsx(T0, {
263
+ layoutBlocks: layoutBlocksMap,
264
+ children: t4
265
+ });
266
+ $[23] = layout._internal.Provider;
267
+ $[24] = layoutBlocksMap;
268
+ $[25] = t4;
269
+ $[26] = t5;
270
+ } else t5 = $[26];
271
+ let t6;
272
+ if ($[27] !== layoutFiles || $[28] !== layoutItems || $[29] !== t2 || $[30] !== t5) {
273
+ t6 = /* @__PURE__ */ jsx(NormalizedDataProvider, {
260
274
  files: layoutFiles,
261
275
  repeatableItems: layoutItems,
262
276
  blocks: t2,
263
- children: t4
277
+ children: t5
264
278
  });
265
- $[23] = layoutFiles;
266
- $[24] = layoutItems;
267
- $[25] = t2;
268
- $[26] = t4;
269
- $[27] = t5;
270
- } else t5 = $[27];
271
- return t5;
279
+ $[27] = layoutFiles;
280
+ $[28] = layoutItems;
281
+ $[29] = t2;
282
+ $[30] = t5;
283
+ $[31] = t6;
284
+ } else t6 = $[31];
285
+ return t6;
272
286
  }
273
287
  let t2;
274
- if ($[28] !== pageBlocksContent) {
288
+ if ($[32] !== pageBlocksContent) {
275
289
  t2 = /* @__PURE__ */ jsx("main", {
276
290
  className: "flex min-h-screen flex-col",
277
291
  children: pageBlocksContent
278
292
  });
279
- $[28] = pageBlocksContent;
280
- $[29] = t2;
281
- } else t2 = $[29];
293
+ $[32] = pageBlocksContent;
294
+ $[33] = t2;
295
+ } else t2 = $[33];
282
296
  return t2;
283
297
  };
284
298
  /**
@@ -76,6 +76,7 @@ const AddBlockSheet = ({ focusCreatedBlock = true }) => {
76
76
  settings: variables.settings ?? null,
77
77
  slot: null,
78
78
  summary: "",
79
+ title: "",
79
80
  position,
80
81
  createdAt: now,
81
82
  updatedAt: now
@@ -4,6 +4,7 @@ import { usePageBlocks } from "../../../lib/normalized-data.js";
4
4
  import { formatShortcut } from "../../../lib/utils.js";
5
5
  import { blockMutations, repeatableItemMutations } from "../../../lib/queries.js";
6
6
  import { isBlockSelection, previewStore, selectionForPage, selectionItemId } from "../previewStore.js";
7
+ import { entityName } from "../entityName.js";
7
8
  import { useUpdateBlockPosition } from "./useUpdateBlockPosition.js";
8
9
  import { usePreviewedPage } from "../CamoxPreview.js";
9
10
  import { c } from "react/compiler-runtime";
@@ -28,7 +29,7 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
28
29
  const handleDeleteBlock = async (block) => {
29
30
  try {
30
31
  await deleteBlock.mutateAsync({ id: block.id });
31
- toast.success(`Deleted "${block.summary || block.type}" block`);
32
+ toast.success(`Deleted "${entityName(block, block.type)}" block`);
32
33
  } catch (error) {
33
34
  console.error("Failed to delete block:", error);
34
35
  toast.error("Could not delete block");
@@ -39,7 +40,7 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
39
40
  const handleDuplicateBlock = async (block) => {
40
41
  try {
41
42
  await duplicateBlock.mutateAsync({ id: block.id });
42
- toast.success(`Duplicated "${block.summary}" block`);
43
+ toast.success(`Duplicated "${entityName(block, block.type)}" block`);
43
44
  } catch (error) {
44
45
  console.error("Failed to duplicate block:", error);
45
46
  toast.error("Could not duplicate block");
@@ -209,8 +210,9 @@ const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "sta
209
210
  open: !!blockToDelete,
210
211
  onOpenChange: (open) => !open && setBlockToDelete(null),
211
212
  children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: "Delete block" }), /* @__PURE__ */ jsxs(AlertDialogDescription, { children: [
212
- "Are you sure you want to delete ",
213
- /* @__PURE__ */ jsx("strong", { children: blockToDelete?.summary }),
213
+ "Are you sure you want to delete",
214
+ " ",
215
+ /* @__PURE__ */ jsx("strong", { children: blockToDelete && entityName(blockToDelete, blockToDelete.type) }),
214
216
  "? This action cannot be undone."
215
217
  ] })] }), /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [/* @__PURE__ */ jsx(AlertDialogCancel, {
216
218
  variant: "outline",
@@ -310,7 +312,7 @@ function useBlockActionsShortcuts() {
310
312
  return;
311
313
  }
312
314
  const block_0 = pageBlocks.find((b_0) => b_0.id === sel_0.blockId);
313
- deleteBlock({ id: sel_0.blockId }).then(() => toast.success(`Deleted "${block_0?.summary || block_0?.type}" block`), _temp6);
315
+ deleteBlock({ id: sel_0.blockId }).then(() => toast.success(`Deleted "${block_0 ? entityName(block_0, block_0.type) : ""}" block`), _temp6);
314
316
  previewStore.send({ type: "clearSelection" });
315
317
  }
316
318
  },
@@ -339,7 +341,7 @@ function useBlockActionsShortcuts() {
339
341
  return;
340
342
  }
341
343
  const block_1 = pageBlocks.find((b_1) => b_1.id === sel_2.blockId);
342
- duplicateBlock({ id: sel_2.blockId }).then(() => toast.success(`Duplicated "${block_1?.summary}" block`), _temp9);
344
+ duplicateBlock({ id: sel_2.blockId }).then(() => toast.success(`Duplicated "${block_1 ? entityName(block_1, block_1.type) : ""}" block`), _temp9);
343
345
  }
344
346
  },
345
347
  {