camox 0.38.0 → 0.40.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/dist/core/editing/createEditableBlock.js +197 -231
- package/dist/features/preview/CamoxPreview.js +202 -151
- package/dist/features/preview/components/CreatePageModal.js +2 -9
- package/dist/features/preview/components/MobilePreviewDrawer.js +303 -0
- package/dist/features/preview/components/PageEditorSidebar.js +2 -2
- package/dist/features/preview/components/PageInfoSidebar.js +283 -246
- package/dist/features/preview/components/PageNavigatorSidebar.js +46 -37
- package/dist/features/preview/components/PreviewPanel.js +92 -71
- package/dist/features/preview/components/RightSidebar.js +37 -75
- package/dist/features/preview/previewStore.js +5 -59
- package/dist/features/provider/AuthenticatedCamoxProvider.js +1 -1
- package/dist/features/studio/CamoxStudio.js +1 -1
- package/dist/features/studio/components/ProjectMenu.js +4 -4
- package/dist/features/studio/components/UserButton.js +21 -3
- package/dist/features/vite/auth.js +52 -0
- package/dist/features/vite/devAuthentication.js +1 -1
- package/dist/features/vite/vite.js +1 -5
- package/dist/studio.css +1 -1
- package/package.json +4 -6
- package/dist/features/agent-chat/agent-chat-labels.js +0 -200
- package/dist/features/agent-chat/components/AgentChatSidebar.js +0 -172
- package/dist/features/agent-chat/components/AgentChatThread.js +0 -593
- package/dist/features/agent-chat/components/AgentToolCallCard.js +0 -141
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { useAuthContext } from "../../../lib/auth.js";
|
|
2
|
+
import { projectQueries } from "../../../lib/queries.js";
|
|
3
|
+
import { cn } from "../../../lib/utils.js";
|
|
4
|
+
import { previewStore, selectionBlockId } from "../previewStore.js";
|
|
5
|
+
import { UserButton } from "../../studio/components/UserButton.js";
|
|
6
|
+
import { AddBlockSidebar } from "./AddBlockSidebar.js";
|
|
7
|
+
import { PageTree } from "./PageTree.js";
|
|
8
|
+
import { PageNavigatorHeader } from "./PageNavigatorSidebar.js";
|
|
9
|
+
import { PageEditorSidebar } from "./PageEditorSidebar.js";
|
|
10
|
+
import { PageInfoSidebar, PageMarkdownContent, PageSeoContent } from "./PageInfoSidebar.js";
|
|
11
|
+
import { c } from "react/compiler-runtime";
|
|
12
|
+
import { useQuery } from "@tanstack/react-query";
|
|
13
|
+
import * as React from "react";
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
import { useSelector } from "@xstate/store-react";
|
|
16
|
+
import { Button } from "@camox/ui/button";
|
|
17
|
+
import { ArrowLeft, FileText, Info, Layers, Search, Settings } from "lucide-react";
|
|
18
|
+
|
|
19
|
+
//#region src/features/preview/components/MobilePreviewDrawer.tsx
|
|
20
|
+
const COLLAPSED_HEIGHT = 80;
|
|
21
|
+
const DRAG_THRESHOLD = 4;
|
|
22
|
+
const screenTitles = {
|
|
23
|
+
root: "Page",
|
|
24
|
+
blocks: "Page content",
|
|
25
|
+
about: "About this page",
|
|
26
|
+
seo: "SEO metadata",
|
|
27
|
+
markdown: "Page markdown"
|
|
28
|
+
};
|
|
29
|
+
function MobilePreviewDrawer({ page, projectName }) {
|
|
30
|
+
const [height, setHeight] = React.useState(COLLAPSED_HEIGHT);
|
|
31
|
+
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
32
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
33
|
+
const [screen, setScreen] = React.useState("root");
|
|
34
|
+
const authCtx = useAuthContext();
|
|
35
|
+
const { data: project } = useQuery(projectQueries.getBySlug(authCtx.projectSlug));
|
|
36
|
+
const dragStartRef = React.useRef({
|
|
37
|
+
y: 0,
|
|
38
|
+
height: COLLAPSED_HEIGHT
|
|
39
|
+
});
|
|
40
|
+
const dragDistanceRef = React.useRef(0);
|
|
41
|
+
const rootContentRef = React.useRef(null);
|
|
42
|
+
const selection = useSelector(previewStore, (state) => state.context.selection);
|
|
43
|
+
const isAddBlockSidebarOpen = useSelector(previewStore, (state_0) => state_0.context.isAddBlockSidebarOpen);
|
|
44
|
+
const selectedBlockId = selectionBlockId(selection);
|
|
45
|
+
const isContentScreen = selectedBlockId != null || isAddBlockSidebarOpen;
|
|
46
|
+
const isTileScreen = screen !== "root" || isContentScreen;
|
|
47
|
+
const showScreenHeader = isExpanded && isTileScreen;
|
|
48
|
+
const getExpandedHeight = React.useCallback(() => {
|
|
49
|
+
if (typeof window === "undefined") return 720;
|
|
50
|
+
if (isTileScreen) return window.innerHeight;
|
|
51
|
+
const contentHeight = rootContentRef.current?.getBoundingClientRect().height ?? 0;
|
|
52
|
+
return Math.max(COLLAPSED_HEIGHT, Math.min(window.innerHeight, COLLAPSED_HEIGHT + contentHeight + 2));
|
|
53
|
+
}, [isTileScreen]);
|
|
54
|
+
const goBack = () => {
|
|
55
|
+
if (isContentScreen) {
|
|
56
|
+
previewStore.send({ type: "clearSelection" });
|
|
57
|
+
previewStore.send({ type: "closeAddBlockSidebar" });
|
|
58
|
+
setScreen("blocks");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
setScreen("root");
|
|
62
|
+
};
|
|
63
|
+
const snapTo = React.useCallback((expanded) => {
|
|
64
|
+
setIsExpanded(expanded);
|
|
65
|
+
setHeight(expanded ? getExpandedHeight() : COLLAPSED_HEIGHT);
|
|
66
|
+
}, [getExpandedHeight]);
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
setScreen("root");
|
|
69
|
+
}, [page.id]);
|
|
70
|
+
React.useEffect(() => {
|
|
71
|
+
const handleResize = () => {
|
|
72
|
+
if (!isExpanded || isDragging) return;
|
|
73
|
+
setHeight(getExpandedHeight());
|
|
74
|
+
};
|
|
75
|
+
handleResize();
|
|
76
|
+
const observer = new ResizeObserver(handleResize);
|
|
77
|
+
if (rootContentRef.current) observer.observe(rootContentRef.current);
|
|
78
|
+
window.addEventListener("resize", handleResize);
|
|
79
|
+
return () => {
|
|
80
|
+
observer.disconnect();
|
|
81
|
+
window.removeEventListener("resize", handleResize);
|
|
82
|
+
};
|
|
83
|
+
}, [
|
|
84
|
+
isExpanded,
|
|
85
|
+
isDragging,
|
|
86
|
+
getExpandedHeight
|
|
87
|
+
]);
|
|
88
|
+
const handlePointerDown = (event) => {
|
|
89
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
90
|
+
dragStartRef.current = {
|
|
91
|
+
y: event.clientY,
|
|
92
|
+
height
|
|
93
|
+
};
|
|
94
|
+
dragDistanceRef.current = 0;
|
|
95
|
+
setIsDragging(true);
|
|
96
|
+
};
|
|
97
|
+
const handlePointerMove = (event_0) => {
|
|
98
|
+
if (!event_0.currentTarget.hasPointerCapture(event_0.pointerId)) return;
|
|
99
|
+
const distance = dragStartRef.current.y - event_0.clientY;
|
|
100
|
+
dragDistanceRef.current = distance;
|
|
101
|
+
const nextHeight = dragStartRef.current.height + distance;
|
|
102
|
+
setHeight(Math.min(getExpandedHeight(), Math.max(COLLAPSED_HEIGHT, nextHeight)));
|
|
103
|
+
};
|
|
104
|
+
const finishDrag = (event_1, onTap = () => snapTo(!isExpanded)) => {
|
|
105
|
+
if (event_1.currentTarget.hasPointerCapture(event_1.pointerId)) event_1.currentTarget.releasePointerCapture(event_1.pointerId);
|
|
106
|
+
setIsDragging(false);
|
|
107
|
+
const distance_0 = dragDistanceRef.current;
|
|
108
|
+
if (Math.abs(distance_0) < DRAG_THRESHOLD) {
|
|
109
|
+
onTap();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (isExpanded && distance_0 < -40) {
|
|
113
|
+
snapTo(false);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
snapTo(dragStartRef.current.height + distance_0 >= (COLLAPSED_HEIGHT + getExpandedHeight()) / 2);
|
|
117
|
+
};
|
|
118
|
+
const cancelDrag = (event_2) => {
|
|
119
|
+
if (event_2.currentTarget.hasPointerCapture(event_2.pointerId)) event_2.currentTarget.releasePointerCapture(event_2.pointerId);
|
|
120
|
+
setIsDragging(false);
|
|
121
|
+
snapTo(isExpanded);
|
|
122
|
+
};
|
|
123
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
124
|
+
className: "bg-background relative z-10 w-full shrink-0 overflow-hidden border-t-2 shadow-[0_-8px_24px_rgba(0,0,0,0.08)]",
|
|
125
|
+
style: {
|
|
126
|
+
height,
|
|
127
|
+
transition: isDragging ? "none" : "height 220ms cubic-bezier(0.22, 1, 0.36, 1)"
|
|
128
|
+
},
|
|
129
|
+
"aria-label": "Project drawer",
|
|
130
|
+
children: [showScreenHeader ? /* @__PURE__ */ jsxs("header", {
|
|
131
|
+
className: "relative h-12 touch-none border-b px-3 pt-2.5 pb-1.5 select-none",
|
|
132
|
+
onPointerDown: handlePointerDown,
|
|
133
|
+
onPointerMove: handlePointerMove,
|
|
134
|
+
onPointerUp: (event_3) => finishDrag(event_3, goBack),
|
|
135
|
+
onPointerCancel: cancelDrag,
|
|
136
|
+
children: [/* @__PURE__ */ jsx("span", { className: "bg-muted-foreground/60 absolute top-1 left-1/2 h-1 w-12 -translate-x-1/2 rounded-full" }), /* @__PURE__ */ jsxs("button", {
|
|
137
|
+
type: "button",
|
|
138
|
+
onClick: (event_4) => {
|
|
139
|
+
if (event_4.detail === 0) goBack();
|
|
140
|
+
},
|
|
141
|
+
className: "hover:bg-accent flex h-8 w-full items-center gap-2 rounded-lg px-2 text-left text-sm font-semibold",
|
|
142
|
+
"aria-label": isContentScreen ? "Back to page content" : "Back to page overview",
|
|
143
|
+
children: [/* @__PURE__ */ jsx(ArrowLeft, { className: "text-muted-foreground size-4" }), isContentScreen ? screenTitles.blocks : screenTitles[screen]]
|
|
144
|
+
})]
|
|
145
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
146
|
+
className: "relative h-20",
|
|
147
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
148
|
+
type: "button",
|
|
149
|
+
className: "relative flex h-20 w-full touch-none items-center px-5 pt-2 pr-20 text-left select-none",
|
|
150
|
+
"aria-controls": "camox-mobile-drawer-content",
|
|
151
|
+
"aria-expanded": isExpanded,
|
|
152
|
+
onPointerDown: handlePointerDown,
|
|
153
|
+
onPointerMove: handlePointerMove,
|
|
154
|
+
onPointerUp: (event_5) => finishDrag(event_5),
|
|
155
|
+
onPointerCancel: cancelDrag,
|
|
156
|
+
onClick: (event_6) => {
|
|
157
|
+
if (event_6.detail === 0) snapTo(!isExpanded);
|
|
158
|
+
},
|
|
159
|
+
children: [/* @__PURE__ */ jsx("span", { className: "bg-muted-foreground/60 absolute top-2 left-1/2 h-1 w-12 -translate-x-1/2 rounded-full" }), /* @__PURE__ */ jsx("span", {
|
|
160
|
+
className: "truncate pr-4 text-sm font-medium",
|
|
161
|
+
children: projectName
|
|
162
|
+
})]
|
|
163
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
164
|
+
className: "absolute top-6 right-5",
|
|
165
|
+
children: /* @__PURE__ */ jsx(UserButton, {})
|
|
166
|
+
})]
|
|
167
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
168
|
+
id: "camox-mobile-drawer-content",
|
|
169
|
+
inert: !isExpanded,
|
|
170
|
+
className: cn("flex min-h-0 flex-col overflow-hidden", isTileScreen && "pb-[env(safe-area-inset-bottom)]", showScreenHeader ? "h-[calc(100%-3rem)]" : "h-[calc(100%-5rem)]"),
|
|
171
|
+
children: selectedBlockId != null ? /* @__PURE__ */ jsx(PageEditorSidebar, {}) : isAddBlockSidebarOpen ? /* @__PURE__ */ jsx(AddBlockSidebar, {}) : /* @__PURE__ */ jsxs("div", {
|
|
172
|
+
className: "min-h-0 flex-1 overflow-auto",
|
|
173
|
+
children: [
|
|
174
|
+
screen === "root" && /* @__PURE__ */ jsxs("div", {
|
|
175
|
+
ref: rootContentRef,
|
|
176
|
+
className: "pb-[env(safe-area-inset-bottom)]",
|
|
177
|
+
children: [
|
|
178
|
+
/* @__PURE__ */ jsx(PageNavigatorHeader, { page }),
|
|
179
|
+
/* @__PURE__ */ jsx("div", {
|
|
180
|
+
className: "px-3 pt-3",
|
|
181
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
182
|
+
type: "button",
|
|
183
|
+
variant: "outline",
|
|
184
|
+
className: "w-full",
|
|
185
|
+
disabled: page.status === "published" || page.livePublishedCheckpointId == null,
|
|
186
|
+
onClick: () => previewStore.send({ type: "viewLivePage" }),
|
|
187
|
+
children: "View live site"
|
|
188
|
+
})
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ jsxs("div", {
|
|
191
|
+
className: "grid grid-cols-2 gap-2 p-3",
|
|
192
|
+
children: [
|
|
193
|
+
/* @__PURE__ */ jsx(DrawerTile, {
|
|
194
|
+
title: "Page content",
|
|
195
|
+
icon: Layers,
|
|
196
|
+
onClick: () => setScreen("blocks"),
|
|
197
|
+
fullWidth: true
|
|
198
|
+
}),
|
|
199
|
+
/* @__PURE__ */ jsx(DrawerTile, {
|
|
200
|
+
title: "About this page",
|
|
201
|
+
icon: Info,
|
|
202
|
+
onClick: () => setScreen("about")
|
|
203
|
+
}),
|
|
204
|
+
/* @__PURE__ */ jsx(DrawerTile, {
|
|
205
|
+
title: "SEO metadata",
|
|
206
|
+
icon: Search,
|
|
207
|
+
onClick: () => setScreen("seo")
|
|
208
|
+
}),
|
|
209
|
+
/* @__PURE__ */ jsx(DrawerTile, {
|
|
210
|
+
title: "Page markdown",
|
|
211
|
+
icon: FileText,
|
|
212
|
+
onClick: () => setScreen("markdown")
|
|
213
|
+
}),
|
|
214
|
+
/* @__PURE__ */ jsx(DrawerTile, {
|
|
215
|
+
title: "Project settings",
|
|
216
|
+
icon: Settings,
|
|
217
|
+
onClick: () => {
|
|
218
|
+
if (!project) return;
|
|
219
|
+
window.open(`${authCtx.authenticationUrl}/${project.organizationSlug}/${project.slug}/overview`, "_blank", "noopener,noreferrer");
|
|
220
|
+
},
|
|
221
|
+
disabled: !project
|
|
222
|
+
})
|
|
223
|
+
]
|
|
224
|
+
})
|
|
225
|
+
]
|
|
226
|
+
}),
|
|
227
|
+
screen === "blocks" && /* @__PURE__ */ jsx("div", {
|
|
228
|
+
className: "flex flex-col gap-2 p-2",
|
|
229
|
+
children: /* @__PURE__ */ jsx(PageTree, {})
|
|
230
|
+
}),
|
|
231
|
+
screen === "about" && /* @__PURE__ */ jsx(PageInfoSidebar, {
|
|
232
|
+
pageId: page.id,
|
|
233
|
+
scrollable: false,
|
|
234
|
+
aboutOnly: true
|
|
235
|
+
}),
|
|
236
|
+
screen === "seo" && /* @__PURE__ */ jsx("div", {
|
|
237
|
+
className: "p-3",
|
|
238
|
+
children: /* @__PURE__ */ jsx(PageSeoContent, { pageId: page.id })
|
|
239
|
+
}),
|
|
240
|
+
screen === "markdown" && /* @__PURE__ */ jsxs("div", {
|
|
241
|
+
className: "space-y-4 p-3",
|
|
242
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
243
|
+
className: "text-muted-foreground text-sm",
|
|
244
|
+
children: "How your content will be served to AI agents."
|
|
245
|
+
}), /* @__PURE__ */ jsx(PageMarkdownContent, { pageId: page.id })]
|
|
246
|
+
})
|
|
247
|
+
]
|
|
248
|
+
}, screen)
|
|
249
|
+
})]
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
function DrawerTile(t0) {
|
|
253
|
+
const $ = c(13);
|
|
254
|
+
if ($[0] !== "a15836a2c406a6e26e3450f2952542d7c3ef6e1f52eed0eca720954850f751a5") {
|
|
255
|
+
for (let $i = 0; $i < 13; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
256
|
+
$[0] = "a15836a2c406a6e26e3450f2952542d7c3ef6e1f52eed0eca720954850f751a5";
|
|
257
|
+
}
|
|
258
|
+
const { title, icon: Icon, onClick, fullWidth: t1, disabled: t2 } = t0;
|
|
259
|
+
const fullWidth = t1 === void 0 ? false : t1;
|
|
260
|
+
const disabled = t2 === void 0 ? false : t2;
|
|
261
|
+
const t3 = fullWidth && "col-span-2";
|
|
262
|
+
let t4;
|
|
263
|
+
if ($[1] !== t3) {
|
|
264
|
+
t4 = cn("bg-muted/40 hover:bg-muted flex flex-col items-start justify-between rounded-xl border p-3 text-left transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", t3);
|
|
265
|
+
$[1] = t3;
|
|
266
|
+
$[2] = t4;
|
|
267
|
+
} else t4 = $[2];
|
|
268
|
+
let t5;
|
|
269
|
+
if ($[3] !== Icon) {
|
|
270
|
+
t5 = /* @__PURE__ */ jsx(Icon, { className: "text-muted-foreground size-5" });
|
|
271
|
+
$[3] = Icon;
|
|
272
|
+
$[4] = t5;
|
|
273
|
+
} else t5 = $[4];
|
|
274
|
+
let t6;
|
|
275
|
+
if ($[5] !== title) {
|
|
276
|
+
t6 = /* @__PURE__ */ jsx("span", {
|
|
277
|
+
className: "mt-3 text-xs font-medium",
|
|
278
|
+
children: title
|
|
279
|
+
});
|
|
280
|
+
$[5] = title;
|
|
281
|
+
$[6] = t6;
|
|
282
|
+
} else t6 = $[6];
|
|
283
|
+
let t7;
|
|
284
|
+
if ($[7] !== disabled || $[8] !== onClick || $[9] !== t4 || $[10] !== t5 || $[11] !== t6) {
|
|
285
|
+
t7 = /* @__PURE__ */ jsxs("button", {
|
|
286
|
+
type: "button",
|
|
287
|
+
onClick,
|
|
288
|
+
disabled,
|
|
289
|
+
className: t4,
|
|
290
|
+
children: [t5, t6]
|
|
291
|
+
});
|
|
292
|
+
$[7] = disabled;
|
|
293
|
+
$[8] = onClick;
|
|
294
|
+
$[9] = t4;
|
|
295
|
+
$[10] = t5;
|
|
296
|
+
$[11] = t6;
|
|
297
|
+
$[12] = t7;
|
|
298
|
+
} else t7 = $[12];
|
|
299
|
+
return t7;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
//#endregion
|
|
303
|
+
export { MobilePreviewDrawer };
|
|
@@ -281,7 +281,7 @@ const PageEditorSidebar = () => {
|
|
|
281
281
|
},
|
|
282
282
|
{
|
|
283
283
|
key: "block",
|
|
284
|
-
label:
|
|
284
|
+
label: blockDef._internal.title,
|
|
285
285
|
isCurrent: ancestorChain.length === 0 && !fieldHasOwnView,
|
|
286
286
|
onClick: () => previewStore.send({
|
|
287
287
|
type: "setFocusedBlock",
|
|
@@ -290,7 +290,7 @@ const PageEditorSidebar = () => {
|
|
|
290
290
|
},
|
|
291
291
|
...ancestorChain.map((ancestor) => ({
|
|
292
292
|
key: `item-${ancestor.id}`,
|
|
293
|
-
label: ancestor.
|
|
293
|
+
label: getArraySchemaForItem(blockDef._internal.contentSchema, ancestor.id, itemsMap)?.title ?? formatFieldName(ancestor.fieldName),
|
|
294
294
|
isCurrent: ancestor.id === currentItemId && !fieldHasOwnView && ancestor.id === ancestorChain[ancestorChain.length - 1]?.id,
|
|
295
295
|
onClick: () => previewStore.send({
|
|
296
296
|
type: "selectItem",
|