camox 0.67.0 → 0.68.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 +2 -1
- package/dist/features/preview/components/PreviewToolbar.js +77 -68
- package/dist/features/preview/repeatableItemTargets.js +13 -7
- package/dist/features/runtime/RuntimeChrome.js +47 -61
- package/dist/features/studio/components/ChatWidget.js +3 -4
- package/dist/features/studio/components/ConnectAgent.js +33 -59
- package/dist/features/studio/components/DraftBar.js +139 -0
- package/dist/features/studio/components/DraftsControl.js +13 -57
- package/dist/features/studio/components/Navbar.js +3 -2
- package/dist/features/studio/components/UserButton.js +7 -11
- package/dist/features/studio/studioStore.js +0 -13
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/dist/features/studio/components/UnnamedDraftBar.js +0 -349
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "camox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.68.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bin": {
|
|
6
6
|
"camox": "./bin/camox.mjs"
|
|
@@ -148,9 +148,9 @@
|
|
|
148
148
|
"unhead": "^3.4.3",
|
|
149
149
|
"yaml": "^2.9.0",
|
|
150
150
|
"zod": "^4.6.7",
|
|
151
|
-
"@camox/
|
|
152
|
-
"@camox/
|
|
153
|
-
"@camox/ui": "0.
|
|
151
|
+
"@camox/api-contract": "0.68.0",
|
|
152
|
+
"@camox/cli": "0.68.0",
|
|
153
|
+
"@camox/ui": "0.68.0"
|
|
154
154
|
},
|
|
155
155
|
"devDependencies": {
|
|
156
156
|
"@earendil-works/pi-ai": "1.3.0",
|
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import { reads, useReadQuery } from "../../../lib/studio-reads.js";
|
|
2
|
-
import { cn } from "../../../lib/utils.js";
|
|
3
|
-
import { studioStore } from "../studioStore.js";
|
|
4
|
-
import { plural } from "../draftLabel.js";
|
|
5
|
-
import { useRenameDraft } from "./ReviewDraftSheet.js";
|
|
6
|
-
import { useDrafts } from "./DraftsControl.js";
|
|
7
|
-
import { c } from "react/compiler-runtime";
|
|
8
|
-
import * as React from "react";
|
|
9
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { useSelector } from "@xstate/store-react";
|
|
11
|
-
import { Button } from "@camox/ui/button";
|
|
12
|
-
import { Input } from "@camox/ui/input";
|
|
13
|
-
import { toast } from "@camox/ui/toaster";
|
|
14
|
-
import { Spinner } from "@camox/ui/spinner";
|
|
15
|
-
import { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger } from "@camox/ui/popover";
|
|
16
|
-
import { FloatingToolbar } from "@camox/ui/floating-toolbar";
|
|
17
|
-
|
|
18
|
-
//#region src/features/studio/components/UnnamedDraftBar.tsx
|
|
19
|
-
/**
|
|
20
|
-
* How long a draft goes without a change before the bar shows, so it doesn't pop up mid-edit.
|
|
21
|
-
*/
|
|
22
|
-
const SETTLE_MS = 1500;
|
|
23
|
-
/**
|
|
24
|
-
* Asks what to do with an unnamed draft, which only editing on Live starts: discard its
|
|
25
|
-
* changes, keep it as a draft by naming it, or publish it. It stays up until one of them ends
|
|
26
|
-
* the draft or names it, and stands in for the navbar's pending changes until then.
|
|
27
|
-
*/
|
|
28
|
-
function UnnamedDraftBar(t0) {
|
|
29
|
-
const $ = c(23);
|
|
30
|
-
const { stacked } = t0;
|
|
31
|
-
const { projectId, current } = useDrafts();
|
|
32
|
-
const unnamed = current?.name === null ? current : null;
|
|
33
|
-
const keeping = useSelector(studioStore, _temp);
|
|
34
|
-
const settled = useSettled(unnamed?.id ?? null, unnamed?.lastChangedAt ?? null);
|
|
35
|
-
if (!projectId || !unnamed || !(settled || keeping)) return null;
|
|
36
|
-
const empty = unnamed.changeCount === 0;
|
|
37
|
-
const t1 = stacked ? "bottom-16" : "bottom-2";
|
|
38
|
-
let t2;
|
|
39
|
-
if ($[0] !== t1) {
|
|
40
|
-
t2 = cn("animate-in fade-in slide-in-from-bottom-4 fixed w-max gap-6 duration-300", t1);
|
|
41
|
-
$[0] = t1;
|
|
42
|
-
$[1] = t2;
|
|
43
|
-
} else t2 = $[1];
|
|
44
|
-
let t3;
|
|
45
|
-
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
46
|
-
t3 = /* @__PURE__ */ jsx("span", {
|
|
47
|
-
"aria-hidden": true,
|
|
48
|
-
className: "size-2 shrink-0 rounded-full bg-blue-500"
|
|
49
|
-
});
|
|
50
|
-
$[2] = t3;
|
|
51
|
-
} else t3 = $[2];
|
|
52
|
-
let t4;
|
|
53
|
-
if ($[3] !== empty || $[4] !== unnamed.changeCount) {
|
|
54
|
-
t4 = empty ? "No changes yet" : plural(unnamed.changeCount, "pending change");
|
|
55
|
-
$[3] = empty;
|
|
56
|
-
$[4] = unnamed.changeCount;
|
|
57
|
-
$[5] = t4;
|
|
58
|
-
} else t4 = $[5];
|
|
59
|
-
let t5;
|
|
60
|
-
if ($[6] !== t4) {
|
|
61
|
-
t5 = /* @__PURE__ */ jsxs("span", {
|
|
62
|
-
className: "flex items-center gap-2 px-2 text-sm",
|
|
63
|
-
children: [t3, t4]
|
|
64
|
-
});
|
|
65
|
-
$[6] = t4;
|
|
66
|
-
$[7] = t5;
|
|
67
|
-
} else t5 = $[7];
|
|
68
|
-
let t6;
|
|
69
|
-
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
70
|
-
t6 = /* @__PURE__ */ jsx(Button, {
|
|
71
|
-
type: "button",
|
|
72
|
-
variant: "outline",
|
|
73
|
-
onClick: _temp2,
|
|
74
|
-
children: "Discard"
|
|
75
|
-
});
|
|
76
|
-
$[8] = t6;
|
|
77
|
-
} else t6 = $[8];
|
|
78
|
-
let t7;
|
|
79
|
-
if ($[9] !== empty || $[10] !== keeping || $[11] !== projectId || $[12] !== unnamed) {
|
|
80
|
-
t7 = /* @__PURE__ */ jsx(KeepDraft, {
|
|
81
|
-
projectId,
|
|
82
|
-
draft: unnamed,
|
|
83
|
-
open: keeping,
|
|
84
|
-
disabled: empty
|
|
85
|
-
});
|
|
86
|
-
$[9] = empty;
|
|
87
|
-
$[10] = keeping;
|
|
88
|
-
$[11] = projectId;
|
|
89
|
-
$[12] = unnamed;
|
|
90
|
-
$[13] = t7;
|
|
91
|
-
} else t7 = $[13];
|
|
92
|
-
let t8;
|
|
93
|
-
if ($[14] !== empty) {
|
|
94
|
-
t8 = /* @__PURE__ */ jsx(Button, {
|
|
95
|
-
type: "button",
|
|
96
|
-
disabled: empty,
|
|
97
|
-
onClick: _temp3,
|
|
98
|
-
children: "Publish…"
|
|
99
|
-
});
|
|
100
|
-
$[14] = empty;
|
|
101
|
-
$[15] = t8;
|
|
102
|
-
} else t8 = $[15];
|
|
103
|
-
let t9;
|
|
104
|
-
if ($[16] !== t7 || $[17] !== t8) {
|
|
105
|
-
t9 = /* @__PURE__ */ jsxs("div", {
|
|
106
|
-
className: "flex items-center gap-2",
|
|
107
|
-
children: [
|
|
108
|
-
t6,
|
|
109
|
-
t7,
|
|
110
|
-
t8
|
|
111
|
-
]
|
|
112
|
-
});
|
|
113
|
-
$[16] = t7;
|
|
114
|
-
$[17] = t8;
|
|
115
|
-
$[18] = t9;
|
|
116
|
-
} else t9 = $[18];
|
|
117
|
-
let t10;
|
|
118
|
-
if ($[19] !== t2 || $[20] !== t5 || $[21] !== t9) {
|
|
119
|
-
t10 = /* @__PURE__ */ jsxs(FloatingToolbar, {
|
|
120
|
-
"aria-label": "Unnamed draft",
|
|
121
|
-
className: t2,
|
|
122
|
-
children: [t5, t9]
|
|
123
|
-
});
|
|
124
|
-
$[19] = t2;
|
|
125
|
-
$[20] = t5;
|
|
126
|
-
$[21] = t9;
|
|
127
|
-
$[22] = t10;
|
|
128
|
-
} else t10 = $[22];
|
|
129
|
-
return t10;
|
|
130
|
-
}
|
|
131
|
-
function _temp3() {
|
|
132
|
-
return studioStore.send({ type: "openReviewDraftSheet" });
|
|
133
|
-
}
|
|
134
|
-
function _temp2() {
|
|
135
|
-
return studioStore.send({ type: "openDeleteDraftDialog" });
|
|
136
|
-
}
|
|
137
|
-
function _temp(state) {
|
|
138
|
-
return state.context.isKeepDraftOpen;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Whether the draft went without a change for `SETTLE_MS`. Once settled it stays so for that
|
|
142
|
-
* draft, so the bar doesn't hide again on the next edit.
|
|
143
|
-
*/
|
|
144
|
-
function useSettled(draftId, lastChangedAt) {
|
|
145
|
-
const $ = c(5);
|
|
146
|
-
const [settledDraft, setSettledDraft] = React.useState(null);
|
|
147
|
-
let t0;
|
|
148
|
-
let t1;
|
|
149
|
-
if ($[0] !== draftId || $[1] !== lastChangedAt || $[2] !== settledDraft) {
|
|
150
|
-
t0 = () => {
|
|
151
|
-
if (!draftId || settledDraft === draftId) return;
|
|
152
|
-
const wait = Math.max(0, (lastChangedAt ?? 0) + SETTLE_MS - Date.now());
|
|
153
|
-
const timer = setTimeout(() => setSettledDraft(draftId), wait);
|
|
154
|
-
return () => clearTimeout(timer);
|
|
155
|
-
};
|
|
156
|
-
t1 = [
|
|
157
|
-
draftId,
|
|
158
|
-
lastChangedAt,
|
|
159
|
-
settledDraft
|
|
160
|
-
];
|
|
161
|
-
$[0] = draftId;
|
|
162
|
-
$[1] = lastChangedAt;
|
|
163
|
-
$[2] = settledDraft;
|
|
164
|
-
$[3] = t0;
|
|
165
|
-
$[4] = t1;
|
|
166
|
-
} else {
|
|
167
|
-
t0 = $[3];
|
|
168
|
-
t1 = $[4];
|
|
169
|
-
}
|
|
170
|
-
React.useEffect(t0, t1);
|
|
171
|
-
return !!draftId && settledDraft === draftId;
|
|
172
|
-
}
|
|
173
|
-
/** "Keep as draft": names the draft, which keeps it and ends the bar. */
|
|
174
|
-
function KeepDraft(t0) {
|
|
175
|
-
const $ = c(15);
|
|
176
|
-
const { projectId, draft, open, disabled } = t0;
|
|
177
|
-
let t1;
|
|
178
|
-
if ($[0] !== disabled) {
|
|
179
|
-
t1 = /* @__PURE__ */ jsx(Button, {
|
|
180
|
-
type: "button",
|
|
181
|
-
variant: "outline",
|
|
182
|
-
disabled
|
|
183
|
-
});
|
|
184
|
-
$[0] = disabled;
|
|
185
|
-
$[1] = t1;
|
|
186
|
-
} else t1 = $[1];
|
|
187
|
-
let t2;
|
|
188
|
-
if ($[2] !== disabled || $[3] !== t1) {
|
|
189
|
-
t2 = /* @__PURE__ */ jsx(PopoverTrigger, {
|
|
190
|
-
disabled,
|
|
191
|
-
render: t1,
|
|
192
|
-
children: "Keep as draft"
|
|
193
|
-
});
|
|
194
|
-
$[2] = disabled;
|
|
195
|
-
$[3] = t1;
|
|
196
|
-
$[4] = t2;
|
|
197
|
-
} else t2 = $[4];
|
|
198
|
-
let t3;
|
|
199
|
-
if ($[5] !== draft || $[6] !== open || $[7] !== projectId) {
|
|
200
|
-
t3 = open && /* @__PURE__ */ jsx(KeepDraftForm, {
|
|
201
|
-
projectId,
|
|
202
|
-
draft
|
|
203
|
-
});
|
|
204
|
-
$[5] = draft;
|
|
205
|
-
$[6] = open;
|
|
206
|
-
$[7] = projectId;
|
|
207
|
-
$[8] = t3;
|
|
208
|
-
} else t3 = $[8];
|
|
209
|
-
let t4;
|
|
210
|
-
if ($[9] !== t3) {
|
|
211
|
-
t4 = /* @__PURE__ */ jsx(PopoverContent, {
|
|
212
|
-
side: "top",
|
|
213
|
-
sideOffset: 16,
|
|
214
|
-
className: "w-80",
|
|
215
|
-
children: t3
|
|
216
|
-
});
|
|
217
|
-
$[9] = t3;
|
|
218
|
-
$[10] = t4;
|
|
219
|
-
} else t4 = $[10];
|
|
220
|
-
let t5;
|
|
221
|
-
if ($[11] !== open || $[12] !== t2 || $[13] !== t4) {
|
|
222
|
-
t5 = /* @__PURE__ */ jsxs(Popover, {
|
|
223
|
-
open,
|
|
224
|
-
onOpenChange: _temp4,
|
|
225
|
-
children: [t2, t4]
|
|
226
|
-
});
|
|
227
|
-
$[11] = open;
|
|
228
|
-
$[12] = t2;
|
|
229
|
-
$[13] = t4;
|
|
230
|
-
$[14] = t5;
|
|
231
|
-
} else t5 = $[14];
|
|
232
|
-
return t5;
|
|
233
|
-
}
|
|
234
|
-
function _temp4(next) {
|
|
235
|
-
return studioStore.send({ type: next ? "openKeepDraft" : "closeKeepDraft" });
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* The name to keep the draft under, filled with the short name its Draft Overview suggests until
|
|
239
|
-
* the editor types: AI names a few changes well, and better than a name typed before making them.
|
|
240
|
-
*/
|
|
241
|
-
function KeepDraftForm(t0) {
|
|
242
|
-
const $ = c(24);
|
|
243
|
-
const { projectId, draft } = t0;
|
|
244
|
-
let t1;
|
|
245
|
-
if ($[0] !== draft.id || $[1] !== projectId) {
|
|
246
|
-
t1 = reads.publishPreview({
|
|
247
|
-
projectId,
|
|
248
|
-
draftId: draft.id
|
|
249
|
-
});
|
|
250
|
-
$[0] = draft.id;
|
|
251
|
-
$[1] = projectId;
|
|
252
|
-
$[2] = t1;
|
|
253
|
-
} else t1 = $[2];
|
|
254
|
-
const preview = useReadQuery(t1);
|
|
255
|
-
const overview = preview.data?.overview;
|
|
256
|
-
const suggested = overview?.status === "ready" ? overview.name : null;
|
|
257
|
-
const summarizing = !suggested && (preview.isPending || overview?.status === "pending");
|
|
258
|
-
const [typed, setTyped] = React.useState(null);
|
|
259
|
-
const name = typed ?? suggested ?? "";
|
|
260
|
-
const rename = useRenameDraft(projectId);
|
|
261
|
-
let t2;
|
|
262
|
-
if ($[3] !== draft.id || $[4] !== name || $[5] !== rename) {
|
|
263
|
-
t2 = (event) => {
|
|
264
|
-
event.preventDefault();
|
|
265
|
-
const kept = name.trim();
|
|
266
|
-
if (!kept) return;
|
|
267
|
-
rename.mutate({
|
|
268
|
-
draftId: draft.id,
|
|
269
|
-
name: kept
|
|
270
|
-
}, { onSuccess: () => {
|
|
271
|
-
studioStore.send({ type: "closeKeepDraft" });
|
|
272
|
-
toast.success(`Kept as "${kept}"`);
|
|
273
|
-
} });
|
|
274
|
-
};
|
|
275
|
-
$[3] = draft.id;
|
|
276
|
-
$[4] = name;
|
|
277
|
-
$[5] = rename;
|
|
278
|
-
$[6] = t2;
|
|
279
|
-
} else t2 = $[6];
|
|
280
|
-
let t3;
|
|
281
|
-
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
|
282
|
-
t3 = /* @__PURE__ */ jsxs(PopoverHeader, { children: [/* @__PURE__ */ jsx(PopoverTitle, { children: "Keep as draft" }), /* @__PURE__ */ jsx(PopoverDescription, { children: "Name it for what it changes, so you and your team can find it later." })] });
|
|
283
|
-
$[7] = t3;
|
|
284
|
-
} else t3 = $[7];
|
|
285
|
-
const t4 = summarizing ? "Summarizing your changes…" : "What does this draft change?";
|
|
286
|
-
let t5;
|
|
287
|
-
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
288
|
-
t5 = (event_0) => setTyped(event_0.target.value);
|
|
289
|
-
$[8] = t5;
|
|
290
|
-
} else t5 = $[8];
|
|
291
|
-
let t6;
|
|
292
|
-
if ($[9] !== name || $[10] !== t4) {
|
|
293
|
-
t6 = /* @__PURE__ */ jsx(Input, {
|
|
294
|
-
autoFocus: true,
|
|
295
|
-
"aria-label": "Draft name",
|
|
296
|
-
value: name,
|
|
297
|
-
maxLength: 200,
|
|
298
|
-
placeholder: t4,
|
|
299
|
-
onChange: t5
|
|
300
|
-
});
|
|
301
|
-
$[9] = name;
|
|
302
|
-
$[10] = t4;
|
|
303
|
-
$[11] = t6;
|
|
304
|
-
} else t6 = $[11];
|
|
305
|
-
let t7;
|
|
306
|
-
if ($[12] !== name || $[13] !== rename.isPending) {
|
|
307
|
-
t7 = !name.trim() || rename.isPending;
|
|
308
|
-
$[12] = name;
|
|
309
|
-
$[13] = rename.isPending;
|
|
310
|
-
$[14] = t7;
|
|
311
|
-
} else t7 = $[14];
|
|
312
|
-
let t8;
|
|
313
|
-
if ($[15] !== rename.isPending) {
|
|
314
|
-
t8 = rename.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
|
|
315
|
-
$[15] = rename.isPending;
|
|
316
|
-
$[16] = t8;
|
|
317
|
-
} else t8 = $[16];
|
|
318
|
-
let t9;
|
|
319
|
-
if ($[17] !== t7 || $[18] !== t8) {
|
|
320
|
-
t9 = /* @__PURE__ */ jsxs(Button, {
|
|
321
|
-
type: "submit",
|
|
322
|
-
disabled: t7,
|
|
323
|
-
children: [t8, "Keep draft"]
|
|
324
|
-
});
|
|
325
|
-
$[17] = t7;
|
|
326
|
-
$[18] = t8;
|
|
327
|
-
$[19] = t9;
|
|
328
|
-
} else t9 = $[19];
|
|
329
|
-
let t10;
|
|
330
|
-
if ($[20] !== t2 || $[21] !== t6 || $[22] !== t9) {
|
|
331
|
-
t10 = /* @__PURE__ */ jsxs("form", {
|
|
332
|
-
className: "flex flex-col gap-3",
|
|
333
|
-
onSubmit: t2,
|
|
334
|
-
children: [
|
|
335
|
-
t3,
|
|
336
|
-
t6,
|
|
337
|
-
t9
|
|
338
|
-
]
|
|
339
|
-
});
|
|
340
|
-
$[20] = t2;
|
|
341
|
-
$[21] = t6;
|
|
342
|
-
$[22] = t9;
|
|
343
|
-
$[23] = t10;
|
|
344
|
-
} else t10 = $[23];
|
|
345
|
-
return t10;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
//#endregion
|
|
349
|
-
export { SETTLE_MS, UnnamedDraftBar };
|