camox 0.42.0 → 0.44.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.
- package/bin/camox.mjs +9 -1
- package/dist/core/components/lexical/{GradientNode.js → HighlightNode.js} +34 -34
- package/dist/core/components/lexical/InlineLexicalEditor.js +14 -14
- package/dist/core/components/lexical/InlineStylesPlugin.js +25 -9
- package/dist/core/components/lexical/SelectionBroadcaster.js +7 -7
- package/dist/core/components/lexical/SidebarLexicalEditor.js +24 -24
- package/dist/core/components/lexical/TextLinkPopover.js +191 -208
- package/dist/core/components/lexical/editorConfig.js +2 -2
- package/dist/core/createApp.d.ts +31 -4
- package/dist/core/createApp.js +2 -1
- package/dist/core/createBlock.js +24 -10
- package/dist/core/createLayout.d.ts +16 -3
- package/dist/core/createLayout.js +15 -15
- package/dist/core/derivedRoutes.js +1 -1
- package/dist/core/dom.d.ts +17 -0
- package/dist/core/dom.js +22 -0
- package/dist/core/editing/createEditableBlock.d.ts +135 -1
- package/dist/core/editing/createEditableBlock.js +209 -74
- package/dist/core/lib/contentType.d.ts +5 -0
- package/dist/core/lib/contentType.js +11 -0
- package/dist/core/lib/fieldTypes.js +1 -0
- package/dist/core/lib/iconTypes.d.ts +13 -0
- package/dist/core/lib/icons.d.ts +6 -0
- package/dist/core/lib/icons.js +130 -0
- package/dist/core/lib/lexicalReact.js +4 -4
- package/dist/core/lib/lexicalState.js +8 -8
- package/dist/core/lib/modifierFormats.js +2 -2
- package/dist/core/lib/textLinks.js +5 -2
- package/dist/core/lib/textStyles.d.ts +3 -3
- package/dist/core/lib/textStyles.js +9 -14
- package/dist/core/pageDestinations.js +37 -0
- package/dist/features/content/components/AssetCard.js +104 -68
- package/dist/features/og/imageResponse.node.js +11 -9
- package/dist/features/preview/CamoxPreview.js +148 -146
- package/dist/features/preview/commentsEnabled.js +2 -2
- package/dist/features/preview/components/AddBlockSidebar.js +1 -1
- package/dist/features/preview/components/AssetLightbox.js +17 -6
- package/dist/features/preview/components/AttachedComments.js +224 -87
- package/dist/features/preview/components/BlockActionsPopover.js +1 -1
- package/dist/features/preview/components/CommentTargetQuote.js +22 -21
- package/dist/features/preview/components/CreatePageModal.js +4 -4
- package/dist/features/preview/components/DerivedLayoutDialog.js +36 -21
- package/dist/features/preview/components/DerivedLayoutSidebar.js +45 -26
- package/dist/features/preview/components/DerivedPageInfoSidebar.js +38 -26
- package/dist/features/preview/components/FieldOverlayStyles.js +29 -9
- package/dist/features/preview/components/FieldToolbar.js +12 -12
- package/dist/features/preview/components/IconFieldEditor.js +231 -0
- package/dist/features/preview/components/ItemFieldsEditor.js +21 -14
- package/dist/features/preview/components/LinkFieldEditor.js +212 -209
- package/dist/features/preview/components/OverlayTracker.js +1 -1
- package/dist/features/preview/components/PageEditorSidebar.js +1 -1
- package/dist/features/preview/components/PageInfoSidebar.js +28 -28
- package/dist/features/preview/components/PagePicker.js +46 -46
- package/dist/features/preview/components/PageTree.js +1 -1
- package/dist/features/preview/components/PreviewPanel.js +1 -1
- package/dist/features/preview/components/PreviewToolbar.js +224 -225
- package/dist/features/preview/components/PublicationRow.js +8 -4
- package/dist/features/preview/components/SendFeedbackDialog.js +83 -0
- package/dist/features/preview/components/useRepeatableItemActions.js +1 -1
- package/dist/features/preview/overlayHighlights.js +54 -0
- package/dist/features/preview/previewCommentsStore.js +54 -34
- package/dist/features/preview/previewSelection.js +28 -23
- package/dist/features/preview/publication.js +10 -0
- package/dist/features/preview/usePageComments.js +39 -0
- package/dist/features/provider/CoreCamoxProvider.js +38 -6
- package/dist/features/provider/LocalhostPreviewProvider.js +81 -45
- package/dist/features/provider/components/CommandPalette.js +35 -84
- package/dist/features/runtime/pageApp.js +32 -28
- package/dist/features/runtime/pageServer.js +4 -1
- package/dist/features/runtime/runtime.d.ts +2 -0
- package/dist/features/runtime/runtime.js +45 -21
- package/dist/features/studio/components/EnvironmentMenu.js +76 -63
- package/dist/features/studio/components/Navbar.js +53 -80
- package/dist/features/vite/auth.js +1 -50
- package/dist/features/vite/iconGeneration.js +16 -0
- package/dist/features/vite/layoutGeneration.js +7 -3
- package/dist/features/vite/vite.d.ts +4 -2
- package/dist/features/vite/vite.js +24 -3
- package/dist/hooks/use-page-destinations.js +53 -0
- package/dist/lib/auth.js +40 -20
- package/dist/lib/preview-handoff.js +13 -0
- package/dist/lib/queries.js +12 -1
- package/dist/lib/server-auth-cookie.js +21 -0
- package/dist/lib/use-project-room.js +5 -2
- package/dist/studio-overlays.css +19 -15
- package/dist/studio.css +1 -1
- package/package.json +9 -4
- package/skills/camox/SKILL.md +38 -9
- package/skills/camox/references/block-definitions.md +107 -286
- package/skills/camox/references/cli-common.md +16 -4
- package/skills/camox/references/cli-content.md +158 -0
- package/skills/camox/references/cli-environments.md +1 -1
- package/skills/camox/references/dom-integrations.md +93 -0
- package/skills/camox/references/field-styling.md +50 -0
- package/skills/camox/references/layout-definitions.md +33 -147
- package/skills/camox/references/routed-layouts.md +71 -0
- package/skills/camoxify/SKILL.md +66 -0
- package/skills/camox/references/cli-blocks.md +0 -78
- package/skills/camox/references/cli-pages.md +0 -53
|
@@ -1,34 +1,148 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
|
|
2
|
+
import { blockQueries, commentMutations, commentQueries } from "../../../lib/queries.js";
|
|
3
|
+
import { areCommentsEnabled } from "../commentsEnabled.js";
|
|
2
4
|
import { previewStore } from "../previewStore.js";
|
|
3
|
-
import { previewCommentsStore, revealCommentTarget } from "../previewCommentsStore.js";
|
|
5
|
+
import { getCommentTargetFieldType, previewCommentsStore, revealCommentTarget } from "../previewCommentsStore.js";
|
|
6
|
+
import { usePageComments } from "../usePageComments.js";
|
|
4
7
|
import { CommentHeader } from "./CommentHeader.js";
|
|
5
8
|
import { CommentTargetQuote } from "./CommentTargetQuote.js";
|
|
9
|
+
import { SendFeedbackDialog } from "./SendFeedbackDialog.js";
|
|
6
10
|
import { SidebarSection, SidebarSectionContent, SidebarSectionHeader } from "./SidebarSection.js";
|
|
11
|
+
import { c } from "react/compiler-runtime";
|
|
12
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
7
13
|
import * as React from "react";
|
|
8
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
15
|
import { useSelector } from "@xstate/store-react";
|
|
16
|
+
import { COMMENT_MESSAGE_MAX_LENGTH } from "@camox/api-contract";
|
|
10
17
|
import { Button } from "@camox/ui/button";
|
|
11
|
-
import { ArrowUp, X } from "lucide-react";
|
|
18
|
+
import { Archive, ArrowUp, CornerLeftUp, Eye, X } from "lucide-react";
|
|
19
|
+
import { toast } from "@camox/ui/toaster";
|
|
12
20
|
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from "@camox/ui/input-group";
|
|
21
|
+
import { ButtonGroup } from "@camox/ui/button-group";
|
|
13
22
|
|
|
14
23
|
//#region src/features/preview/components/AttachedComments.tsx
|
|
15
24
|
function resizeComposer(element) {
|
|
16
25
|
element.style.height = "auto";
|
|
17
26
|
element.style.height = `${element.scrollHeight}px`;
|
|
18
27
|
}
|
|
28
|
+
function editorTarget({ blockId, itemId, fieldName }) {
|
|
29
|
+
if (blockId == null) return { kind: "page" };
|
|
30
|
+
if (itemId != null) {
|
|
31
|
+
if (fieldName != null) return {
|
|
32
|
+
kind: "item-field",
|
|
33
|
+
blockId,
|
|
34
|
+
itemId,
|
|
35
|
+
fieldName
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
kind: "item",
|
|
39
|
+
blockId,
|
|
40
|
+
itemId
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (fieldName != null) return {
|
|
44
|
+
kind: "block-field",
|
|
45
|
+
blockId,
|
|
46
|
+
fieldName
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
kind: "block",
|
|
50
|
+
blockId
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** Gate before mounting queries, mutations, or composers. */
|
|
54
|
+
function AttachedComments(props) {
|
|
55
|
+
const $ = c(3);
|
|
56
|
+
if ($[0] !== "8254f8bf23ff0138d71d56295c89e5b6eb791bb39cd29713ed38f79fecd96403") {
|
|
57
|
+
for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
58
|
+
$[0] = "8254f8bf23ff0138d71d56295c89e5b6eb791bb39cd29713ed38f79fecd96403";
|
|
59
|
+
}
|
|
60
|
+
if (!areCommentsEnabled() || props.pageId == null) return null;
|
|
61
|
+
let t0;
|
|
62
|
+
if ($[1] !== props) {
|
|
63
|
+
t0 = /* @__PURE__ */ jsx(EnabledAttachedComments, {
|
|
64
|
+
...props,
|
|
65
|
+
pageId: props.pageId
|
|
66
|
+
});
|
|
67
|
+
$[1] = props;
|
|
68
|
+
$[2] = t0;
|
|
69
|
+
} else t0 = $[2];
|
|
70
|
+
return t0;
|
|
71
|
+
}
|
|
19
72
|
/** Shared comment list and composer for editors and the Feedback sidebar. */
|
|
20
|
-
function
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
73
|
+
function EnabledAttachedComments({ pageId, blockId, itemId, fieldName, allPageComments = false }) {
|
|
74
|
+
const camoxApp = useCamoxApp();
|
|
75
|
+
const queryClient = useQueryClient();
|
|
76
|
+
const commentsQuery = usePageComments(pageId);
|
|
77
|
+
const { draft, activeId, focusTarget } = useSelector(previewCommentsStore, (state) => state.context);
|
|
78
|
+
const target = editorTarget({
|
|
79
|
+
blockId,
|
|
80
|
+
itemId,
|
|
81
|
+
fieldName
|
|
82
|
+
});
|
|
83
|
+
const matches = (entry) => entry.pageId === pageId && (allPageComments || entry.target != null && entry.target.kind === target.kind && (!("blockId" in entry.target) || entry.target.blockId === blockId) && (!("itemId" in entry.target) || entry.target.itemId === itemId) && (!("fieldName" in entry.target) || entry.target.fieldName === fieldName));
|
|
84
|
+
const attached = (commentsQuery.data ?? []).filter(matches);
|
|
85
|
+
const visible = attached.filter((comment) => !comment.resolved);
|
|
26
86
|
const currentDraft = draft && matches(draft) ? draft : null;
|
|
27
|
-
const selected = attached.find((
|
|
87
|
+
const selected = attached.find((comment_0) => comment_0.id === activeId);
|
|
28
88
|
const textarea = React.useRef(null);
|
|
29
89
|
const activeComment = React.useRef(null);
|
|
30
90
|
const draftTarget = currentDraft?.target;
|
|
31
91
|
const message = currentDraft?.message ?? "";
|
|
92
|
+
const submitting = React.useRef(false);
|
|
93
|
+
const setResolved = useMutation({
|
|
94
|
+
...commentMutations.setResolved(),
|
|
95
|
+
onSuccess: (comment_1, submitted) => {
|
|
96
|
+
const queryKey = commentQueries.list(submitted.pageId).queryKey;
|
|
97
|
+
queryClient.setQueryData(queryKey, (comments) => comments?.map((entry_0) => entry_0.id === comment_1.id ? comment_1 : entry_0));
|
|
98
|
+
queryClient.invalidateQueries({ queryKey });
|
|
99
|
+
},
|
|
100
|
+
onError: () => toast.error("Could not update feedback. Please try again.")
|
|
101
|
+
});
|
|
102
|
+
const createComment = useMutation({
|
|
103
|
+
...commentMutations.create(),
|
|
104
|
+
onSuccess: (comment_2, submitted_0) => {
|
|
105
|
+
const queryKey_0 = commentQueries.list(submitted_0.pageId).queryKey;
|
|
106
|
+
queryClient.setQueryData(queryKey_0, (comments_0) => {
|
|
107
|
+
if (!comments_0) return void 0;
|
|
108
|
+
return [...comments_0.filter((entry_1) => entry_1.id !== comment_2.id), comment_2].sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id));
|
|
109
|
+
});
|
|
110
|
+
queryClient.invalidateQueries({ queryKey: queryKey_0 });
|
|
111
|
+
previewCommentsStore.send({
|
|
112
|
+
type: "postSucceeded",
|
|
113
|
+
draft: submitted_0
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
onSettled: () => {
|
|
117
|
+
submitting.current = false;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
const selectComment = async (id, target_0) => {
|
|
121
|
+
previewCommentsStore.send({
|
|
122
|
+
type: "selectComment",
|
|
123
|
+
id
|
|
124
|
+
});
|
|
125
|
+
if (target_0.kind === "page") {
|
|
126
|
+
revealCommentTarget(target_0);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const bundle = await queryClient.fetchQuery(blockQueries.get(target_0.blockId));
|
|
131
|
+
if (previewCommentsStore.getSnapshot().context.activeId !== id) return;
|
|
132
|
+
if ("itemId" in target_0 && !bundle.repeatableItems.some((item) => item.id === target_0.itemId)) {
|
|
133
|
+
toast.error("This feedback target is no longer available.");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const fieldType = getCommentTargetFieldType(target_0, bundle, camoxApp);
|
|
137
|
+
if ("fieldName" in target_0 && !fieldType) {
|
|
138
|
+
toast.error("This feedback field is no longer available.");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
revealCommentTarget(target_0, fieldType);
|
|
142
|
+
} catch {
|
|
143
|
+
toast.error("This feedback target is no longer available.");
|
|
144
|
+
}
|
|
145
|
+
};
|
|
32
146
|
React.useLayoutEffect(() => {
|
|
33
147
|
if (textarea.current) resizeComposer(textarea.current);
|
|
34
148
|
}, [message, pageId]);
|
|
@@ -45,17 +159,9 @@ function AttachedComments({ pageId, blockId, itemId, fieldName, fieldType, allPa
|
|
|
45
159
|
return () => observer.disconnect();
|
|
46
160
|
}, [pageId]);
|
|
47
161
|
const submit = () => {
|
|
48
|
-
if (!message.trim()) return;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
id: crypto.randomUUID(),
|
|
52
|
-
author: {
|
|
53
|
-
name: session?.user.name || "You",
|
|
54
|
-
image: session?.user.image ?? null
|
|
55
|
-
},
|
|
56
|
-
createdAt: Date.now()
|
|
57
|
-
});
|
|
58
|
-
textarea.current?.focus({ preventScroll: true });
|
|
162
|
+
if (!areCommentsEnabled() || !currentDraft || !message.trim() || submitting.current) return;
|
|
163
|
+
submitting.current = true;
|
|
164
|
+
createComment.mutate(currentDraft);
|
|
59
165
|
};
|
|
60
166
|
React.useEffect(() => {
|
|
61
167
|
if (!draftTarget || focusTarget !== draftTarget || !textarea.current) return;
|
|
@@ -67,7 +173,6 @@ function AttachedComments({ pageId, blockId, itemId, fieldName, fieldType, allPa
|
|
|
67
173
|
if (!selected) return;
|
|
68
174
|
activeComment.current?.scrollIntoView({ block: "nearest" });
|
|
69
175
|
}, [selected]);
|
|
70
|
-
if (pageId == null) return null;
|
|
71
176
|
return /* @__PURE__ */ jsxs(SidebarSection, {
|
|
72
177
|
"aria-label": allPageComments ? "Feedback" : blockId == null ? "Page comments" : fieldName ? `Comments on ${fieldName}` : itemId == null ? "Block comments" : "Item comments",
|
|
73
178
|
divider: allPageComments ? "none" : "top",
|
|
@@ -88,50 +193,92 @@ function AttachedComments({ pageId, blockId, itemId, fieldName, fieldType, allPa
|
|
|
88
193
|
children: /* @__PURE__ */ jsx(X, { className: "text-muted-foreground" })
|
|
89
194
|
})]
|
|
90
195
|
}) : /* @__PURE__ */ jsx(SidebarSectionHeader, { children: "Feedback" }), /* @__PURE__ */ jsxs(SidebarSectionContent, { children: [
|
|
91
|
-
|
|
196
|
+
commentsQuery.isPending && /* @__PURE__ */ jsx("p", {
|
|
92
197
|
className: "text-muted-foreground text-sm",
|
|
93
|
-
children: "
|
|
198
|
+
children: "Loading feedback…"
|
|
94
199
|
}),
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
200
|
+
commentsQuery.isError && /* @__PURE__ */ jsxs("div", {
|
|
201
|
+
role: "alert",
|
|
202
|
+
className: "text-sm",
|
|
203
|
+
children: [
|
|
204
|
+
"Could not load feedback.",
|
|
205
|
+
" ",
|
|
206
|
+
/* @__PURE__ */ jsx(Button, {
|
|
207
|
+
type: "button",
|
|
208
|
+
variant: "link",
|
|
209
|
+
onClick: () => void commentsQuery.refetch(),
|
|
210
|
+
children: "Retry"
|
|
211
|
+
})
|
|
212
|
+
]
|
|
213
|
+
}),
|
|
214
|
+
allPageComments && commentsQuery.isSuccess && visible.length === 0 && /* @__PURE__ */ jsxs("p", {
|
|
215
|
+
className: "text-muted-foreground text-sm",
|
|
216
|
+
children: [attached.length === 0 ? "No feedback yet." : "No unresolved feedback.", " Select something on the page to comment on it."]
|
|
217
|
+
}),
|
|
218
|
+
visible.map((comment_3) => /* @__PURE__ */ jsxs("div", {
|
|
219
|
+
ref: comment_3.id === activeId ? activeComment : void 0,
|
|
220
|
+
className: "rounded-md p-1",
|
|
221
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(CommentHeader, {
|
|
222
|
+
author: comment_3.author,
|
|
223
|
+
createdAt: comment_3.createdAt
|
|
117
224
|
}), /* @__PURE__ */ jsxs("div", {
|
|
118
225
|
className: "pl-8",
|
|
119
|
-
children: [allPageComments && /* @__PURE__ */ jsx(CommentTargetQuote, {
|
|
226
|
+
children: [allPageComments && (comment_3.target ? /* @__PURE__ */ jsx(CommentTargetQuote, {
|
|
120
227
|
pageId,
|
|
121
|
-
target:
|
|
122
|
-
})
|
|
228
|
+
target: comment_3.target
|
|
229
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
230
|
+
className: "text-muted-foreground text-sm",
|
|
231
|
+
children: "Target no longer available"
|
|
232
|
+
})), /* @__PURE__ */ jsx("p", {
|
|
123
233
|
className: "text-sm wrap-break-word whitespace-pre-wrap",
|
|
124
|
-
children:
|
|
234
|
+
children: comment_3.message
|
|
125
235
|
})]
|
|
236
|
+
})] }), /* @__PURE__ */ jsxs(ButtonGroup, {
|
|
237
|
+
className: "mt-2 ml-8",
|
|
238
|
+
"aria-label": "Comment actions",
|
|
239
|
+
children: [
|
|
240
|
+
allPageComments && /* @__PURE__ */ jsxs(Button, {
|
|
241
|
+
type: "button",
|
|
242
|
+
variant: "outline",
|
|
243
|
+
size: "sm",
|
|
244
|
+
disabled: comment_3.target == null,
|
|
245
|
+
onClick: () => {
|
|
246
|
+
if (comment_3.target) selectComment(comment_3.id, comment_3.target);
|
|
247
|
+
},
|
|
248
|
+
children: [/* @__PURE__ */ jsx(Eye, { className: "text-muted-foreground" }), "View"]
|
|
249
|
+
}),
|
|
250
|
+
!allPageComments && /* @__PURE__ */ jsxs(Button, {
|
|
251
|
+
type: "button",
|
|
252
|
+
variant: "outline",
|
|
253
|
+
size: "sm",
|
|
254
|
+
onClick: () => previewStore.send({
|
|
255
|
+
type: "setCommentMode",
|
|
256
|
+
enabled: true
|
|
257
|
+
}),
|
|
258
|
+
children: [/* @__PURE__ */ jsx(CornerLeftUp, { className: "text-muted-foreground" }), "See all"]
|
|
259
|
+
}),
|
|
260
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
261
|
+
type: "button",
|
|
262
|
+
variant: "outline",
|
|
263
|
+
size: "sm",
|
|
264
|
+
"aria-label": "Archive comment",
|
|
265
|
+
disabled: setResolved.isPending,
|
|
266
|
+
onClick: () => {
|
|
267
|
+
setResolved.mutate({
|
|
268
|
+
pageId,
|
|
269
|
+
id: comment_3.id,
|
|
270
|
+
resolved: true
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
children: [/* @__PURE__ */ jsx(Archive, { className: "text-muted-foreground" }), "Archive"]
|
|
274
|
+
})
|
|
275
|
+
]
|
|
126
276
|
})]
|
|
127
|
-
},
|
|
128
|
-
allPageComments && /* @__PURE__ */ jsx(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
disabled: attached.length === 0,
|
|
133
|
-
children: "Send feedback to agent..."
|
|
134
|
-
}),
|
|
277
|
+
}, comment_3.id)),
|
|
278
|
+
allPageComments && /* @__PURE__ */ jsx(SendFeedbackDialog, {
|
|
279
|
+
pageId,
|
|
280
|
+
disabled: visible.length === 0
|
|
281
|
+
}, pageId),
|
|
135
282
|
!allPageComments && /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupTextarea, {
|
|
136
283
|
ref: textarea,
|
|
137
284
|
"aria-label": "Comment text",
|
|
@@ -139,37 +286,22 @@ function AttachedComments({ pageId, blockId, itemId, fieldName, fieldType, allPa
|
|
|
139
286
|
className: "block field-sizing-fixed min-h-0 flex-none overflow-hidden leading-6",
|
|
140
287
|
rows: 1,
|
|
141
288
|
value: message,
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
289
|
+
maxLength: COMMENT_MESSAGE_MAX_LENGTH,
|
|
290
|
+
onKeyDown: (event) => {
|
|
291
|
+
if (event.key !== "Enter" || event.shiftKey || event.nativeEvent.isComposing) return;
|
|
292
|
+
event.preventDefault();
|
|
293
|
+
event.stopPropagation();
|
|
146
294
|
submit();
|
|
147
295
|
},
|
|
148
|
-
onChange: (
|
|
149
|
-
if (!currentDraft) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
].filter((part) => part != null).join("__");
|
|
155
|
-
previewCommentsStore.send({
|
|
156
|
-
type: "startComment",
|
|
157
|
-
pageId,
|
|
158
|
-
target: {
|
|
159
|
-
blockId,
|
|
160
|
-
itemId,
|
|
161
|
-
fieldName,
|
|
162
|
-
fieldType,
|
|
163
|
-
selector: blockId == null ? "body" : fieldName != null ? `[data-camox-field-id="${CSS.escape(fieldId)}"]` : itemId != null ? `[data-camox-repeater-item-id="${itemId}"]` : `[data-camox-block-id="${blockId}"]`,
|
|
164
|
-
label: blockId == null ? `Page · ${pageId}` : fieldName != null ? `Field · ${fieldName}` : itemId != null ? `Item · ${itemId}` : `Block · ${blockId}`,
|
|
165
|
-
x: .5,
|
|
166
|
-
y: .5
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
296
|
+
onChange: (event_0) => {
|
|
297
|
+
if (!currentDraft) previewCommentsStore.send({
|
|
298
|
+
type: "startComment",
|
|
299
|
+
pageId,
|
|
300
|
+
target
|
|
301
|
+
});
|
|
170
302
|
previewCommentsStore.send({
|
|
171
303
|
type: "setMessage",
|
|
172
|
-
message:
|
|
304
|
+
message: event_0.target.value
|
|
173
305
|
});
|
|
174
306
|
}
|
|
175
307
|
}), /* @__PURE__ */ jsx(InputGroupAddon, {
|
|
@@ -181,11 +313,16 @@ function AttachedComments({ pageId, blockId, itemId, fieldName, fieldType, allPa
|
|
|
181
313
|
variant: "default",
|
|
182
314
|
className: "rounded-full",
|
|
183
315
|
"aria-label": "Post comment",
|
|
184
|
-
disabled: !message.trim(),
|
|
316
|
+
disabled: !message.trim() || createComment.isPending,
|
|
185
317
|
onClick: submit,
|
|
186
318
|
children: /* @__PURE__ */ jsx(ArrowUp, { size: 16 })
|
|
187
319
|
})
|
|
188
|
-
})] })
|
|
320
|
+
})] }),
|
|
321
|
+
createComment.isError && currentDraft?.id === createComment.variables?.id && /* @__PURE__ */ jsx("p", {
|
|
322
|
+
role: "alert",
|
|
323
|
+
className: "text-destructive text-sm",
|
|
324
|
+
children: "Could not post feedback. Your draft is saved here; try posting again."
|
|
325
|
+
})
|
|
189
326
|
] })]
|
|
190
327
|
});
|
|
191
328
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { actionsStore } from "../../provider/actionsStore.js";
|
|
2
2
|
import { usePageBlocks } from "../../../lib/normalized-data.js";
|
|
3
|
+
import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
|
|
3
4
|
import { blockMutations, repeatableItemMutations } from "../../../lib/queries.js";
|
|
4
5
|
import { formatShortcut } from "../../../lib/utils.js";
|
|
5
|
-
import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
|
|
6
6
|
import { previewStore, selectionItemId } from "../previewStore.js";
|
|
7
7
|
import { useRequireDraftSource } from "../../../core/hooks/useRequireDraftSource.js";
|
|
8
8
|
import { useUpdateBlockPosition } from "./useUpdateBlockPosition.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { isLexicalState, lexicalStateToPlainText } from "../../../core/lib/lexicalState.js";
|
|
2
|
+
import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
|
|
2
3
|
import { blockQueries, pageQueries } from "../../../lib/queries.js";
|
|
4
|
+
import { getCommentTargetFieldType } from "../previewCommentsStore.js";
|
|
3
5
|
import { c } from "react/compiler-runtime";
|
|
4
6
|
import { useQuery } from "@tanstack/react-query";
|
|
5
7
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -7,9 +9,9 @@ import { jsx } from "react/jsx-runtime";
|
|
|
7
9
|
//#region src/features/preview/components/CommentTargetQuote.tsx
|
|
8
10
|
function Quote(t0) {
|
|
9
11
|
const $ = c(3);
|
|
10
|
-
if ($[0] !== "
|
|
12
|
+
if ($[0] !== "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab") {
|
|
11
13
|
for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
12
|
-
$[0] = "
|
|
14
|
+
$[0] = "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab";
|
|
13
15
|
}
|
|
14
16
|
const { children } = t0;
|
|
15
17
|
let t1;
|
|
@@ -25,9 +27,9 @@ function Quote(t0) {
|
|
|
25
27
|
}
|
|
26
28
|
function PageQuote(t0) {
|
|
27
29
|
const $ = c(5);
|
|
28
|
-
if ($[0] !== "
|
|
30
|
+
if ($[0] !== "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab") {
|
|
29
31
|
for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
30
|
-
$[0] = "
|
|
32
|
+
$[0] = "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab";
|
|
31
33
|
}
|
|
32
34
|
const { pageId } = t0;
|
|
33
35
|
let t1;
|
|
@@ -48,11 +50,12 @@ function PageQuote(t0) {
|
|
|
48
50
|
}
|
|
49
51
|
function BlockQuote(t0) {
|
|
50
52
|
const $ = c(19);
|
|
51
|
-
if ($[0] !== "
|
|
53
|
+
if ($[0] !== "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab") {
|
|
52
54
|
for (let $i = 0; $i < 19; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
53
|
-
$[0] = "
|
|
55
|
+
$[0] = "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab";
|
|
54
56
|
}
|
|
55
57
|
const { target } = t0;
|
|
58
|
+
const app = useCamoxApp();
|
|
56
59
|
let t1;
|
|
57
60
|
if ($[1] !== target.blockId) {
|
|
58
61
|
t1 = blockQueries.get(target.blockId);
|
|
@@ -71,11 +74,11 @@ function BlockQuote(t0) {
|
|
|
71
74
|
return t3;
|
|
72
75
|
}
|
|
73
76
|
let t2;
|
|
74
|
-
if ($[5] !== bundle.block || $[6] !== bundle.repeatableItems || $[7] !== target
|
|
75
|
-
t2 =
|
|
77
|
+
if ($[5] !== bundle.block || $[6] !== bundle.repeatableItems || $[7] !== target) {
|
|
78
|
+
t2 = "itemId" in target ? bundle.repeatableItems.find((item) => item.id === target.itemId) : bundle.block;
|
|
76
79
|
$[5] = bundle.block;
|
|
77
80
|
$[6] = bundle.repeatableItems;
|
|
78
|
-
$[7] = target
|
|
81
|
+
$[7] = target;
|
|
79
82
|
$[8] = t2;
|
|
80
83
|
} else t2 = $[8];
|
|
81
84
|
const subject = t2;
|
|
@@ -87,9 +90,10 @@ function BlockQuote(t0) {
|
|
|
87
90
|
} else t3 = $[9];
|
|
88
91
|
return t3;
|
|
89
92
|
}
|
|
90
|
-
if (
|
|
93
|
+
if ("fieldName" in target) {
|
|
94
|
+
const fieldType = getCommentTargetFieldType(target, bundle, app);
|
|
91
95
|
const value = subject.content[target.fieldName];
|
|
92
|
-
if (
|
|
96
|
+
if (fieldType === "String") {
|
|
93
97
|
if (typeof value === "string" || isLexicalState(value)) {
|
|
94
98
|
let t3;
|
|
95
99
|
if ($[10] !== value) {
|
|
@@ -105,7 +109,7 @@ function BlockQuote(t0) {
|
|
|
105
109
|
} else t4 = $[13];
|
|
106
110
|
return t4;
|
|
107
111
|
}
|
|
108
|
-
if (value == null
|
|
112
|
+
if (value == null) {
|
|
109
113
|
let t3;
|
|
110
114
|
if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
|
|
111
115
|
t3 = /* @__PURE__ */ jsx(Quote, { children: "Empty text" });
|
|
@@ -114,7 +118,7 @@ function BlockQuote(t0) {
|
|
|
114
118
|
return t3;
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
|
-
if (
|
|
121
|
+
if (fieldType === "Link" && value && typeof value === "object" && "text" in value && typeof value.text === "string") {
|
|
118
122
|
const t3 = value.text || "Empty link text";
|
|
119
123
|
let t4;
|
|
120
124
|
if ($[15] !== t3) {
|
|
@@ -125,7 +129,7 @@ function BlockQuote(t0) {
|
|
|
125
129
|
return t4;
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
|
-
const t3 = subject.summary || (
|
|
132
|
+
const t3 = subject.summary || ("itemId" in target ? "Untitled item" : "Untitled block");
|
|
129
133
|
let t4;
|
|
130
134
|
if ($[17] !== t3) {
|
|
131
135
|
t4 = /* @__PURE__ */ jsx(Quote, { children: t3 });
|
|
@@ -136,12 +140,12 @@ function BlockQuote(t0) {
|
|
|
136
140
|
}
|
|
137
141
|
function CommentTargetQuote(t0) {
|
|
138
142
|
const $ = c(5);
|
|
139
|
-
if ($[0] !== "
|
|
143
|
+
if ($[0] !== "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab") {
|
|
140
144
|
for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
141
|
-
$[0] = "
|
|
145
|
+
$[0] = "3d839e9320d85d713ee71a099780efa90c475e3bad1d5b3892ff6d87762000ab";
|
|
142
146
|
}
|
|
143
147
|
const { pageId, target } = t0;
|
|
144
|
-
if (target.
|
|
148
|
+
if (target.kind === "page") {
|
|
145
149
|
let t1;
|
|
146
150
|
if ($[1] !== pageId) {
|
|
147
151
|
t1 = /* @__PURE__ */ jsx(PageQuote, { pageId });
|
|
@@ -152,10 +156,7 @@ function CommentTargetQuote(t0) {
|
|
|
152
156
|
}
|
|
153
157
|
let t1;
|
|
154
158
|
if ($[3] !== target) {
|
|
155
|
-
t1 = /* @__PURE__ */ jsx(BlockQuote, { target
|
|
156
|
-
...target,
|
|
157
|
-
blockId: target.blockId
|
|
158
|
-
} });
|
|
159
|
+
t1 = /* @__PURE__ */ jsx(BlockQuote, { target });
|
|
159
160
|
$[3] = target;
|
|
160
161
|
$[4] = t1;
|
|
161
162
|
} else t1 = $[4];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useNavigate } from "../../navigation/navigation.js";
|
|
2
2
|
import { useProjectSlug } from "../../../lib/auth.js";
|
|
3
|
-
import { layoutQueries, pageMutations, pageQueries, projectQueries } from "../../../lib/queries.js";
|
|
4
3
|
import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
|
|
4
|
+
import { layoutQueries, pageMutations, pageQueries, projectQueries } from "../../../lib/queries.js";
|
|
5
5
|
import { previewStore } from "../previewStore.js";
|
|
6
6
|
import { PageLocationFieldset } from "./PageLocationFieldset.js";
|
|
7
7
|
import { PageNicknameField } from "./PageNicknameField.js";
|
|
@@ -26,9 +26,9 @@ const slugifyPathSegment = (nickname) => {
|
|
|
26
26
|
};
|
|
27
27
|
const CreatePageModal = () => {
|
|
28
28
|
const $ = c(59);
|
|
29
|
-
if ($[0] !== "
|
|
29
|
+
if ($[0] !== "7d9f627f2fd6df9193c55db2f9612514acd4807aab2e5cc3fbd5bdd5aaf23672") {
|
|
30
30
|
for (let $i = 0; $i < 59; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
31
|
-
$[0] = "
|
|
31
|
+
$[0] = "7d9f627f2fd6df9193c55db2f9612514acd4807aab2e5cc3fbd5bdd5aaf23672";
|
|
32
32
|
}
|
|
33
33
|
const projectSlug = useProjectSlug();
|
|
34
34
|
const open = useSelector(previewStore, _temp);
|
|
@@ -84,7 +84,7 @@ const CreatePageModal = () => {
|
|
|
84
84
|
const camoxApp = useCamoxApp();
|
|
85
85
|
let t8;
|
|
86
86
|
if ($[14] !== allLayouts || $[15] !== camoxApp) {
|
|
87
|
-
t8 = allLayouts?.filter((layout) => camoxApp.getLayoutById(layout.layoutId)?._internal.kind
|
|
87
|
+
t8 = allLayouts?.filter((layout) => camoxApp.getLayoutById(layout.layoutId)?._internal.kind === "curated");
|
|
88
88
|
$[14] = allLayouts;
|
|
89
89
|
$[15] = camoxApp;
|
|
90
90
|
$[16] = t8;
|
|
@@ -5,7 +5,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
import { Button } from "@camox/ui/button";
|
|
6
6
|
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@camox/ui/dialog";
|
|
7
7
|
import { Label } from "@camox/ui/label";
|
|
8
|
-
import {
|
|
8
|
+
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from "@camox/ui/input-group";
|
|
9
9
|
|
|
10
10
|
//#region src/features/preview/components/DerivedLayoutDialog.tsx
|
|
11
11
|
function DerivedLayoutDialog({ layout, projectSlug, currentParams, onClose }) {
|
|
@@ -28,11 +28,12 @@ function DerivedLayoutDialog({ layout, projectSlug, currentParams, onClose }) {
|
|
|
28
28
|
const value = values[param]?.trim();
|
|
29
29
|
return value && !value.includes("/") && value !== "." && value !== "..";
|
|
30
30
|
});
|
|
31
|
-
const
|
|
31
|
+
const resolvedSegments = segments.map((segment_1) => {
|
|
32
32
|
if (!segment_1.startsWith("$")) return encodeURIComponent(segment_1);
|
|
33
33
|
const value_0 = values[segment_1.slice(1)]?.trim();
|
|
34
34
|
return value_0 ? encodeURIComponent(value_0) : segment_1;
|
|
35
|
-
})
|
|
35
|
+
});
|
|
36
|
+
const path = `/${resolvedSegments.join("/")}`;
|
|
36
37
|
return /* @__PURE__ */ jsx(Dialog, {
|
|
37
38
|
open: true,
|
|
38
39
|
onOpenChange: (open) => !open && onClose(),
|
|
@@ -57,24 +58,38 @@ function DerivedLayoutDialog({ layout, projectSlug, currentParams, onClose }) {
|
|
|
57
58
|
},
|
|
58
59
|
children: [
|
|
59
60
|
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsxs(DialogTitle, { children: ["Preview ", layout._internal.title] }), /* @__PURE__ */ jsx(DialogDescription, { children: "Enter the path parameters for the page you want to preview." })] }),
|
|
60
|
-
params.map((param_0) =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
params.map((param_0) => {
|
|
62
|
+
const index = segments.indexOf(`$${param_0}`);
|
|
63
|
+
const prefix = resolvedSegments.slice(0, index).join("/");
|
|
64
|
+
const suffix = segments.slice(index + 1).every((segment_2) => !segment_2.startsWith("$")) ? resolvedSegments.slice(index + 1).join("/") : "";
|
|
65
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
66
|
+
className: "space-y-2",
|
|
67
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
68
|
+
htmlFor: `${id}-${param_0}`,
|
|
69
|
+
children: param_0
|
|
70
|
+
}), /* @__PURE__ */ jsxs(InputGroup, { children: [
|
|
71
|
+
/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsxs(InputGroupText, {
|
|
72
|
+
className: "font-mono",
|
|
73
|
+
children: ["/", prefix && `${prefix}/`]
|
|
74
|
+
}) }),
|
|
75
|
+
/* @__PURE__ */ jsx(InputGroupInput, {
|
|
76
|
+
id: `${id}-${param_0}`,
|
|
77
|
+
required: true,
|
|
78
|
+
value: values[param_0] ?? "",
|
|
79
|
+
onChange: (event_0) => setValues((previous) => ({
|
|
80
|
+
...previous,
|
|
81
|
+
[param_0]: event_0.target.value
|
|
82
|
+
}))
|
|
83
|
+
}),
|
|
84
|
+
suffix && /* @__PURE__ */ jsx(InputGroupAddon, {
|
|
85
|
+
align: "inline-end",
|
|
86
|
+
children: /* @__PURE__ */ jsxs(InputGroupText, {
|
|
87
|
+
className: "font-mono",
|
|
88
|
+
children: ["/", suffix]
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
] })]
|
|
92
|
+
}, param_0);
|
|
78
93
|
}),
|
|
79
94
|
error && /* @__PURE__ */ jsx("p", {
|
|
80
95
|
role: "alert",
|