camox 0.66.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/content/components/MissingFromLocale.js +1 -1
- package/dist/features/page/UnplacedLayoutContent.js +141 -0
- package/dist/features/preview/components/ItemFieldsEditor.js +50 -44
- package/dist/features/preview/components/PreviewToolbar.js +77 -68
- package/dist/features/preview/components/SelectionEditor.js +284 -231
- package/dist/features/preview/components/contentFieldSchema.js +5 -1
- package/dist/features/preview/repeatableItemTargets.js +13 -7
- package/dist/features/runtime/RuntimeChrome.js +47 -61
- package/dist/features/runtime/pageApp.js +24 -10
- package/dist/features/runtime/runtime.d.ts +13 -0
- package/dist/features/runtime/runtime.js +58 -2
- package/dist/features/studio/components/ChatWidget.js +3 -4
- package/dist/features/studio/components/ConnectAgent.js +33 -59
- package/dist/features/studio/components/ContentFindings.js +397 -0
- 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/Patrol.js +52 -34
- package/dist/features/studio/components/ReviewDraftSheet.js +4 -4
- package/dist/features/studio/components/Squareling.js +0 -9
- package/dist/features/studio/components/UserButton.js +7 -11
- package/dist/features/studio/findingSentence.js +3 -5
- package/dist/features/studio/patrollerBio.js +0 -1
- package/dist/features/studio/reportSentence.js +0 -5
- package/dist/features/studio/studioStore.js +0 -13
- package/dist/features/studio/workingSentence.js +0 -4
- 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
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { useCurrentDraftId } from "../../../lib/draft-scope.js";
|
|
2
|
+
import { useViewLocale } from "../../../lib/view-locale-context.js";
|
|
3
|
+
import { AuthContext } from "../../../lib/auth.js";
|
|
4
|
+
import { reads, useReadQuery } from "../../../lib/studio-reads.js";
|
|
5
|
+
import { patrolMutations } from "../../../lib/queries.js";
|
|
6
|
+
import { studioStore } from "../studioStore.js";
|
|
7
|
+
import { askAgentMessage, dismissLabel, findingSentenceInPlace, fixLabel } from "../findingSentence.js";
|
|
8
|
+
import { useShowInCanvas } from "../showInCanvas.js";
|
|
9
|
+
import { c } from "react/compiler-runtime";
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
import { useMutation } from "@tanstack/react-query";
|
|
13
|
+
import { Button } from "@camox/ui/button";
|
|
14
|
+
import { CircleAlert } from "lucide-react";
|
|
15
|
+
import { toast } from "@camox/ui/toaster";
|
|
16
|
+
import { Alert, AlertDescription, AlertTitle } from "@camox/ui/alert";
|
|
17
|
+
|
|
18
|
+
//#region src/features/studio/components/ContentFindings.tsx
|
|
19
|
+
/** The open findings of the Patrol viewed in a subject, in the locale viewed. */
|
|
20
|
+
function useContentFindings(subject) {
|
|
21
|
+
const $ = c(22);
|
|
22
|
+
const { projectUuid } = React.useContext(AuthContext);
|
|
23
|
+
let t0;
|
|
24
|
+
if ($[0] !== projectUuid) {
|
|
25
|
+
t0 = reads.project({ projectUuid });
|
|
26
|
+
$[0] = projectUuid;
|
|
27
|
+
$[1] = t0;
|
|
28
|
+
} else t0 = $[1];
|
|
29
|
+
const { data: project } = useReadQuery(t0);
|
|
30
|
+
let t1;
|
|
31
|
+
if ($[2] !== project?.id) {
|
|
32
|
+
t1 = reads.patrol({ projectId: project?.id ?? 0 });
|
|
33
|
+
$[2] = project?.id;
|
|
34
|
+
$[3] = t1;
|
|
35
|
+
} else t1 = $[3];
|
|
36
|
+
const t2 = project !== void 0 && subject !== null;
|
|
37
|
+
let t3;
|
|
38
|
+
if ($[4] !== t2) {
|
|
39
|
+
t3 = { enabled: t2 };
|
|
40
|
+
$[4] = t2;
|
|
41
|
+
$[5] = t3;
|
|
42
|
+
} else t3 = $[5];
|
|
43
|
+
const { data: view } = useReadQuery(t1, t3);
|
|
44
|
+
const viewed = useViewLocale().locale;
|
|
45
|
+
let t4;
|
|
46
|
+
if ($[6] !== project?.id) {
|
|
47
|
+
t4 = reads.localeList({ projectId: project?.id ?? 0 });
|
|
48
|
+
$[6] = project?.id;
|
|
49
|
+
$[7] = t4;
|
|
50
|
+
} else t4 = $[7];
|
|
51
|
+
const t5 = project !== void 0 && subject !== null;
|
|
52
|
+
let t6;
|
|
53
|
+
if ($[8] !== t5) {
|
|
54
|
+
t6 = { enabled: t5 };
|
|
55
|
+
$[8] = t5;
|
|
56
|
+
$[9] = t6;
|
|
57
|
+
} else t6 = $[9];
|
|
58
|
+
const { data: locales } = useReadQuery(t4, t6);
|
|
59
|
+
let t7;
|
|
60
|
+
if ($[10] !== locales || $[11] !== viewed.isDefault || $[12] !== viewed.tag) {
|
|
61
|
+
t7 = viewed.isDefault ? locales?.find(_temp)?.tag ?? viewed.tag : viewed.tag;
|
|
62
|
+
$[10] = locales;
|
|
63
|
+
$[11] = viewed.isDefault;
|
|
64
|
+
$[12] = viewed.tag;
|
|
65
|
+
$[13] = t7;
|
|
66
|
+
} else t7 = $[13];
|
|
67
|
+
const tag = t7;
|
|
68
|
+
let t8;
|
|
69
|
+
if ($[14] !== subject || $[15] !== tag || $[16] !== view?.patrollers) {
|
|
70
|
+
t8 = subject === null ? [] : (view?.patrollers ?? []).flatMap((patroller) => patroller.findings.filter((finding) => finding.subject.entity === subject.entity && finding.subject.id === subject.id && finding.locale === tag).map((finding_0) => ({
|
|
71
|
+
...finding_0,
|
|
72
|
+
role: patroller.role
|
|
73
|
+
})));
|
|
74
|
+
$[14] = subject;
|
|
75
|
+
$[15] = tag;
|
|
76
|
+
$[16] = view?.patrollers;
|
|
77
|
+
$[17] = t8;
|
|
78
|
+
} else t8 = $[17];
|
|
79
|
+
const findings = t8;
|
|
80
|
+
const t9 = project?.id;
|
|
81
|
+
const t10 = view?.patrolDraft ?? null;
|
|
82
|
+
let t11;
|
|
83
|
+
if ($[18] !== findings || $[19] !== t10 || $[20] !== t9) {
|
|
84
|
+
t11 = {
|
|
85
|
+
projectId: t9,
|
|
86
|
+
patrolDraft: t10,
|
|
87
|
+
findings
|
|
88
|
+
};
|
|
89
|
+
$[18] = findings;
|
|
90
|
+
$[19] = t10;
|
|
91
|
+
$[20] = t9;
|
|
92
|
+
$[21] = t11;
|
|
93
|
+
} else t11 = $[21];
|
|
94
|
+
return t11;
|
|
95
|
+
}
|
|
96
|
+
function _temp(locale) {
|
|
97
|
+
return locale.isDefault;
|
|
98
|
+
}
|
|
99
|
+
/** What a field's row says of its findings, such as "2 findings", or nothing without any. */
|
|
100
|
+
function findingsHint(view, field) {
|
|
101
|
+
const count = view.findings.filter((finding) => finding.field === field).length;
|
|
102
|
+
if (count === 0) return void 0;
|
|
103
|
+
return count === 1 ? "1 finding" : `${count} findings`;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The findings in one field of a subject, as `useContentFindings` reads them, under that field's
|
|
107
|
+
* editor. Without `field`, those in none of `fields`: about the subject as a whole.
|
|
108
|
+
*/
|
|
109
|
+
function ContentFindings(t0) {
|
|
110
|
+
const $ = c(20);
|
|
111
|
+
const { view, field, fields, className } = t0;
|
|
112
|
+
const { projectId, patrolDraft, findings } = view;
|
|
113
|
+
let t1;
|
|
114
|
+
let t2;
|
|
115
|
+
let t3;
|
|
116
|
+
let t4;
|
|
117
|
+
if ($[0] !== className || $[1] !== field || $[2] !== fields || $[3] !== findings || $[4] !== patrolDraft || $[5] !== projectId) {
|
|
118
|
+
t4 = Symbol.for("react.early_return_sentinel");
|
|
119
|
+
bb0: {
|
|
120
|
+
let t5;
|
|
121
|
+
if ($[10] !== field || $[11] !== fields) {
|
|
122
|
+
t5 = (finding) => field === void 0 ? !fields.includes(finding.field) : finding.field === field;
|
|
123
|
+
$[10] = field;
|
|
124
|
+
$[11] = fields;
|
|
125
|
+
$[12] = t5;
|
|
126
|
+
} else t5 = $[12];
|
|
127
|
+
const shown = findings.filter(t5);
|
|
128
|
+
if (projectId === void 0 || shown.length === 0) {
|
|
129
|
+
t4 = null;
|
|
130
|
+
break bb0;
|
|
131
|
+
}
|
|
132
|
+
t1 = true;
|
|
133
|
+
t2 = className ?? "space-y-2 px-2 pb-4";
|
|
134
|
+
let t6;
|
|
135
|
+
if ($[13] !== patrolDraft || $[14] !== projectId) {
|
|
136
|
+
t6 = (finding_0) => /* @__PURE__ */ jsx(FindingAlert, {
|
|
137
|
+
projectId,
|
|
138
|
+
finding: finding_0,
|
|
139
|
+
patrolDraft
|
|
140
|
+
}, finding_0.id);
|
|
141
|
+
$[13] = patrolDraft;
|
|
142
|
+
$[14] = projectId;
|
|
143
|
+
$[15] = t6;
|
|
144
|
+
} else t6 = $[15];
|
|
145
|
+
t3 = shown.map(t6);
|
|
146
|
+
}
|
|
147
|
+
$[0] = className;
|
|
148
|
+
$[1] = field;
|
|
149
|
+
$[2] = fields;
|
|
150
|
+
$[3] = findings;
|
|
151
|
+
$[4] = patrolDraft;
|
|
152
|
+
$[5] = projectId;
|
|
153
|
+
$[6] = t1;
|
|
154
|
+
$[7] = t2;
|
|
155
|
+
$[8] = t3;
|
|
156
|
+
$[9] = t4;
|
|
157
|
+
} else {
|
|
158
|
+
t1 = $[6];
|
|
159
|
+
t2 = $[7];
|
|
160
|
+
t3 = $[8];
|
|
161
|
+
t4 = $[9];
|
|
162
|
+
}
|
|
163
|
+
if (t4 !== Symbol.for("react.early_return_sentinel")) return t4;
|
|
164
|
+
let t5;
|
|
165
|
+
if ($[16] !== t1 || $[17] !== t2 || $[18] !== t3) {
|
|
166
|
+
t5 = /* @__PURE__ */ jsx("div", {
|
|
167
|
+
"data-content-findings": t1,
|
|
168
|
+
className: t2,
|
|
169
|
+
children: t3
|
|
170
|
+
});
|
|
171
|
+
$[16] = t1;
|
|
172
|
+
$[17] = t2;
|
|
173
|
+
$[18] = t3;
|
|
174
|
+
$[19] = t5;
|
|
175
|
+
} else t5 = $[19];
|
|
176
|
+
return t5;
|
|
177
|
+
}
|
|
178
|
+
function FindingAlert(t0) {
|
|
179
|
+
const $ = c(44);
|
|
180
|
+
const { projectId, finding, patrolDraft } = t0;
|
|
181
|
+
const draftId = useCurrentDraftId();
|
|
182
|
+
let t1;
|
|
183
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
184
|
+
t1 = {
|
|
185
|
+
...patrolMutations.applyFix(),
|
|
186
|
+
onSuccess: _temp2,
|
|
187
|
+
onError: _temp3
|
|
188
|
+
};
|
|
189
|
+
$[0] = t1;
|
|
190
|
+
} else t1 = $[0];
|
|
191
|
+
const applyFix = useMutation(t1);
|
|
192
|
+
let t2;
|
|
193
|
+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
|
194
|
+
t2 = {
|
|
195
|
+
...patrolMutations.dismissFinding(),
|
|
196
|
+
onError: _temp4
|
|
197
|
+
};
|
|
198
|
+
$[1] = t2;
|
|
199
|
+
} else t2 = $[1];
|
|
200
|
+
const dismiss = useMutation(t2);
|
|
201
|
+
const busy = applyFix.isPending || dismiss.isPending;
|
|
202
|
+
const fixesHere = draftId !== null && (!finding.live || draftId === patrolDraft?.id);
|
|
203
|
+
let t3;
|
|
204
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
205
|
+
t3 = /* @__PURE__ */ jsx(CircleAlert, {});
|
|
206
|
+
$[2] = t3;
|
|
207
|
+
} else t3 = $[2];
|
|
208
|
+
let t4;
|
|
209
|
+
if ($[3] !== finding) {
|
|
210
|
+
t4 = findingSentenceInPlace(finding);
|
|
211
|
+
$[3] = finding;
|
|
212
|
+
$[4] = t4;
|
|
213
|
+
} else t4 = $[4];
|
|
214
|
+
let t5;
|
|
215
|
+
if ($[5] !== t4) {
|
|
216
|
+
t5 = /* @__PURE__ */ jsx(AlertTitle, {
|
|
217
|
+
className: "text-xs font-normal",
|
|
218
|
+
children: t4
|
|
219
|
+
});
|
|
220
|
+
$[5] = t4;
|
|
221
|
+
$[6] = t5;
|
|
222
|
+
} else t5 = $[6];
|
|
223
|
+
let t6;
|
|
224
|
+
if ($[7] !== finding.role) {
|
|
225
|
+
t6 = /* @__PURE__ */ jsx("p", { children: finding.role });
|
|
226
|
+
$[7] = finding.role;
|
|
227
|
+
$[8] = t6;
|
|
228
|
+
} else t6 = $[8];
|
|
229
|
+
let t7;
|
|
230
|
+
if ($[9] !== applyFix || $[10] !== busy || $[11] !== finding.fix || $[12] !== finding.id || $[13] !== fixesHere || $[14] !== projectId) {
|
|
231
|
+
t7 = fixesHere && finding.fix && /* @__PURE__ */ jsx(Button, {
|
|
232
|
+
variant: "outline",
|
|
233
|
+
size: "xs",
|
|
234
|
+
disabled: busy,
|
|
235
|
+
onClick: () => applyFix.mutate({
|
|
236
|
+
projectId,
|
|
237
|
+
findingId: finding.id
|
|
238
|
+
}),
|
|
239
|
+
children: fixLabel(finding.fix)
|
|
240
|
+
});
|
|
241
|
+
$[9] = applyFix;
|
|
242
|
+
$[10] = busy;
|
|
243
|
+
$[11] = finding.fix;
|
|
244
|
+
$[12] = finding.id;
|
|
245
|
+
$[13] = fixesHere;
|
|
246
|
+
$[14] = projectId;
|
|
247
|
+
$[15] = t7;
|
|
248
|
+
} else t7 = $[15];
|
|
249
|
+
let t8;
|
|
250
|
+
if ($[16] !== finding || $[17] !== fixesHere) {
|
|
251
|
+
t8 = fixesHere && /* @__PURE__ */ jsx(Button, {
|
|
252
|
+
variant: "outline",
|
|
253
|
+
size: "xs",
|
|
254
|
+
onClick: () => studioStore.trigger.askAgent({ text: askAgentMessage(finding, finding.role) }),
|
|
255
|
+
children: "Ask the agent"
|
|
256
|
+
});
|
|
257
|
+
$[16] = finding;
|
|
258
|
+
$[17] = fixesHere;
|
|
259
|
+
$[18] = t8;
|
|
260
|
+
} else t8 = $[18];
|
|
261
|
+
let t9;
|
|
262
|
+
if ($[19] !== draftId || $[20] !== finding || $[21] !== patrolDraft) {
|
|
263
|
+
t9 = draftId === null && patrolDraft && /* @__PURE__ */ jsx(OpenInPatrolDraft, {
|
|
264
|
+
finding,
|
|
265
|
+
patrolDraft
|
|
266
|
+
});
|
|
267
|
+
$[19] = draftId;
|
|
268
|
+
$[20] = finding;
|
|
269
|
+
$[21] = patrolDraft;
|
|
270
|
+
$[22] = t9;
|
|
271
|
+
} else t9 = $[22];
|
|
272
|
+
let t10;
|
|
273
|
+
if ($[23] !== dismiss || $[24] !== finding.id || $[25] !== projectId) {
|
|
274
|
+
t10 = () => dismiss.mutate({
|
|
275
|
+
projectId,
|
|
276
|
+
findingId: finding.id
|
|
277
|
+
});
|
|
278
|
+
$[23] = dismiss;
|
|
279
|
+
$[24] = finding.id;
|
|
280
|
+
$[25] = projectId;
|
|
281
|
+
$[26] = t10;
|
|
282
|
+
} else t10 = $[26];
|
|
283
|
+
let t11;
|
|
284
|
+
if ($[27] !== finding.about) {
|
|
285
|
+
t11 = dismissLabel(finding.about);
|
|
286
|
+
$[27] = finding.about;
|
|
287
|
+
$[28] = t11;
|
|
288
|
+
} else t11 = $[28];
|
|
289
|
+
let t12;
|
|
290
|
+
if ($[29] !== busy || $[30] !== t10 || $[31] !== t11) {
|
|
291
|
+
t12 = /* @__PURE__ */ jsx(Button, {
|
|
292
|
+
variant: "ghost",
|
|
293
|
+
size: "xs",
|
|
294
|
+
disabled: busy,
|
|
295
|
+
onClick: t10,
|
|
296
|
+
children: t11
|
|
297
|
+
});
|
|
298
|
+
$[29] = busy;
|
|
299
|
+
$[30] = t10;
|
|
300
|
+
$[31] = t11;
|
|
301
|
+
$[32] = t12;
|
|
302
|
+
} else t12 = $[32];
|
|
303
|
+
let t13;
|
|
304
|
+
if ($[33] !== t12 || $[34] !== t7 || $[35] !== t8 || $[36] !== t9) {
|
|
305
|
+
t13 = /* @__PURE__ */ jsxs("span", {
|
|
306
|
+
className: "mt-1.5 flex flex-wrap gap-1",
|
|
307
|
+
children: [
|
|
308
|
+
t7,
|
|
309
|
+
t8,
|
|
310
|
+
t9,
|
|
311
|
+
t12
|
|
312
|
+
]
|
|
313
|
+
});
|
|
314
|
+
$[33] = t12;
|
|
315
|
+
$[34] = t7;
|
|
316
|
+
$[35] = t8;
|
|
317
|
+
$[36] = t9;
|
|
318
|
+
$[37] = t13;
|
|
319
|
+
} else t13 = $[37];
|
|
320
|
+
let t14;
|
|
321
|
+
if ($[38] !== t13 || $[39] !== t6) {
|
|
322
|
+
t14 = /* @__PURE__ */ jsxs(AlertDescription, {
|
|
323
|
+
className: "text-xs",
|
|
324
|
+
children: [t6, t13]
|
|
325
|
+
});
|
|
326
|
+
$[38] = t13;
|
|
327
|
+
$[39] = t6;
|
|
328
|
+
$[40] = t14;
|
|
329
|
+
} else t14 = $[40];
|
|
330
|
+
let t15;
|
|
331
|
+
if ($[41] !== t14 || $[42] !== t5) {
|
|
332
|
+
t15 = /* @__PURE__ */ jsxs(Alert, {
|
|
333
|
+
"data-content-finding": true,
|
|
334
|
+
variant: "warning",
|
|
335
|
+
className: "px-3 py-2",
|
|
336
|
+
children: [
|
|
337
|
+
t3,
|
|
338
|
+
t5,
|
|
339
|
+
t14
|
|
340
|
+
]
|
|
341
|
+
});
|
|
342
|
+
$[41] = t14;
|
|
343
|
+
$[42] = t5;
|
|
344
|
+
$[43] = t15;
|
|
345
|
+
} else t15 = $[43];
|
|
346
|
+
return t15;
|
|
347
|
+
}
|
|
348
|
+
function _temp4(error_0) {
|
|
349
|
+
return toast.error(error_0.message || "Could not dismiss it");
|
|
350
|
+
}
|
|
351
|
+
function _temp3(error) {
|
|
352
|
+
return toast.error(error.message || "Could not apply the fix");
|
|
353
|
+
}
|
|
354
|
+
function _temp2(t0) {
|
|
355
|
+
const { applied } = t0;
|
|
356
|
+
if (!applied) toast.info("The link changed since it was checked, so it's being checked again.");
|
|
357
|
+
}
|
|
358
|
+
/** Opens the Patrol Draft on a Live finding's field, as the Canvas shows it there. */
|
|
359
|
+
function OpenInPatrolDraft(t0) {
|
|
360
|
+
const $ = c(9);
|
|
361
|
+
const { finding, patrolDraft } = t0;
|
|
362
|
+
const showInCanvas = useShowInCanvas();
|
|
363
|
+
const { place } = finding;
|
|
364
|
+
if (place?.kind !== "page") return null;
|
|
365
|
+
let t1;
|
|
366
|
+
if ($[0] !== finding.field || $[1] !== finding.fieldKind || $[2] !== finding.locale || $[3] !== patrolDraft.id || $[4] !== place.blockId || $[5] !== place.itemId || $[6] !== place.pageId || $[7] !== showInCanvas) {
|
|
367
|
+
t1 = /* @__PURE__ */ jsx(Button, {
|
|
368
|
+
variant: "outline",
|
|
369
|
+
size: "xs",
|
|
370
|
+
onClick: () => void showInCanvas({
|
|
371
|
+
pageId: place.pageId,
|
|
372
|
+
locale: finding.locale,
|
|
373
|
+
blockId: place.blockId,
|
|
374
|
+
itemId: place.itemId,
|
|
375
|
+
field: {
|
|
376
|
+
name: finding.field,
|
|
377
|
+
kind: finding.fieldKind
|
|
378
|
+
},
|
|
379
|
+
draft: patrolDraft.id
|
|
380
|
+
}),
|
|
381
|
+
children: "Open the Patrol Draft"
|
|
382
|
+
});
|
|
383
|
+
$[0] = finding.field;
|
|
384
|
+
$[1] = finding.fieldKind;
|
|
385
|
+
$[2] = finding.locale;
|
|
386
|
+
$[3] = patrolDraft.id;
|
|
387
|
+
$[4] = place.blockId;
|
|
388
|
+
$[5] = place.itemId;
|
|
389
|
+
$[6] = place.pageId;
|
|
390
|
+
$[7] = showInCanvas;
|
|
391
|
+
$[8] = t1;
|
|
392
|
+
} else t1 = $[8];
|
|
393
|
+
return t1;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
//#endregion
|
|
397
|
+
export { ContentFindings, findingsHint, useContentFindings };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { studioStore } from "../studioStore.js";
|
|
3
|
+
import { plural } from "../draftLabel.js";
|
|
4
|
+
import { useDrafts } from "./DraftsControl.js";
|
|
5
|
+
import { c } from "react/compiler-runtime";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Button } from "@camox/ui/button";
|
|
9
|
+
import { FloatingToolbar } from "@camox/ui/floating-toolbar";
|
|
10
|
+
|
|
11
|
+
//#region src/features/studio/components/DraftBar.tsx
|
|
12
|
+
/**
|
|
13
|
+
* How long a draft goes without a change before its bar shows, so it doesn't pop up mid-edit.
|
|
14
|
+
*/
|
|
15
|
+
const SETTLE_MS = 1500;
|
|
16
|
+
/**
|
|
17
|
+
* Asks what to do with the draft being viewed, once its edits settle: discard its changes or
|
|
18
|
+
* publish them. `stacked` places it in the Preview toolbar's column, just above the toolbar;
|
|
19
|
+
* otherwise it floats at the bottom of the screen on its own.
|
|
20
|
+
*/
|
|
21
|
+
function DraftBar(t0) {
|
|
22
|
+
const $ = c(15);
|
|
23
|
+
const { stacked: t1 } = t0;
|
|
24
|
+
const stacked = t1 === void 0 ? false : t1;
|
|
25
|
+
const { projectId, current } = useDrafts();
|
|
26
|
+
const settled = useSettled(current?.id ?? null, current?.lastChangedAt ?? null);
|
|
27
|
+
if (!projectId || !current || !settled) return null;
|
|
28
|
+
const empty = current.changeCount === 0;
|
|
29
|
+
const t2 = stacked ? "pointer-events-auto relative left-auto translate-x-0" : "fixed bottom-2";
|
|
30
|
+
let t3;
|
|
31
|
+
if ($[0] !== t2) {
|
|
32
|
+
t3 = cn("w-max gap-4", t2);
|
|
33
|
+
$[0] = t2;
|
|
34
|
+
$[1] = t3;
|
|
35
|
+
} else t3 = $[1];
|
|
36
|
+
let t4;
|
|
37
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
38
|
+
t4 = /* @__PURE__ */ jsx("span", {
|
|
39
|
+
"aria-hidden": true,
|
|
40
|
+
className: "size-2 shrink-0 rounded-full bg-blue-500"
|
|
41
|
+
});
|
|
42
|
+
$[2] = t4;
|
|
43
|
+
} else t4 = $[2];
|
|
44
|
+
let t5;
|
|
45
|
+
if ($[3] !== current.changeCount || $[4] !== empty) {
|
|
46
|
+
t5 = empty ? "No changes yet" : plural(current.changeCount, "pending change");
|
|
47
|
+
$[3] = current.changeCount;
|
|
48
|
+
$[4] = empty;
|
|
49
|
+
$[5] = t5;
|
|
50
|
+
} else t5 = $[5];
|
|
51
|
+
let t6;
|
|
52
|
+
if ($[6] !== t5) {
|
|
53
|
+
t6 = /* @__PURE__ */ jsxs("span", {
|
|
54
|
+
className: "flex items-center gap-2 px-2 text-sm",
|
|
55
|
+
children: [t4, t5]
|
|
56
|
+
});
|
|
57
|
+
$[6] = t5;
|
|
58
|
+
$[7] = t6;
|
|
59
|
+
} else t6 = $[7];
|
|
60
|
+
let t7;
|
|
61
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
62
|
+
t7 = /* @__PURE__ */ jsx(Button, {
|
|
63
|
+
type: "button",
|
|
64
|
+
variant: "outline",
|
|
65
|
+
onClick: _temp,
|
|
66
|
+
children: "Discard"
|
|
67
|
+
});
|
|
68
|
+
$[8] = t7;
|
|
69
|
+
} else t7 = $[8];
|
|
70
|
+
let t8;
|
|
71
|
+
if ($[9] !== empty) {
|
|
72
|
+
t8 = /* @__PURE__ */ jsxs("div", {
|
|
73
|
+
className: "flex items-center gap-2",
|
|
74
|
+
children: [t7, /* @__PURE__ */ jsx(Button, {
|
|
75
|
+
type: "button",
|
|
76
|
+
disabled: empty,
|
|
77
|
+
onClick: _temp2,
|
|
78
|
+
children: "Publish…"
|
|
79
|
+
})]
|
|
80
|
+
});
|
|
81
|
+
$[9] = empty;
|
|
82
|
+
$[10] = t8;
|
|
83
|
+
} else t8 = $[10];
|
|
84
|
+
let t9;
|
|
85
|
+
if ($[11] !== t3 || $[12] !== t6 || $[13] !== t8) {
|
|
86
|
+
t9 = /* @__PURE__ */ jsxs(FloatingToolbar, {
|
|
87
|
+
"aria-label": "Draft",
|
|
88
|
+
className: t3,
|
|
89
|
+
children: [t6, t8]
|
|
90
|
+
});
|
|
91
|
+
$[11] = t3;
|
|
92
|
+
$[12] = t6;
|
|
93
|
+
$[13] = t8;
|
|
94
|
+
$[14] = t9;
|
|
95
|
+
} else t9 = $[14];
|
|
96
|
+
return t9;
|
|
97
|
+
}
|
|
98
|
+
function _temp2() {
|
|
99
|
+
return studioStore.send({ type: "openReviewDraftSheet" });
|
|
100
|
+
}
|
|
101
|
+
function _temp() {
|
|
102
|
+
return studioStore.send({ type: "openDeleteDraftDialog" });
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Whether the draft went without a change for `SETTLE_MS`. Once settled it stays so for that
|
|
106
|
+
* draft, so the bar doesn't hide again on the next edit.
|
|
107
|
+
*/
|
|
108
|
+
function useSettled(draftId, lastChangedAt) {
|
|
109
|
+
const $ = c(5);
|
|
110
|
+
const [settledDraft, setSettledDraft] = React.useState(null);
|
|
111
|
+
let t0;
|
|
112
|
+
let t1;
|
|
113
|
+
if ($[0] !== draftId || $[1] !== lastChangedAt || $[2] !== settledDraft) {
|
|
114
|
+
t0 = () => {
|
|
115
|
+
if (!draftId || settledDraft === draftId) return;
|
|
116
|
+
const wait = Math.max(0, (lastChangedAt ?? 0) + SETTLE_MS - Date.now());
|
|
117
|
+
const timer = setTimeout(() => setSettledDraft(draftId), wait);
|
|
118
|
+
return () => clearTimeout(timer);
|
|
119
|
+
};
|
|
120
|
+
t1 = [
|
|
121
|
+
draftId,
|
|
122
|
+
lastChangedAt,
|
|
123
|
+
settledDraft
|
|
124
|
+
];
|
|
125
|
+
$[0] = draftId;
|
|
126
|
+
$[1] = lastChangedAt;
|
|
127
|
+
$[2] = settledDraft;
|
|
128
|
+
$[3] = t0;
|
|
129
|
+
$[4] = t1;
|
|
130
|
+
} else {
|
|
131
|
+
t0 = $[3];
|
|
132
|
+
t1 = $[4];
|
|
133
|
+
}
|
|
134
|
+
React.useEffect(t0, t1);
|
|
135
|
+
return !!draftId && settledDraft === draftId;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
export { DraftBar, SETTLE_MS };
|
|
@@ -14,7 +14,6 @@ import { useSelector } from "@xstate/store-react";
|
|
|
14
14
|
import { Button } from "@camox/ui/button";
|
|
15
15
|
import { ChevronsUpDown } from "lucide-react";
|
|
16
16
|
import { toast } from "@camox/ui/toaster";
|
|
17
|
-
import { Badge } from "@camox/ui/badge";
|
|
18
17
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@camox/ui/dropdown-menu";
|
|
19
18
|
|
|
20
19
|
//#region src/features/studio/components/DraftsControl.tsx
|
|
@@ -374,7 +373,6 @@ function _temp5() {
|
|
|
374
373
|
function _temp4() {
|
|
375
374
|
studioStore.send({ type: "closeReviewDraftSheet" });
|
|
376
375
|
studioStore.send({ type: "closeDeleteDraftDialog" });
|
|
377
|
-
studioStore.send({ type: "closeKeepDraft" });
|
|
378
376
|
}
|
|
379
377
|
function _temp3(t0) {
|
|
380
378
|
const { move } = t0;
|
|
@@ -387,47 +385,6 @@ function _temp(state) {
|
|
|
387
385
|
return state.context.reviewDraftSheet;
|
|
388
386
|
}
|
|
389
387
|
/**
|
|
390
|
-
* The current draft's pending changes, which open its review to publish or delete them. Live
|
|
391
|
-
* has none, so it shows nothing there. An unnamed draft shows the Unnamed Draft Bar instead.
|
|
392
|
-
*/
|
|
393
|
-
function PendingChanges() {
|
|
394
|
-
const $ = c(7);
|
|
395
|
-
const { current } = useDrafts();
|
|
396
|
-
if (!current || current.name === null) return null;
|
|
397
|
-
let t0;
|
|
398
|
-
if ($[0] !== current.changeCount) {
|
|
399
|
-
t0 = plural(current.changeCount, "change");
|
|
400
|
-
$[0] = current.changeCount;
|
|
401
|
-
$[1] = t0;
|
|
402
|
-
} else t0 = $[1];
|
|
403
|
-
const t1 = `Review ${t0}`;
|
|
404
|
-
let t2;
|
|
405
|
-
if ($[2] !== current.changeCount) {
|
|
406
|
-
t2 = /* @__PURE__ */ jsx(Badge, {
|
|
407
|
-
className: "bg-primary-foreground/20 text-primary-foreground min-w-5 px-1.5 tabular-nums",
|
|
408
|
-
children: current.changeCount
|
|
409
|
-
});
|
|
410
|
-
$[2] = current.changeCount;
|
|
411
|
-
$[3] = t2;
|
|
412
|
-
} else t2 = $[3];
|
|
413
|
-
let t3;
|
|
414
|
-
if ($[4] !== t1 || $[5] !== t2) {
|
|
415
|
-
t3 = /* @__PURE__ */ jsxs(Button, {
|
|
416
|
-
type: "button",
|
|
417
|
-
"aria-label": t1,
|
|
418
|
-
onClick: _temp9,
|
|
419
|
-
children: ["Review changes", t2]
|
|
420
|
-
});
|
|
421
|
-
$[4] = t1;
|
|
422
|
-
$[5] = t2;
|
|
423
|
-
$[6] = t3;
|
|
424
|
-
} else t3 = $[6];
|
|
425
|
-
return t3;
|
|
426
|
-
}
|
|
427
|
-
function _temp9() {
|
|
428
|
-
return studioStore.send({ type: "openReviewDraftSheet" });
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
388
|
* The drafts controls' actions in the command palette, offered where the controls offer them. The palette only opens the review and the delete confirmation; it never publishes or
|
|
432
389
|
* deletes by itself.
|
|
433
390
|
*/
|
|
@@ -453,7 +410,7 @@ function useDraftsActions(t0) {
|
|
|
453
410
|
],
|
|
454
411
|
groupLabel: "Drafts",
|
|
455
412
|
checkIfAvailable: () => inDraft,
|
|
456
|
-
execute:
|
|
413
|
+
execute: _temp9
|
|
457
414
|
},
|
|
458
415
|
{
|
|
459
416
|
id: "delete-draft",
|
|
@@ -469,22 +426,15 @@ function useDraftsActions(t0) {
|
|
|
469
426
|
],
|
|
470
427
|
groupLabel: "Drafts",
|
|
471
428
|
checkIfAvailable: () => inDraft,
|
|
472
|
-
execute:
|
|
429
|
+
execute: _temp10
|
|
473
430
|
},
|
|
474
431
|
{
|
|
475
432
|
id: "rename-draft",
|
|
476
|
-
label: unnamed ? "
|
|
477
|
-
aliases: unnamed ? [
|
|
478
|
-
"Name draft",
|
|
479
|
-
"Rename draft",
|
|
480
|
-
"Save draft"
|
|
481
|
-
] : ["Name draft"],
|
|
433
|
+
label: unnamed ? "Name draft…" : "Rename draft…",
|
|
434
|
+
aliases: unnamed ? ["Rename draft", "Save draft"] : ["Name draft"],
|
|
482
435
|
groupLabel: "Drafts",
|
|
483
436
|
checkIfAvailable: () => inDraft,
|
|
484
|
-
execute:
|
|
485
|
-
type: "openReviewDraftSheet",
|
|
486
|
-
startRenaming: true
|
|
487
|
-
})
|
|
437
|
+
execute: _temp11
|
|
488
438
|
},
|
|
489
439
|
{
|
|
490
440
|
id: "switch-to-live",
|
|
@@ -561,9 +511,15 @@ function _temp13() {
|
|
|
561
511
|
}
|
|
562
512
|
function _temp12() {}
|
|
563
513
|
function _temp11() {
|
|
564
|
-
return studioStore.send({
|
|
514
|
+
return studioStore.send({
|
|
515
|
+
type: "openReviewDraftSheet",
|
|
516
|
+
startRenaming: true
|
|
517
|
+
});
|
|
565
518
|
}
|
|
566
519
|
function _temp10() {
|
|
520
|
+
return studioStore.send({ type: "openDeleteDraftDialog" });
|
|
521
|
+
}
|
|
522
|
+
function _temp9() {
|
|
567
523
|
return studioStore.send({ type: "openReviewDraftSheet" });
|
|
568
524
|
}
|
|
569
525
|
/** Who published Live last and when: a member, a release, or nobody yet. */
|
|
@@ -648,4 +604,4 @@ function DraftItem(t0) {
|
|
|
648
604
|
}
|
|
649
605
|
|
|
650
606
|
//#endregion
|
|
651
|
-
export { DraftPicker,
|
|
607
|
+
export { DraftPicker, useDrafts };
|
|
@@ -7,7 +7,8 @@ import { useLocalePath, useLocalizedPath } from "../../../lib/view-locale.js";
|
|
|
7
7
|
import { STUDIO_BASE_PATH, STUDIO_CONTENT_PATH, STUDIO_SETTINGS_PATH } from "../routes.js";
|
|
8
8
|
import { studioStore } from "../studioStore.js";
|
|
9
9
|
import { UserButton } from "./UserButton.js";
|
|
10
|
-
import {
|
|
10
|
+
import { ConnectAgent } from "./ConnectAgent.js";
|
|
11
|
+
import { DraftPicker } from "./DraftsControl.js";
|
|
11
12
|
import { LocalePicker } from "./LocalePicker.js";
|
|
12
13
|
import { ProjectMenu } from "./ProjectMenu.js";
|
|
13
14
|
import { c } from "react/compiler-runtime";
|
|
@@ -144,7 +145,7 @@ const Navbar = (t0) => {
|
|
|
144
145
|
if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
|
|
145
146
|
t10 = /* @__PURE__ */ jsxs("div", {
|
|
146
147
|
className: "flex items-center gap-2",
|
|
147
|
-
children: [/* @__PURE__ */ jsx(
|
|
148
|
+
children: [/* @__PURE__ */ jsx(ConnectAgent, {}), /* @__PURE__ */ jsx(UserButton, {})]
|
|
148
149
|
});
|
|
149
150
|
$[23] = t10;
|
|
150
151
|
} else t10 = $[23];
|