camox 0.43.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/InlineStylesPlugin.js +22 -6
- package/dist/core/components/lexical/SelectionBroadcaster.js +4 -4
- package/dist/core/components/lexical/SidebarLexicalEditor.js +15 -15
- package/dist/core/createApp.d.ts +28 -2
- package/dist/core/createBlock.js +24 -10
- 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/lexicalState.js +6 -6
- package/dist/core/lib/modifierFormats.js +1 -1
- package/dist/core/lib/textStyles.d.ts +1 -1
- package/dist/core/lib/textStyles.js +3 -3
- package/dist/features/content/components/AssetCard.js +104 -68
- package/dist/features/preview/CamoxPreview.js +120 -95
- package/dist/features/preview/commentsEnabled.js +2 -2
- package/dist/features/preview/components/AssetLightbox.js +17 -6
- package/dist/features/preview/components/AttachedComments.js +224 -87
- package/dist/features/preview/components/CommentTargetQuote.js +22 -21
- package/dist/features/preview/components/DerivedLayoutDialog.js +36 -21
- package/dist/features/preview/components/FieldOverlayStyles.js +29 -9
- package/dist/features/preview/components/FieldToolbar.js +8 -8
- package/dist/features/preview/components/IconFieldEditor.js +231 -0
- package/dist/features/preview/components/ItemFieldsEditor.js +21 -14
- package/dist/features/preview/components/OverlayTracker.js +1 -1
- package/dist/features/preview/components/PagePicker.js +44 -44
- package/dist/features/preview/components/PreviewPanel.js +1 -1
- package/dist/features/preview/components/PreviewToolbar.js +224 -225
- package/dist/features/preview/components/SendFeedbackDialog.js +83 -0
- 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/usePageComments.js +39 -0
- package/dist/features/provider/CoreCamoxProvider.js +37 -5
- 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 +25 -0
- package/dist/features/studio/components/EnvironmentMenu.js +75 -63
- package/dist/features/vite/auth.js +1 -50
- package/dist/features/vite/iconGeneration.js +16 -0
- package/dist/features/vite/vite.d.ts +4 -2
- package/dist/features/vite/vite.js +19 -2
- package/dist/lib/auth.js +39 -16
- package/dist/lib/preview-handoff.js +13 -0
- package/dist/lib/queries.js +12 -1
- 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 +5 -4
- package/skills/camox/SKILL.md +6 -0
- package/skills/camox/references/block-definitions.md +27 -0
- package/skills/camox/references/cli-common.md +14 -0
- package/skills/camox/references/cli-content.md +11 -0
- package/skills/camox/references/field-styling.md +4 -4
- package/skills/camoxify/SKILL.md +14 -0
|
@@ -21,9 +21,9 @@ import { Switch } from "@camox/ui/switch";
|
|
|
21
21
|
//#region src/features/preview/components/AssetLightbox.tsx
|
|
22
22
|
function DeliveredSize(t0) {
|
|
23
23
|
const $ = c(16);
|
|
24
|
-
if ($[0] !== "
|
|
24
|
+
if ($[0] !== "a37322f6f4a0473903954c8afefb928b001d0a8beede19e05fe56bf7cdbe1ecf") {
|
|
25
25
|
for (let $i = 0; $i < 16; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
26
|
-
$[0] = "
|
|
26
|
+
$[0] = "a37322f6f4a0473903954c8afefb928b001d0a8beede19e05fe56bf7cdbe1ecf";
|
|
27
27
|
}
|
|
28
28
|
const { bytes, raw } = t0;
|
|
29
29
|
if (bytes == null) {
|
|
@@ -92,9 +92,9 @@ function DeliveredSize(t0) {
|
|
|
92
92
|
}
|
|
93
93
|
function DeliveredLabel(t0) {
|
|
94
94
|
const $ = c(4);
|
|
95
|
-
if ($[0] !== "
|
|
95
|
+
if ($[0] !== "a37322f6f4a0473903954c8afefb928b001d0a8beede19e05fe56bf7cdbe1ecf") {
|
|
96
96
|
for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
97
|
-
$[0] = "
|
|
97
|
+
$[0] = "a37322f6f4a0473903954c8afefb928b001d0a8beede19e05fe56bf7cdbe1ecf";
|
|
98
98
|
}
|
|
99
99
|
const { children } = t0;
|
|
100
100
|
let t1;
|
|
@@ -171,6 +171,7 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
|
|
|
171
171
|
}
|
|
172
172
|
}, [open]);
|
|
173
173
|
const isImage = file?.mimeType?.startsWith("image/") ?? false;
|
|
174
|
+
const isVideo = file?.mimeType?.startsWith("video/") ?? false;
|
|
174
175
|
const canUseAiMetadata = isRasterImage(file?.mimeType);
|
|
175
176
|
const fileUrl = file?.url;
|
|
176
177
|
const fileMimeType = file?.mimeType;
|
|
@@ -367,6 +368,16 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
|
|
|
367
368
|
className: "max-h-full max-w-full cursor-zoom-in object-contain shadow-lg",
|
|
368
369
|
draggable: false
|
|
369
370
|
})
|
|
371
|
+
}) : isVideo ? /* @__PURE__ */ jsx("div", {
|
|
372
|
+
className: "checkered absolute inset-0 flex items-center justify-center p-6",
|
|
373
|
+
children: open && /* @__PURE__ */ jsx("video", {
|
|
374
|
+
src: file.url,
|
|
375
|
+
controls: true,
|
|
376
|
+
playsInline: true,
|
|
377
|
+
preload: "metadata",
|
|
378
|
+
"aria-label": file.alt || file.filename || "Video preview",
|
|
379
|
+
className: "max-h-full max-w-full object-contain shadow-lg"
|
|
380
|
+
}, file.url)
|
|
370
381
|
}) : /* @__PURE__ */ jsx("div", {
|
|
371
382
|
className: "bg-muted/30 flex h-full min-h-[70vh] items-center justify-center p-6",
|
|
372
383
|
children: /* @__PURE__ */ jsx(FileIcon, { className: "text-muted-foreground h-16 w-16" })
|
|
@@ -530,7 +541,7 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
|
|
|
530
541
|
ref: replaceInputRef,
|
|
531
542
|
type: "file",
|
|
532
543
|
className: "hidden",
|
|
533
|
-
accept: isImage ? "image/*" : "*/*",
|
|
544
|
+
accept: isImage ? "image/*" : isVideo ? "video/*" : "*/*",
|
|
534
545
|
onChange: (e_0) => {
|
|
535
546
|
if (e_0.target.files) handleReplaceDrop(e_0.target.files);
|
|
536
547
|
e_0.target.value = "";
|
|
@@ -540,7 +551,7 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
|
|
|
540
551
|
type: "button",
|
|
541
552
|
variant: "secondary",
|
|
542
553
|
onClick: () => replaceInputRef.current?.click(),
|
|
543
|
-
children: isImage ? "Replace image" : "Replace file"
|
|
554
|
+
children: isImage ? "Replace image" : isVideo ? "Replace video" : "Replace file"
|
|
544
555
|
})
|
|
545
556
|
]
|
|
546
557
|
})
|
|
@@ -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,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];
|
|
@@ -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",
|