camox 0.41.1 → 0.43.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 (93) hide show
  1. package/dist/core/components/lexical/{GradientNode.js → HighlightNode.js} +34 -34
  2. package/dist/core/components/lexical/InlineLexicalEditor.js +14 -14
  3. package/dist/core/components/lexical/InlineStylesPlugin.js +6 -6
  4. package/dist/core/components/lexical/SelectionBroadcaster.js +5 -5
  5. package/dist/core/components/lexical/SidebarLexicalEditor.js +52 -49
  6. package/dist/core/components/lexical/TextLinkPopover.js +191 -208
  7. package/dist/core/components/lexical/editorConfig.js +2 -2
  8. package/dist/core/createApp.d.ts +19 -4
  9. package/dist/core/createApp.js +2 -1
  10. package/dist/core/createLayout.d.ts +16 -3
  11. package/dist/core/createLayout.js +15 -15
  12. package/dist/core/derivedRoutes.js +1 -1
  13. package/dist/core/dom.d.ts +17 -0
  14. package/dist/core/dom.js +22 -0
  15. package/dist/core/editing/createEditableBlock.d.ts +8 -1
  16. package/dist/core/editing/createEditableBlock.js +636 -459
  17. package/dist/core/hooks/useOverlayState.js +11 -0
  18. package/dist/core/lib/fieldTypes.js +5 -5
  19. package/dist/core/lib/lexicalReact.js +4 -4
  20. package/dist/core/lib/lexicalState.js +20 -4
  21. package/dist/core/lib/modifierFormats.js +1 -1
  22. package/dist/core/lib/textLinks.js +5 -2
  23. package/dist/core/lib/textStyles.d.ts +2 -2
  24. package/dist/core/lib/textStyles.js +6 -11
  25. package/dist/core/pageDestinations.js +37 -0
  26. package/dist/features/og/imageResponse.node.js +11 -9
  27. package/dist/features/preview/CamoxPreview.js +108 -124
  28. package/dist/features/preview/commentsEnabled.js +8 -0
  29. package/dist/features/preview/components/AddBlockSidebar.js +80 -90
  30. package/dist/features/preview/components/AssetLightbox.js +4 -11
  31. package/dist/features/preview/components/AttachedComments.js +194 -0
  32. package/dist/features/preview/components/BlockActionsPopover.js +14 -65
  33. package/dist/features/preview/components/CommentHeader.js +122 -0
  34. package/dist/features/preview/components/CommentSidebar.js +29 -0
  35. package/dist/features/preview/components/CommentTargetQuote.js +166 -0
  36. package/dist/features/preview/components/CreatePageModal.js +4 -10
  37. package/dist/features/preview/components/DerivedLayoutSidebar.js +45 -26
  38. package/dist/features/preview/components/DerivedPageInfoSidebar.js +38 -26
  39. package/dist/features/preview/components/FieldToolbar.js +7 -7
  40. package/dist/features/preview/components/ItemFieldsEditor.js +275 -204
  41. package/dist/features/preview/components/LeftSidebar.js +18 -18
  42. package/dist/features/preview/components/LinkFieldEditor.js +212 -209
  43. package/dist/features/preview/components/OverlayTracker.js +14 -20
  44. package/dist/features/preview/components/Overlays.js +26 -35
  45. package/dist/features/preview/components/PageEditorSidebar.js +90 -91
  46. package/dist/features/preview/components/PageInfoSidebar.js +128 -159
  47. package/dist/features/preview/components/PagePicker.js +29 -24
  48. package/dist/features/preview/components/PageTree.js +159 -157
  49. package/dist/features/preview/components/PreviewComments.js +56 -0
  50. package/dist/features/preview/components/PreviewPanel.js +122 -78
  51. package/dist/features/preview/components/PreviewToolbar.js +280 -231
  52. package/dist/features/preview/components/PublicationRow.js +8 -11
  53. package/dist/features/preview/components/RightSidebar.js +14 -11
  54. package/dist/features/preview/components/SidebarSection.js +121 -0
  55. package/dist/features/preview/components/useRepeatableItemActions.js +1 -1
  56. package/dist/features/preview/previewCommentsStore.js +115 -0
  57. package/dist/features/preview/previewSelection.js +75 -0
  58. package/dist/features/preview/previewStore.js +19 -39
  59. package/dist/features/preview/publication.js +10 -0
  60. package/dist/features/provider/AuthenticatedCamoxProvider.js +46 -34
  61. package/dist/features/provider/CoreCamoxProvider.js +1 -1
  62. package/dist/features/provider/components/CommandPalette.js +142 -58
  63. package/dist/features/provider/useAdminShortcuts.js +19 -8
  64. package/dist/features/routes/pageRuntime.js +0 -6
  65. package/dist/features/runtime/RuntimeChrome.js +40 -37
  66. package/dist/features/runtime/runtime.js +20 -21
  67. package/dist/features/studio/CamoxStudio.js +30 -50
  68. package/dist/features/studio/components/EnvironmentMenu.js +3 -2
  69. package/dist/features/studio/components/Navbar.js +53 -80
  70. package/dist/features/vite/layoutGeneration.js +7 -3
  71. package/dist/features/vite/runtimeDev.js +4 -1
  72. package/dist/features/vite/vite.d.ts +3 -2
  73. package/dist/features/vite/vite.js +14 -6
  74. package/dist/hooks/use-file-upload.js +0 -2
  75. package/dist/hooks/use-page-destinations.js +53 -0
  76. package/dist/lib/auth.js +11 -14
  77. package/dist/lib/server-auth-cookie.js +21 -0
  78. package/dist/studio.css +1 -1
  79. package/package.json +9 -7
  80. package/skills/camox/SKILL.md +32 -9
  81. package/skills/camox/references/block-definitions.md +84 -290
  82. package/skills/camox/references/cli-common.md +2 -4
  83. package/skills/camox/references/cli-content.md +147 -0
  84. package/skills/camox/references/cli-environments.md +1 -1
  85. package/skills/camox/references/dom-integrations.md +93 -0
  86. package/skills/camox/references/field-styling.md +50 -0
  87. package/skills/camox/references/layout-definitions.md +33 -147
  88. package/skills/camox/references/routed-layouts.md +71 -0
  89. package/skills/camoxify/SKILL.md +52 -0
  90. package/dist/lib/telemetry-client.js +0 -66
  91. package/dist/lib/telemetry.js +0 -26
  92. package/skills/camox/references/cli-blocks.md +0 -78
  93. package/skills/camox/references/cli-pages.md +0 -53
@@ -1,7 +1,8 @@
1
- import { previewStore, selectionBlockId } from "../previewStore.js";
1
+ import { previewStore, selectIsCommentMode, selectionBlockId } from "../previewStore.js";
2
2
  import { AddBlockSidebar } from "./AddBlockSidebar.js";
3
3
  import { PageEditorSidebar } from "./PageEditorSidebar.js";
4
4
  import { PageInfoSidebar } from "./PageInfoSidebar.js";
5
+ import { CommentSidebar } from "./CommentSidebar.js";
5
6
  import { DerivedPageInfoSidebar } from "./DerivedPageInfoSidebar.js";
6
7
  import { c } from "react/compiler-runtime";
7
8
  import { jsx } from "react/jsx-runtime";
@@ -9,14 +10,15 @@ import { useSelector } from "@xstate/store-react";
9
10
 
10
11
  //#region src/features/preview/components/RightSidebar.tsx
11
12
  const RightSidebar = (t0) => {
12
- const $ = c(9);
13
- if ($[0] !== "d71e54add8a0890703a029e4ca30b5b8fa7b144767455a2e03c5c0c217ac64a0") {
14
- for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
15
- $[0] = "d71e54add8a0890703a029e4ca30b5b8fa7b144767455a2e03c5c0c217ac64a0";
13
+ const $ = c(10);
14
+ if ($[0] !== "3a6f3cf40d082faeaea258269c927ca17e318c22f0c389df569e2bea3318461a") {
15
+ for (let $i = 0; $i < 10; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
16
+ $[0] = "3a6f3cf40d082faeaea258269c927ca17e318c22f0c389df569e2bea3318461a";
16
17
  }
17
18
  const { pageId, derivedLayoutId } = t0;
18
19
  const selection = useSelector(previewStore, _temp);
19
20
  const isAddBlockSidebarOpen = useSelector(previewStore, _temp2);
21
+ const isCommentMode = useSelector(previewStore, selectIsCommentMode);
20
22
  let t1;
21
23
  if ($[1] !== selection) {
22
24
  t1 = selectionBlockId(selection);
@@ -31,18 +33,19 @@ const RightSidebar = (t0) => {
31
33
  $[3] = t2;
32
34
  } else t2 = $[3];
33
35
  let t3;
34
- if ($[4] !== derivedLayoutId || $[5] !== isAddBlockSidebarOpen || $[6] !== pageId || $[7] !== selectedBlockId) {
36
+ if ($[4] !== derivedLayoutId || $[5] !== isAddBlockSidebarOpen || $[6] !== isCommentMode || $[7] !== pageId || $[8] !== selectedBlockId) {
35
37
  t3 = /* @__PURE__ */ jsx("aside", {
36
38
  className: "bg-background relative flex shrink-0 flex-col border-l-2",
37
39
  style: t2,
38
- children: pageId != null && isAddBlockSidebarOpen ? /* @__PURE__ */ jsx(AddBlockSidebar, {}) : selectedBlockId != null ? /* @__PURE__ */ jsx(PageEditorSidebar, {}) : pageId != null ? /* @__PURE__ */ jsx(PageInfoSidebar, { pageId }) : /* @__PURE__ */ jsx(DerivedPageInfoSidebar, { layoutId: derivedLayoutId })
40
+ children: pageId != null && isCommentMode ? /* @__PURE__ */ jsx(CommentSidebar, { pageId }, pageId) : pageId != null && isAddBlockSidebarOpen ? /* @__PURE__ */ jsx(AddBlockSidebar, {}) : selectedBlockId != null ? /* @__PURE__ */ jsx(PageEditorSidebar, { pageId }) : pageId != null ? /* @__PURE__ */ jsx(PageInfoSidebar, { pageId }) : /* @__PURE__ */ jsx(DerivedPageInfoSidebar, { layoutId: derivedLayoutId })
39
41
  });
40
42
  $[4] = derivedLayoutId;
41
43
  $[5] = isAddBlockSidebarOpen;
42
- $[6] = pageId;
43
- $[7] = selectedBlockId;
44
- $[8] = t3;
45
- } else t3 = $[8];
44
+ $[6] = isCommentMode;
45
+ $[7] = pageId;
46
+ $[8] = selectedBlockId;
47
+ $[9] = t3;
48
+ } else t3 = $[9];
46
49
  return t3;
47
50
  };
48
51
  function _temp(state) {
@@ -0,0 +1,121 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region src/features/preview/components/SidebarSection.tsx
6
+ function SidebarSection(t0) {
7
+ const $ = c(12);
8
+ if ($[0] !== "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f") {
9
+ for (let $i = 0; $i < 12; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
10
+ $[0] = "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f";
11
+ }
12
+ let className;
13
+ let props;
14
+ let t1;
15
+ if ($[1] !== t0) {
16
+ ({divider: t1, className, ...props} = t0);
17
+ $[1] = t0;
18
+ $[2] = className;
19
+ $[3] = props;
20
+ $[4] = t1;
21
+ } else {
22
+ className = $[2];
23
+ props = $[3];
24
+ t1 = $[4];
25
+ }
26
+ const divider = t1 === void 0 ? "none" : t1;
27
+ const t2 = divider === "top" && "border-t";
28
+ const t3 = divider === "bottom" && "border-b";
29
+ let t4;
30
+ if ($[5] !== className || $[6] !== t2 || $[7] !== t3) {
31
+ t4 = cn("border-border space-y-4 px-2 py-4", t2, t3, className);
32
+ $[5] = className;
33
+ $[6] = t2;
34
+ $[7] = t3;
35
+ $[8] = t4;
36
+ } else t4 = $[8];
37
+ let t5;
38
+ if ($[9] !== props || $[10] !== t4) {
39
+ t5 = /* @__PURE__ */ jsx("section", {
40
+ className: t4,
41
+ ...props
42
+ });
43
+ $[9] = props;
44
+ $[10] = t4;
45
+ $[11] = t5;
46
+ } else t5 = $[11];
47
+ return t5;
48
+ }
49
+ function SidebarSectionHeader(t0) {
50
+ const $ = c(9);
51
+ if ($[0] !== "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f") {
52
+ for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
53
+ $[0] = "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f";
54
+ }
55
+ let className;
56
+ let props;
57
+ if ($[1] !== t0) {
58
+ ({className, ...props} = t0);
59
+ $[1] = t0;
60
+ $[2] = className;
61
+ $[3] = props;
62
+ } else {
63
+ className = $[2];
64
+ props = $[3];
65
+ }
66
+ let t1;
67
+ if ($[4] !== className) {
68
+ t1 = cn("text-muted-foreground flex items-center gap-2 text-sm leading-none font-medium", className);
69
+ $[4] = className;
70
+ $[5] = t1;
71
+ } else t1 = $[5];
72
+ let t2;
73
+ if ($[6] !== props || $[7] !== t1) {
74
+ t2 = /* @__PURE__ */ jsx("h3", {
75
+ className: t1,
76
+ ...props
77
+ });
78
+ $[6] = props;
79
+ $[7] = t1;
80
+ $[8] = t2;
81
+ } else t2 = $[8];
82
+ return t2;
83
+ }
84
+ function SidebarSectionContent(t0) {
85
+ const $ = c(9);
86
+ if ($[0] !== "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f") {
87
+ for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
88
+ $[0] = "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f";
89
+ }
90
+ let className;
91
+ let props;
92
+ if ($[1] !== t0) {
93
+ ({className, ...props} = t0);
94
+ $[1] = t0;
95
+ $[2] = className;
96
+ $[3] = props;
97
+ } else {
98
+ className = $[2];
99
+ props = $[3];
100
+ }
101
+ let t1;
102
+ if ($[4] !== className) {
103
+ t1 = cn("space-y-4", className);
104
+ $[4] = className;
105
+ $[5] = t1;
106
+ } else t1 = $[5];
107
+ let t2;
108
+ if ($[6] !== props || $[7] !== t1) {
109
+ t2 = /* @__PURE__ */ jsx("div", {
110
+ className: t1,
111
+ ...props
112
+ });
113
+ $[6] = props;
114
+ $[7] = t1;
115
+ $[8] = t2;
116
+ } else t2 = $[8];
117
+ return t2;
118
+ }
119
+
120
+ //#endregion
121
+ export { SidebarSection, SidebarSectionContent, SidebarSectionHeader };
@@ -1,5 +1,5 @@
1
- import { repeatableItemMutations } from "../../../lib/queries.js";
2
1
  import "../../provider/components/CamoxAppContext.js";
2
+ import { repeatableItemMutations } from "../../../lib/queries.js";
3
3
  import { previewStore } from "../previewStore.js";
4
4
  import { useRequireDraftSource } from "../../../core/hooks/useRequireDraftSource.js";
5
5
  import { c } from "react/compiler-runtime";
@@ -0,0 +1,115 @@
1
+ import { previewStore } from "./previewStore.js";
2
+ import { createStore } from "@xstate/store-react";
3
+
4
+ //#region src/features/preview/previewCommentsStore.ts
5
+ function revealCommentTarget(target) {
6
+ previewStore.send({
7
+ type: "setCommentMode",
8
+ enabled: false
9
+ });
10
+ previewStore.send({ type: "closeAddBlockSidebar" });
11
+ previewStore.send({ type: "clearPeekedBlock" });
12
+ if (target.blockId == null) {
13
+ previewStore.send({
14
+ type: "setSelection",
15
+ selection: null
16
+ });
17
+ return;
18
+ }
19
+ if (target.fieldName != null) {
20
+ previewStore.send({
21
+ type: "setSelection",
22
+ selection: target.itemId == null ? {
23
+ type: "block-field",
24
+ blockId: target.blockId,
25
+ fieldName: target.fieldName,
26
+ fieldType: target.fieldType ?? "String"
27
+ } : {
28
+ type: "item-field",
29
+ blockId: target.blockId,
30
+ itemId: target.itemId,
31
+ fieldName: target.fieldName,
32
+ fieldType: target.fieldType ?? "String"
33
+ }
34
+ });
35
+ return;
36
+ }
37
+ previewStore.send({
38
+ type: "setSelection",
39
+ selection: target.itemId == null ? {
40
+ type: "block",
41
+ blockId: target.blockId
42
+ } : {
43
+ type: "item",
44
+ blockId: target.blockId,
45
+ itemId: target.itemId
46
+ }
47
+ });
48
+ }
49
+ /** UI prototype only: comments live in memory, scoped to their originating page. */
50
+ const previewCommentsStore = createStore({
51
+ context: {
52
+ comments: [],
53
+ draft: null,
54
+ activeId: null,
55
+ focusTarget: null
56
+ },
57
+ on: {
58
+ startComment: (context, event) => ({
59
+ ...context,
60
+ draft: {
61
+ pageId: event.pageId,
62
+ target: event.target,
63
+ message: ""
64
+ },
65
+ activeId: null,
66
+ focusTarget: event.focusComposer ? event.target : null
67
+ }),
68
+ composerFocused: (context) => ({
69
+ ...context,
70
+ focusTarget: null
71
+ }),
72
+ setMessage: (context, event) => ({
73
+ ...context,
74
+ draft: context.draft ? {
75
+ ...context.draft,
76
+ message: event.message
77
+ } : null
78
+ }),
79
+ postComment: (context, event) => {
80
+ const draft = context.draft;
81
+ if (!draft?.message.trim()) return context;
82
+ return {
83
+ ...context,
84
+ comments: [...context.comments, {
85
+ ...draft,
86
+ id: event.id,
87
+ message: draft.message.trim(),
88
+ author: event.author,
89
+ createdAt: event.createdAt
90
+ }],
91
+ draft: null,
92
+ activeId: event.id,
93
+ focusTarget: null
94
+ };
95
+ },
96
+ selectComment: (context, event) => ({
97
+ ...context,
98
+ activeId: event.id
99
+ }),
100
+ cancelDraft: (context) => ({
101
+ ...context,
102
+ draft: null,
103
+ focusTarget: null
104
+ }),
105
+ clearSelection: (context) => ({
106
+ ...context,
107
+ draft: null,
108
+ activeId: null,
109
+ focusTarget: null
110
+ })
111
+ }
112
+ });
113
+
114
+ //#endregion
115
+ export { previewCommentsStore, revealCommentTarget };
@@ -0,0 +1,75 @@
1
+ import { previewStore, selectIsCommentMode, selectIsEditMode } from "./previewStore.js";
2
+ import { previewCommentsStore, revealCommentTarget } from "./previewCommentsStore.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { createContext, useContext } from "react";
5
+
6
+ //#region src/features/preview/previewSelection.ts
7
+ const PreviewPageContext = createContext(null);
8
+ /** Both editing and commenting use the target already known by the editable component. */
9
+ function selectPreviewTarget(selection, pageId, event) {
10
+ const snapshot = previewStore.getSnapshot();
11
+ if (!selectIsEditMode(snapshot)) return;
12
+ if (!selectIsCommentMode(snapshot)) {
13
+ if (selection.type === "block") {
14
+ previewStore.send({
15
+ type: "setFocusedBlock",
16
+ blockId: selection.blockId
17
+ });
18
+ return;
19
+ }
20
+ previewStore.send({
21
+ type: "setSelection",
22
+ selection
23
+ });
24
+ return;
25
+ }
26
+ if (!event) return;
27
+ event.preventDefault();
28
+ event.stopPropagation();
29
+ if (pageId === null) return;
30
+ const element = event.currentTarget;
31
+ const rect = element.getBoundingClientRect();
32
+ const field = selection.type === "block-field" || selection.type === "item-field";
33
+ const itemId = "itemId" in selection ? selection.itemId : void 0;
34
+ const attribute = field ? "data-camox-field-id" : selection.type === "item" ? "data-camox-repeater-item-id" : element.hasAttribute("data-camox-comment-block-id") ? "data-camox-comment-block-id" : "data-camox-block-id";
35
+ const id = field ? [
36
+ selection.blockId,
37
+ itemId,
38
+ selection.fieldName
39
+ ].filter((part) => part != null).join("__") : String(itemId ?? selection.blockId);
40
+ const target = {
41
+ blockId: selection.blockId,
42
+ itemId,
43
+ fieldName: field ? selection.fieldName : void 0,
44
+ fieldType: field ? selection.fieldType : void 0,
45
+ selector: `[${attribute}="${CSS.escape(id)}"]`,
46
+ label: field ? `Field · ${selection.fieldName}` : `${selection.type === "item" ? "Item" : "Block"} · ${id}`,
47
+ x: event.clientX == null ? .5 : Math.max(0, Math.min(1, (event.clientX - rect.left) / (rect.width || 1))),
48
+ y: event.clientY == null ? .5 : Math.max(0, Math.min(1, (event.clientY - rect.top) / (rect.height || 1)))
49
+ };
50
+ previewCommentsStore.send({
51
+ type: "startComment",
52
+ pageId,
53
+ target,
54
+ focusComposer: true
55
+ });
56
+ revealCommentTarget(target);
57
+ }
58
+ function usePreviewSelection() {
59
+ const $ = c(3);
60
+ if ($[0] !== "5c1128621012a50122fc348fb93c4181c8f52e6cf8c887d22b4d96421b55a5a6") {
61
+ for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
62
+ $[0] = "5c1128621012a50122fc348fb93c4181c8f52e6cf8c887d22b4d96421b55a5a6";
63
+ }
64
+ const pageId = useContext(PreviewPageContext);
65
+ let t0;
66
+ if ($[1] !== pageId) {
67
+ t0 = (selection, event) => selectPreviewTarget(selection, pageId, event);
68
+ $[1] = pageId;
69
+ $[2] = t0;
70
+ } else t0 = $[2];
71
+ return t0;
72
+ }
73
+
74
+ //#endregion
75
+ export { PreviewPageContext, usePreviewSelection };
@@ -1,4 +1,4 @@
1
- import { trackClientEvent } from "../../lib/telemetry-client.js";
1
+ import { areCommentsEnabled } from "./commentsEnabled.js";
2
2
  import { createStore } from "@xstate/store-react";
3
3
  import { toast } from "@camox/ui/toaster";
4
4
 
@@ -22,15 +22,15 @@ function selectionField(sel) {
22
22
  };
23
23
  return null;
24
24
  }
25
- const selectIsEditMode = (state) => state.context.mode === "editing-draft";
25
+ const selectIsCommentMode = (state) => state.context.mode === "commenting-draft";
26
+ /** Commenting is a draft-only editing submode. */
27
+ const selectIsEditMode = (state) => state.context.mode === "editing-draft" || selectIsCommentMode(state);
26
28
  const selectPreviewSource = (state) => state.context.mode === "previewing-live" ? "live" : "draft";
27
29
  const previewStore = createStore({
28
30
  context: {
29
31
  mode: "previewing-draft",
30
32
  isToolbarHidden: false,
31
- isPageEditorSidebarOpen: false,
32
33
  isAddBlockSidebarOpen: false,
33
- addBlockSource: null,
34
34
  isCreatePageModalOpen: false,
35
35
  editingPageId: null,
36
36
  viewportMode: "full",
@@ -41,21 +41,24 @@ const previewStore = createStore({
41
41
  iframeElement: null
42
42
  },
43
43
  on: {
44
- exitEditMode: (context, _, enqueue) => {
45
- if (context.mode !== "editing-draft") return context;
46
- enqueue.effect(() => {
47
- trackClientEvent("edit_mode_toggled", { enabled: false });
48
- });
44
+ setCommentMode: (context, event) => {
45
+ if (!selectIsEditMode({ context })) return context;
46
+ const commenting = areCommentsEnabled() && event.enabled;
47
+ return {
48
+ ...context,
49
+ mode: commenting ? "commenting-draft" : "editing-draft",
50
+ selection: commenting ? null : context.selection
51
+ };
52
+ },
53
+ exitEditMode: (context) => {
54
+ if (!selectIsEditMode({ context })) return context;
49
55
  return {
50
56
  ...context,
51
57
  mode: "previewing-draft"
52
58
  };
53
59
  },
54
- enterEditMode: (context, _, enqueue) => {
55
- if (context.mode === "editing-draft") return context;
56
- enqueue.effect(() => {
57
- trackClientEvent("edit_mode_toggled", { enabled: true });
58
- });
60
+ enterEditMode: (context) => {
61
+ if (selectIsEditMode({ context })) return context;
59
62
  return {
60
63
  ...context,
61
64
  mode: "editing-draft",
@@ -68,7 +71,6 @@ const previewStore = createStore({
68
71
  }),
69
72
  viewLivePage: (context, _, enqueue) => {
70
73
  enqueue.effect(() => {
71
- if (context.mode === "editing-draft") trackClientEvent("edit_mode_toggled", { enabled: false });
72
74
  toast("Viewing live version of the site");
73
75
  });
74
76
  return {
@@ -185,14 +187,12 @@ const previewStore = createStore({
185
187
  openAddBlockSidebar: (context, event) => ({
186
188
  ...context,
187
189
  isAddBlockSidebarOpen: true,
188
- addBlockSource: event.via ?? null,
189
190
  peekedBlock: null,
190
191
  peekedBlockPosition: event.afterPosition ?? null
191
192
  }),
192
193
  closeAddBlockSidebar: (context) => ({
193
194
  ...context,
194
195
  isAddBlockSidebarOpen: false,
195
- addBlockSource: null,
196
196
  peekedBlock: null,
197
197
  peekedBlockPosition: null
198
198
  }),
@@ -211,25 +211,6 @@ const previewStore = createStore({
211
211
  ...context,
212
212
  skipPeekedBlockExitAnimation: false
213
213
  }),
214
- toggleContentSheet: (context) => ({
215
- ...context,
216
- isPageEditorSidebarOpen: false
217
- }),
218
- openBlockContentSheet: (context, event) => {
219
- const currentBlockMatches = context.selection?.blockId === event.blockId;
220
- return {
221
- ...context,
222
- isPageEditorSidebarOpen: false,
223
- selection: currentBlockMatches ? context.selection : {
224
- type: "block",
225
- blockId: event.blockId
226
- }
227
- };
228
- },
229
- closeBlockContentSheet: (context) => ({
230
- ...context,
231
- isPageEditorSidebarOpen: false
232
- }),
233
214
  openCreatePageModal: (context) => ({
234
215
  ...context,
235
216
  isCreatePageModalOpen: true
@@ -238,9 +219,8 @@ const previewStore = createStore({
238
219
  ...context,
239
220
  isCreatePageModalOpen: false
240
221
  }),
241
- openEditPageModal: (context, event, enqueue) => {
222
+ openEditPageModal: (context, event) => {
242
223
  if (context.editingPageId === event.pageId) return context;
243
- enqueue.effect(() => trackClientEvent("page_editor_opened", { pageId: event.pageId }));
244
224
  return {
245
225
  ...context,
246
226
  editingPageId: event.pageId
@@ -269,4 +249,4 @@ const previewStore = createStore({
269
249
  });
270
250
 
271
251
  //#endregion
272
- export { previewStore, selectIsEditMode, selectPreviewSource, selectionBlockId, selectionField, selectionItemId };
252
+ export { previewStore, selectIsCommentMode, selectIsEditMode, selectPreviewSource, selectionBlockId, selectionField, selectionItemId };
@@ -5,6 +5,16 @@
5
5
  * not a separate publishing UI or a sequence of independent block requests.
6
6
  */
7
7
  function buildPublicationPlan(target) {
8
+ if (target.kind === "layout" && target.layout.kind === "singleton") return {
9
+ title: "Publish page content",
10
+ description: `Publishes the editable blocks on ${target.name}. The route and application data are controlled by code, not publishing.`,
11
+ items: [{
12
+ key: `layout:${target.layout.id}`,
13
+ label: `${target.name} blocks`,
14
+ impact: "Updates this page’s before and after blocks. Synced block changes also apply wherever those blocks are used.",
15
+ optional: false
16
+ }]
17
+ };
8
18
  if (target.kind === "layout") return {
9
19
  title: target.layout.status === "modified" ? "Publish changes" : "Publish layout",
10
20
  description: `Publishes ${target.name} on every page using this layout. Generated content and external data are not published by this action.`,
@@ -1,12 +1,12 @@
1
1
  import { AuthContext, useAuthActions } from "../../lib/auth.js";
2
2
  import { projectQueries } from "../../lib/queries.js";
3
- import { identifyProject, identifyUser } from "../../lib/telemetry-client.js";
4
3
  import { useApplyTheme, useThemeActions } from "../studio/useTheme.js";
5
4
  import { useNavbarActions } from "../studio/components/Navbar.js";
6
5
  import { usePreviewPagesActions } from "../preview/CamoxPreview.js";
7
6
  import { useProjectRoom } from "../../lib/use-project-room.js";
8
7
  import { CommandPalette, useCommandPaletteActions } from "./components/CommandPalette.js";
9
8
  import { useAdminShortcuts } from "./useAdminShortcuts.js";
9
+ import { c } from "react/compiler-runtime";
10
10
  import { useQuery } from "@tanstack/react-query";
11
11
  import * as React from "react";
12
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -14,50 +14,62 @@ import { Toaster } from "@camox/ui/toaster";
14
14
  import studioCssUrl from "virtual:camox-studio-css";
15
15
 
16
16
  //#region src/features/provider/AuthenticatedCamoxProvider.tsx
17
- function AuthenticatedCamoxProvider({ children }) {
17
+ function AuthenticatedCamoxProvider(t0) {
18
+ const $ = c(10);
19
+ if ($[0] !== "5934dd91b5a9b867275ab8801058e109f6352a3ac512ceb2f083d56bd54b2d7a") {
20
+ for (let $i = 0; $i < 10; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
21
+ $[0] = "5934dd91b5a9b867275ab8801058e109f6352a3ac512ceb2f083d56bd54b2d7a";
22
+ }
23
+ const { children } = t0;
18
24
  useAdminShortcuts();
19
25
  useCommandPaletteActions();
20
26
  useThemeActions();
21
27
  useAuthActions();
22
28
  useNavbarActions();
23
29
  usePreviewPagesActions();
24
- const { authClient, apiUrl, projectSlug, environmentName } = React.useContext(AuthContext);
25
- const { data: session } = authClient.useSession();
26
- const { data: project } = useQuery(projectQueries.getBySlug(projectSlug));
30
+ const { apiUrl, projectSlug } = React.useContext(AuthContext);
31
+ let t1;
32
+ if ($[1] !== projectSlug) {
33
+ t1 = projectQueries.getBySlug(projectSlug);
34
+ $[1] = projectSlug;
35
+ $[2] = t1;
36
+ } else t1 = $[2];
37
+ const { data: project } = useQuery(t1);
27
38
  useProjectRoom(apiUrl, project?.id);
28
- React.useEffect(() => {
29
- const user = session?.user;
30
- if (!user) return;
31
- identifyUser({
32
- userId: user.id,
33
- email: user.email,
34
- name: user.name
35
- });
36
- }, [session?.user]);
37
- React.useEffect(() => {
38
- if (!project) return;
39
- identifyProject({
40
- projectId: project.id,
41
- projectSlug,
42
- projectName: project.name,
43
- environmentName
44
- });
45
- }, [
46
- environmentName,
47
- project,
48
- projectSlug
49
- ]);
50
39
  const { resolvedTheme } = useApplyTheme();
51
- return /* @__PURE__ */ jsxs(Fragment, { children: [
52
- /* @__PURE__ */ jsx("link", {
40
+ let t2;
41
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t2 = /* @__PURE__ */ jsx("link", {
53
43
  rel: "stylesheet",
54
44
  href: studioCssUrl,
55
45
  "data-camox-studio": true
56
- }),
57
- children,
58
- /* @__PURE__ */ jsx(Toaster, { theme: resolvedTheme }),
59
- /* @__PURE__ */ jsx(CommandPalette, {})
60
- ] });
46
+ });
47
+ $[3] = t2;
48
+ } else t2 = $[3];
49
+ let t3;
50
+ if ($[4] !== resolvedTheme) {
51
+ t3 = /* @__PURE__ */ jsx(Toaster, { theme: resolvedTheme });
52
+ $[4] = resolvedTheme;
53
+ $[5] = t3;
54
+ } else t3 = $[5];
55
+ let t4;
56
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t4 = /* @__PURE__ */ jsx(CommandPalette, {});
58
+ $[6] = t4;
59
+ } else t4 = $[6];
60
+ let t5;
61
+ if ($[7] !== children || $[8] !== t3) {
62
+ t5 = /* @__PURE__ */ jsxs(Fragment, { children: [
63
+ t2,
64
+ children,
65
+ t3,
66
+ t4
67
+ ] });
68
+ $[7] = children;
69
+ $[8] = t3;
70
+ $[9] = t5;
71
+ } else t5 = $[9];
72
+ return t5;
61
73
  }
62
74
 
63
75
  //#endregion
@@ -1,7 +1,7 @@
1
1
  import { AuthContext, createCamoxAuthClient, useProcessOtt } from "../../lib/auth.js";
2
2
  import { initApiClient } from "../../lib/api-client.js";
3
- import { projectQueries } from "../../lib/queries.js";
4
3
  import { CamoxAppProvider } from "./components/CamoxAppContext.js";
4
+ import { projectQueries } from "../../lib/queries.js";
5
5
  import { useQueryClient } from "@tanstack/react-query";
6
6
  import * as React from "react";
7
7
  import { jsx } from "react/jsx-runtime";