camox 0.78.0 → 0.80.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.
@@ -0,0 +1,443 @@
1
+ import { useDraftScope } from "../../lib/draft-scope.js";
2
+ import { useNavigate } from "../navigation/navigation.js";
3
+ import { reads, useReadQuery, useStudioCache } from "../../lib/studio-reads.js";
4
+ import { cn } from "../../lib/utils.js";
5
+ import { brandMutations } from "../../lib/queries.js";
6
+ import { previewStore } from "../preview/previewStore.js";
7
+ import { useWebsiteHref } from "../studio/components/Navbar.js";
8
+ import { BrandPart } from "./BrandPart.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 { Skeleton } from "@camox/ui/skeleton";
15
+ import { Spinner } from "@camox/ui/spinner";
16
+ import { Slider } from "@base-ui/react/slider";
17
+ import { VOICE_AXES } from "@camox/api-contract/voice";
18
+
19
+ //#region src/features/brand/VoiceGroup.tsx
20
+ /**
21
+ * The Voice group, at the top of the Brand Section (ADR 0051): a slider per Voice Axis, showing
22
+ * its chosen step and that step's definition, as models read it. Moving sliders saves nothing:
23
+ * Save shows while they differ from the saved Voice, and saves every moved axis as one change.
24
+ * Like any edit to the brand, saving while viewing Live starts a draft. "Save and rewrite", beside it,
25
+ * also asks Camox's agent, as the member, to rewrite the site's copy in the new Voice, and shows
26
+ * the draft with its thread beside the Canvas, where the rewrite happens.
27
+ */
28
+ function VoiceGroup(t0) {
29
+ const $ = c(37);
30
+ const { projectId } = t0;
31
+ let t1;
32
+ if ($[0] !== projectId) {
33
+ t1 = reads.voice({ projectId });
34
+ $[0] = projectId;
35
+ $[1] = t1;
36
+ } else t1 = $[1];
37
+ const { data: saved } = useReadQuery(t1);
38
+ let t2;
39
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
40
+ t2 = {};
41
+ $[2] = t2;
42
+ } else t2 = $[2];
43
+ const [moved, setMoved] = React.useState(t2);
44
+ const cache = useStudioCache();
45
+ const draftScope = useDraftScope();
46
+ const navigate = useNavigate();
47
+ const websiteHref = useWebsiteHref();
48
+ const heading = React.useRef(null);
49
+ const actions = React.useRef(null);
50
+ const [justSaved, setJustSaved] = React.useState(false);
51
+ let t3;
52
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
53
+ t3 = brandMutations.saveVoice();
54
+ $[3] = t3;
55
+ } else t3 = $[3];
56
+ let t4;
57
+ if ($[4] !== cache || $[5] !== draftScope || $[6] !== navigate || $[7] !== projectId || $[8] !== websiteHref) {
58
+ t4 = {
59
+ ...t3,
60
+ onSuccess: (_voice, t5) => {
61
+ const { rewrite } = t5;
62
+ const focused = document.activeElement;
63
+ const focusWasOnSave = !focused || focused === document.body || actions.current?.contains(focused);
64
+ setMoved({});
65
+ cache.invalidate(reads.voice({ projectId }));
66
+ if (!rewrite) {
67
+ setJustSaved(true);
68
+ if (focusWasOnSave) heading.current?.focus();
69
+ return;
70
+ }
71
+ previewStore.send({ type: "showCanvas" });
72
+ navigate({
73
+ to: websiteHref(),
74
+ draft: draftScope.current() ?? void 0
75
+ });
76
+ }
77
+ };
78
+ $[4] = cache;
79
+ $[5] = draftScope;
80
+ $[6] = navigate;
81
+ $[7] = projectId;
82
+ $[8] = websiteHref;
83
+ $[9] = t4;
84
+ } else t4 = $[9];
85
+ const save = useMutation(t4);
86
+ let t5;
87
+ if ($[10] !== moved || $[11] !== saved) {
88
+ t5 = saved && {
89
+ ...saved,
90
+ ...moved
91
+ };
92
+ $[10] = moved;
93
+ $[11] = saved;
94
+ $[12] = t5;
95
+ } else t5 = $[12];
96
+ const voice = t5;
97
+ let t6;
98
+ if ($[13] !== saved || $[14] !== voice) {
99
+ t6 = saved && voice ? changedAxes(saved, voice) : {};
100
+ $[13] = saved;
101
+ $[14] = voice;
102
+ $[15] = t6;
103
+ } else t6 = $[15];
104
+ const changed = t6;
105
+ let t7;
106
+ if ($[16] !== changed) {
107
+ t7 = Object.keys(changed);
108
+ $[16] = changed;
109
+ $[17] = t7;
110
+ } else t7 = $[17];
111
+ const dirty = t7.length > 0;
112
+ const t8 = dirty ? "The Voice has unsaved changes." : justSaved ? "Voice saved." : "";
113
+ let t9;
114
+ if ($[18] !== t8) {
115
+ t9 = /* @__PURE__ */ jsx("p", {
116
+ role: "status",
117
+ className: "sr-only",
118
+ children: t8
119
+ });
120
+ $[18] = t8;
121
+ $[19] = t9;
122
+ } else t9 = $[19];
123
+ let t10;
124
+ if ($[20] !== changed || $[21] !== dirty || $[22] !== projectId || $[23] !== save) {
125
+ t10 = dirty && /* @__PURE__ */ jsxs("div", {
126
+ className: "flex flex-wrap gap-2",
127
+ children: [/* @__PURE__ */ jsxs(Button, {
128
+ disabled: save.isPending,
129
+ onClick: () => save.mutate({
130
+ projectId,
131
+ steps: changed
132
+ }),
133
+ children: [save.isPending && !save.variables?.rewrite && /* @__PURE__ */ jsx(Spinner, {}), "Save"]
134
+ }), /* @__PURE__ */ jsxs(Button, {
135
+ variant: "outline",
136
+ disabled: save.isPending,
137
+ onClick: () => save.mutate({
138
+ projectId,
139
+ steps: changed,
140
+ rewrite: true
141
+ }),
142
+ children: [save.isPending && save.variables?.rewrite && /* @__PURE__ */ jsx(Spinner, {}), "Save and rewrite"]
143
+ })]
144
+ });
145
+ $[20] = changed;
146
+ $[21] = dirty;
147
+ $[22] = projectId;
148
+ $[23] = save;
149
+ $[24] = t10;
150
+ } else t10 = $[24];
151
+ let t11;
152
+ if ($[25] !== save.error) {
153
+ t11 = save.error && /* @__PURE__ */ jsx("p", {
154
+ "data-voice-error": true,
155
+ role: "alert",
156
+ className: "text-destructive text-xs",
157
+ children: save.error.message
158
+ });
159
+ $[25] = save.error;
160
+ $[26] = t11;
161
+ } else t11 = $[26];
162
+ let t12;
163
+ if ($[27] !== t10 || $[28] !== t11 || $[29] !== t9) {
164
+ t12 = /* @__PURE__ */ jsxs("div", {
165
+ ref: actions,
166
+ className: "flex flex-col items-start gap-3",
167
+ children: [
168
+ t9,
169
+ t10,
170
+ t11
171
+ ]
172
+ });
173
+ $[27] = t10;
174
+ $[28] = t11;
175
+ $[29] = t9;
176
+ $[30] = t12;
177
+ } else t12 = $[30];
178
+ let t13;
179
+ if ($[31] !== save || $[32] !== voice) {
180
+ t13 = voice ? /* @__PURE__ */ jsx("ul", {
181
+ className: "flex flex-col gap-12",
182
+ children: VOICE_AXES.map((axis) => /* @__PURE__ */ jsx(VoiceAxisRow, {
183
+ axis,
184
+ step: voice[axis.key],
185
+ disabled: save.isPending,
186
+ onStep: (step) => {
187
+ setMoved((current) => ({
188
+ ...current,
189
+ [axis.key]: step
190
+ }));
191
+ setJustSaved(false);
192
+ save.reset();
193
+ }
194
+ }, axis.key))
195
+ }) : /* @__PURE__ */ jsx(Skeleton, { className: "h-96" });
196
+ $[31] = save;
197
+ $[32] = voice;
198
+ $[33] = t13;
199
+ } else t13 = $[33];
200
+ let t14;
201
+ if ($[34] !== t12 || $[35] !== t13) {
202
+ t14 = /* @__PURE__ */ jsx(BrandPart, {
203
+ "data-voice": true,
204
+ title: "Voice",
205
+ description: "How the website speaks to visitors.",
206
+ headingRef: heading,
207
+ aside: t12,
208
+ children: t13
209
+ });
210
+ $[34] = t12;
211
+ $[35] = t13;
212
+ $[36] = t14;
213
+ } else t14 = $[36];
214
+ return t14;
215
+ }
216
+ /** The axes `voice` moves away from `saved`, with their new steps. */
217
+ function changedAxes(saved, voice) {
218
+ const changed = {};
219
+ for (const { key } of VOICE_AXES) if (voice[key] !== saved[key]) changed[key] = voice[key];
220
+ return changed;
221
+ }
222
+ const sentenceCase = (text) => text.charAt(0).toUpperCase() + text.slice(1);
223
+ /**
224
+ * One Voice Axis: its name over an oversized slider, with the chosen step's name and definition
225
+ * centered under its stop, and following it as it moves.
226
+ */
227
+ function VoiceAxisRow(t0) {
228
+ const $ = c(55);
229
+ const { axis, step, disabled, onStep } = t0;
230
+ const steps = axis.steps;
231
+ const last = steps.length - 1;
232
+ let t1;
233
+ if ($[0] !== step || $[1] !== steps) {
234
+ let t2;
235
+ if ($[3] !== step) {
236
+ t2 = (candidate) => candidate.key === step;
237
+ $[3] = step;
238
+ $[4] = t2;
239
+ } else t2 = $[4];
240
+ t1 = steps.findIndex(t2);
241
+ $[0] = step;
242
+ $[1] = steps;
243
+ $[2] = t1;
244
+ } else t1 = $[2];
245
+ const index = Math.max(t1, 0);
246
+ const chosen = steps[index];
247
+ const at = index / last * 100;
248
+ let t2;
249
+ if ($[5] !== axis.name) {
250
+ t2 = /* @__PURE__ */ jsx("h3", {
251
+ "data-voice-axis-name": true,
252
+ className: "text-sm font-medium",
253
+ children: axis.name
254
+ });
255
+ $[5] = axis.name;
256
+ $[6] = t2;
257
+ } else t2 = $[6];
258
+ let t3;
259
+ if ($[7] !== onStep || $[8] !== steps) {
260
+ t3 = (value) => {
261
+ const next = steps[value];
262
+ if (next) onStep(next.key);
263
+ };
264
+ $[7] = onStep;
265
+ $[8] = steps;
266
+ $[9] = t3;
267
+ } else t3 = $[9];
268
+ let t4;
269
+ if ($[10] !== last || $[11] !== steps) {
270
+ let t5;
271
+ if ($[13] !== last) {
272
+ t5 = (candidate_0, stop) => /* @__PURE__ */ jsx("span", {
273
+ "aria-hidden": true,
274
+ className: "bg-muted-foreground/80 absolute top-1/2 size-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full",
275
+ style: { left: `${stop / last * 100}%` }
276
+ }, candidate_0.key);
277
+ $[13] = last;
278
+ $[14] = t5;
279
+ } else t5 = $[14];
280
+ t4 = steps.map(t5);
281
+ $[10] = last;
282
+ $[11] = steps;
283
+ $[12] = t4;
284
+ } else t4 = $[12];
285
+ let t5;
286
+ if ($[15] !== t4) {
287
+ t5 = /* @__PURE__ */ jsx(Slider.Track, {
288
+ className: "bg-muted relative h-2 w-full rounded-full",
289
+ children: /* @__PURE__ */ jsx("div", {
290
+ className: "pointer-events-none absolute inset-x-3.5 inset-y-0",
291
+ children: t4
292
+ })
293
+ });
294
+ $[15] = t4;
295
+ $[16] = t5;
296
+ } else t5 = $[16];
297
+ let t6;
298
+ if ($[17] !== axis.name) {
299
+ t6 = () => axis.name;
300
+ $[17] = axis.name;
301
+ $[18] = t6;
302
+ } else t6 = $[18];
303
+ const t7 = chosen.name;
304
+ const t8 = steps.length;
305
+ let t9;
306
+ if ($[19] !== chosen.definition) {
307
+ t9 = sentenceCase(chosen.definition);
308
+ $[19] = chosen.definition;
309
+ $[20] = t9;
310
+ } else t9 = $[20];
311
+ const t10 = `${t7}, ${index + 1} of ${t8}. ${t9}`;
312
+ let t11;
313
+ if ($[21] !== t10 || $[22] !== t6) {
314
+ t11 = /* @__PURE__ */ jsx(Slider.Thumb, {
315
+ getAriaLabel: t6,
316
+ "aria-valuetext": t10,
317
+ className: "border-primary bg-background ring-ring/50 block size-7 shrink-0 rounded-full border-[3px] shadow-md transition-[left,box-shadow] duration-150 ease-out outline-none hover:ring-4 has-focus-visible:ring-4 data-disabled:pointer-events-none motion-reduce:transition-none"
318
+ });
319
+ $[21] = t10;
320
+ $[22] = t6;
321
+ $[23] = t11;
322
+ } else t11 = $[23];
323
+ let t12;
324
+ if ($[24] !== t11 || $[25] !== t5) {
325
+ t12 = /* @__PURE__ */ jsxs(Slider.Control, {
326
+ className: "relative flex h-8 w-full cursor-pointer touch-none items-center select-none data-disabled:cursor-not-allowed",
327
+ children: [t5, t11]
328
+ });
329
+ $[24] = t11;
330
+ $[25] = t5;
331
+ $[26] = t12;
332
+ } else t12 = $[26];
333
+ let t13;
334
+ if ($[27] !== disabled || $[28] !== index || $[29] !== last || $[30] !== t12 || $[31] !== t3) {
335
+ t13 = /* @__PURE__ */ jsx(Slider.Root, {
336
+ value: index,
337
+ min: 0,
338
+ max: last,
339
+ step: 1,
340
+ thumbAlignment: "edge",
341
+ disabled,
342
+ className: "data-disabled:opacity-50",
343
+ onValueChange: t3,
344
+ children: t12
345
+ });
346
+ $[27] = disabled;
347
+ $[28] = index;
348
+ $[29] = last;
349
+ $[30] = t12;
350
+ $[31] = t3;
351
+ $[32] = t13;
352
+ } else t13 = $[32];
353
+ const t14 = index === 0 ? "text-left" : index === last ? "text-right" : "text-center";
354
+ let t15;
355
+ if ($[33] !== t14) {
356
+ t15 = cn("transition-[margin-left] duration-200 ease-out motion-reduce:transition-none", t14);
357
+ $[33] = t14;
358
+ $[34] = t15;
359
+ } else t15 = $[34];
360
+ const t16 = `clamp(-0.875rem, calc(${at}% - min(8rem, 50%)), calc(100% + 0.875rem - min(16rem, 100%)))`;
361
+ let t17;
362
+ if ($[35] !== t16) {
363
+ t17 = {
364
+ width: "min(16rem, 100%)",
365
+ marginLeft: t16
366
+ };
367
+ $[35] = t16;
368
+ $[36] = t17;
369
+ } else t17 = $[36];
370
+ const t18 = chosen.key;
371
+ let t19;
372
+ if ($[37] !== chosen.name) {
373
+ t19 = /* @__PURE__ */ jsx("p", {
374
+ "data-voice-step": true,
375
+ className: "font-semibold",
376
+ children: chosen.name
377
+ });
378
+ $[37] = chosen.name;
379
+ $[38] = t19;
380
+ } else t19 = $[38];
381
+ let t20;
382
+ if ($[39] !== chosen.definition) {
383
+ t20 = sentenceCase(chosen.definition);
384
+ $[39] = chosen.definition;
385
+ $[40] = t20;
386
+ } else t20 = $[40];
387
+ let t21;
388
+ if ($[41] !== t20) {
389
+ t21 = /* @__PURE__ */ jsx("p", {
390
+ "data-voice-definition": true,
391
+ className: "text-muted-foreground mt-0.5 text-sm",
392
+ children: t20
393
+ });
394
+ $[41] = t20;
395
+ $[42] = t21;
396
+ } else t21 = $[42];
397
+ let t22;
398
+ if ($[43] !== chosen.key || $[44] !== t19 || $[45] !== t21) {
399
+ t22 = /* @__PURE__ */ jsxs("div", {
400
+ className: "animate-in fade-in-0 duration-200",
401
+ children: [t19, t21]
402
+ }, t18);
403
+ $[43] = chosen.key;
404
+ $[44] = t19;
405
+ $[45] = t21;
406
+ $[46] = t22;
407
+ } else t22 = $[46];
408
+ let t23;
409
+ if ($[47] !== t15 || $[48] !== t17 || $[49] !== t22) {
410
+ t23 = /* @__PURE__ */ jsx("div", {
411
+ className: "mx-3.5 min-h-21",
412
+ children: /* @__PURE__ */ jsx("div", {
413
+ className: t15,
414
+ style: t17,
415
+ children: t22
416
+ })
417
+ });
418
+ $[47] = t15;
419
+ $[48] = t17;
420
+ $[49] = t22;
421
+ $[50] = t23;
422
+ } else t23 = $[50];
423
+ let t24;
424
+ if ($[51] !== t13 || $[52] !== t2 || $[53] !== t23) {
425
+ t24 = /* @__PURE__ */ jsxs("li", {
426
+ "data-voice-axis": true,
427
+ className: "flex flex-col gap-3",
428
+ children: [
429
+ t2,
430
+ t13,
431
+ t23
432
+ ]
433
+ });
434
+ $[51] = t13;
435
+ $[52] = t2;
436
+ $[53] = t23;
437
+ $[54] = t24;
438
+ } else t24 = $[54];
439
+ return t24;
440
+ }
441
+
442
+ //#endregion
443
+ export { VoiceGroup };
@@ -3,7 +3,7 @@ import { CamoxContent } from "../content/CamoxContent.js";
3
3
  import { AuthenticatedCamoxProvider } from "../provider/AuthenticatedCamoxProvider.js";
4
4
  import { CamoxStudio } from "../studio/CamoxStudio.js";
5
5
  import { CompleteBlockEditingRuntimeProvider } from "../../core/editing/CompleteBlockEditingRuntime.js";
6
- import { CamoxMemory } from "../memory/CamoxMemory.js";
6
+ import { CamoxBrand } from "../brand/CamoxBrand.js";
7
7
  import { CamoxSettings } from "../settings/CamoxSettings.js";
8
8
  import { c } from "react/compiler-runtime";
9
9
  import { jsx } from "react/jsx-runtime";
@@ -12,7 +12,7 @@ import { jsx } from "react/jsx-runtime";
12
12
  /** The studio section each studio route shows. */
13
13
  const STUDIO_SECTIONS = {
14
14
  "studio-content": CamoxContent,
15
- "studio-memory": CamoxMemory,
15
+ "studio-brand": CamoxBrand,
16
16
  "studio-settings": CamoxSettings
17
17
  };
18
18
  function EditablePageExperience(t0) {
@@ -0,0 +1,3 @@
1
+ import { artifactFrameProps } from "../../core/lib/artifact.js";
2
+ import { connectArtifactHost } from "../../core/lib/artifactHost.js";
3
+ export { artifactFrameProps, connectArtifactHost };
@@ -0,0 +1,4 @@
1
+ import { artifactFrameProps } from "../../core/lib/artifact.js";
2
+ import { connectArtifactHost } from "../../core/lib/artifactHost.js";
3
+
4
+ export { artifactFrameProps, connectArtifactHost };
@@ -11,7 +11,7 @@ import { LookPlaceholderHeight } from "@camox/api-contract/drafts";
11
11
  import { UseHeadInput } from "unhead/types";
12
12
  //#region src/features/runtime/runtime.d.ts
13
13
  /** The studio's own routes, rather than a page or the Canvas. */
14
- declare const STUDIO_ROUTE_KINDS: readonly ["studio", "studio-content", "studio-memory", "studio-settings", "studio-nested"];
14
+ declare const STUDIO_ROUTE_KINDS: readonly ["studio", "studio-content", "studio-brand", "studio-settings", "studio-nested"];
15
15
  export type StudioRouteKind = (typeof STUDIO_ROUTE_KINDS)[number];
16
16
  export type RuntimeRouteKind = RuntimeOwnedRouteKind | "canvas" | "page" | StudioRouteKind;
17
17
  export interface RuntimeRouteMatch {
@@ -8,7 +8,7 @@ import { ARTIFACTS_PATH_PREFIX, RUNTIME_ROUTE_PATHS, matchRuntimeOwnedRoute } fr
8
8
  import { reads } from "../../lib/studio-reads.js";
9
9
  import { recordMarkdownTemplate } from "../../core/recordItem.js";
10
10
  import { PLATFORM_SCRIPT } from "../../lib/platform.js";
11
- import { STUDIO_ASSETS_PATH, STUDIO_CANVAS_PATH, STUDIO_CONTENT_PATH, STUDIO_MEMORY_PATH, STUDIO_SETTINGS_PATH, matchCollectionContentPath } from "../studio/routes.js";
11
+ import { STUDIO_ASSETS_PATH, STUDIO_BRAND_PATH, STUDIO_CANVAS_PATH, STUDIO_CONTENT_PATH, STUDIO_SETTINGS_PATH, matchCollectionContentPath } from "../studio/routes.js";
12
12
  import { STUDIO_THEME_SCRIPT } from "../studio/studioTheme.js";
13
13
  import { DefaultPageImage, renderPageImage } from "../og/pageImage.js";
14
14
  import { discoverLayoutPages } from "../../core/derivedRoutes.js";
@@ -39,7 +39,7 @@ const DEFAULT_RUNTIME_BASE_PATH = "";
39
39
  const STUDIO_ROUTE_KINDS = [
40
40
  "studio",
41
41
  "studio-content",
42
- "studio-memory",
42
+ "studio-brand",
43
43
  "studio-settings",
44
44
  "studio-nested"
45
45
  ];
@@ -123,8 +123,8 @@ function matchRuntimeRoute(pathname) {
123
123
  kind: "studio-content",
124
124
  pathname
125
125
  };
126
- if (pathname === "/camox/memory" || pathname === `${"/camox/memory"}/`) return {
127
- kind: "studio-memory",
126
+ if (pathname === "/camox/brand" || pathname === `${"/camox/brand"}/`) return {
127
+ kind: "studio-brand",
128
128
  pathname
129
129
  };
130
130
  if (pathname === "/camox/settings" || pathname === `${"/camox/settings"}/`) return {
@@ -16,15 +16,16 @@ import { toast } from "@camox/ui/toaster";
16
16
  import { Skeleton } from "@camox/ui/skeleton";
17
17
  import { Spinner } from "@camox/ui/spinner";
18
18
  import { Popover, PopoverContent, PopoverHeader, PopoverTitle, PopoverTrigger } from "@camox/ui/popover";
19
+ import { voiceAxis, voiceStep } from "@camox/api-contract/voice";
19
20
 
20
21
  //#region src/features/studio/components/DraftReview.tsx
21
22
  /**
22
- * Where a subject sits: its page or layout, or the files, the languages or memory, which belong
23
- * to none.
23
+ * Where a subject sits: its page or layout, or the files, the languages or the brand (the Voice
24
+ * and memory), which belong to none.
24
25
  */
25
26
  function ownerName(owner, entity) {
26
27
  if (entity === "locale") return "Languages";
27
- if (entity === "memory") return "Memory";
28
+ if (entity === "memory" || entity === "voiceAxis") return "Brand";
28
29
  if (!owner) return entity === "file" ? "Files" : "Elsewhere";
29
30
  if (owner.kind === "layout") return `Layout ${owner.name}`;
30
31
  if (owner.kind === "syncedBlock") return `Synced block ${owner.title}`;
@@ -219,44 +220,57 @@ const MEMORY_CHANGE_LABELS = {
219
220
  changed: "Changed",
220
221
  deleted: "Deleted"
221
222
  };
223
+ /** A Voice Axis the draft moves, as it reads: "Humor: Earnest → Light". */
224
+ function voiceLine({ axis, before, after }) {
225
+ const stepName = (key) => voiceStep(axis, key).name;
226
+ return `${voiceAxis(axis).name}: ${stepName(before)} → ${stepName(after)}`;
227
+ }
222
228
  /**
223
- * The memories the draft adds, changes and deletes, each with its text, and Live's before a
224
- * change: what Camox's agent will remember once it's published. Nothing when it changes none.
229
+ * What publishing the draft changes in the brand: each Voice Axis it moves, from Live's step to the
230
+ * draft's, then the memories it adds, changes and deletes, each with its text, and Live's before a
231
+ * change. Nothing when it changes neither.
225
232
  */
226
- function MemoryChanges(t0) {
227
- const $ = c(5);
228
- const { changes } = t0;
229
- if (changes.length === 0) return null;
233
+ function BrandChanges(t0) {
234
+ const $ = c(8);
235
+ const { voice, changes } = t0;
236
+ if (voice.length === 0 && changes.length === 0) return null;
230
237
  let t1;
231
238
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
232
239
  t1 = /* @__PURE__ */ jsx("h3", {
233
240
  className: "text-sm font-medium",
234
- children: "Memory"
241
+ children: "Brand"
235
242
  });
236
243
  $[0] = t1;
237
244
  } else t1 = $[0];
238
245
  let t2;
239
- if ($[1] !== changes) {
240
- t2 = changes.map(_temp4);
241
- $[1] = changes;
246
+ if ($[1] !== voice) {
247
+ t2 = voice.map(_temp4);
248
+ $[1] = voice;
242
249
  $[2] = t2;
243
250
  } else t2 = $[2];
244
251
  let t3;
245
- if ($[3] !== t2) {
246
- t3 = /* @__PURE__ */ jsxs("section", {
247
- "data-memory-changes": true,
252
+ if ($[3] !== changes) {
253
+ t3 = changes.map(_temp5);
254
+ $[3] = changes;
255
+ $[4] = t3;
256
+ } else t3 = $[4];
257
+ let t4;
258
+ if ($[5] !== t2 || $[6] !== t3) {
259
+ t4 = /* @__PURE__ */ jsxs("section", {
260
+ "data-brand-changes": true,
248
261
  className: "flex flex-col gap-2",
249
- children: [t1, /* @__PURE__ */ jsx("ul", {
262
+ children: [t1, /* @__PURE__ */ jsxs("ul", {
250
263
  className: "flex flex-col gap-2",
251
- children: t2
264
+ children: [t2, t3]
252
265
  })]
253
266
  });
254
- $[3] = t2;
255
- $[4] = t3;
256
- } else t3 = $[4];
257
- return t3;
267
+ $[5] = t2;
268
+ $[6] = t3;
269
+ $[7] = t4;
270
+ } else t4 = $[7];
271
+ return t4;
258
272
  }
259
- function _temp4(memory) {
273
+ function _temp5(memory) {
260
274
  return /* @__PURE__ */ jsxs("li", {
261
275
  className: "flex flex-col gap-0.5 rounded-lg border p-3 text-sm",
262
276
  children: [
@@ -275,6 +289,12 @@ function _temp4(memory) {
275
289
  ]
276
290
  }, memory.id);
277
291
  }
292
+ function _temp4(change) {
293
+ return /* @__PURE__ */ jsx("li", {
294
+ className: "rounded-lg border p-3 text-sm",
295
+ children: /* @__PURE__ */ jsx("p", { children: voiceLine(change) })
296
+ }, change.axis);
297
+ }
278
298
  /**
279
299
  * The draft's overview: the bullets AI wrote about its changes, in full, saying it's updating
280
300
  * while they describe an older version of the draft. While
@@ -290,7 +310,7 @@ function DraftOverview(t0) {
290
310
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
291
311
  t1 = {
292
312
  ...draftMutations.retryOverview(),
293
- onError: _temp5
313
+ onError: _temp6
294
314
  };
295
315
  $[0] = t1;
296
316
  } else t1 = $[0];
@@ -311,7 +331,7 @@ function DraftOverview(t0) {
311
331
  if (overview.status === "ready") {
312
332
  let t2;
313
333
  if ($[3] !== overview.bullets) {
314
- t2 = overview.bullets.map(_temp6);
334
+ t2 = overview.bullets.map(_temp7);
315
335
  $[3] = overview.bullets;
316
336
  $[4] = t2;
317
337
  } else t2 = $[4];
@@ -352,7 +372,7 @@ function DraftOverview(t0) {
352
372
  if (overview.status === "failed") {
353
373
  let t2;
354
374
  if ($[12] !== changes) {
355
- t2 = new Set(changes.map(_temp7));
375
+ t2 = new Set(changes.map(_temp8));
356
376
  $[12] = changes;
357
377
  $[13] = t2;
358
378
  } else t2 = $[13];
@@ -455,13 +475,13 @@ function DraftOverview(t0) {
455
475
  } else t2 = $[34];
456
476
  return t2;
457
477
  }
458
- function _temp7(change) {
478
+ function _temp8(change) {
459
479
  return ownerName(change.owner, change.entity);
460
480
  }
461
- function _temp6(bullet, index) {
481
+ function _temp7(bullet, index) {
462
482
  return /* @__PURE__ */ jsx("li", { children: bullet }, index);
463
483
  }
464
- function _temp5(error) {
484
+ function _temp6(error) {
465
485
  return toast.error(error.message || "Could not summarize the draft");
466
486
  }
467
487
  /**
@@ -569,8 +589,11 @@ function DraftReview(t0) {
569
589
  showInCanvas(target);
570
590
  }
571
591
  }),
572
- lines.map(_temp8),
573
- /* @__PURE__ */ jsx(MemoryChanges, { changes: data.memoryChanges })
592
+ lines.map(_temp9),
593
+ /* @__PURE__ */ jsx(BrandChanges, {
594
+ voice: data.voiceChanges,
595
+ changes: data.memoryChanges
596
+ })
574
597
  ]
575
598
  }) : /* @__PURE__ */ jsx("div", {
576
599
  className: cn("flex items-center justify-center", REVIEW_BODY_HEIGHT),
@@ -646,7 +669,7 @@ function DraftReview(t0) {
646
669
  } else t16 = $[50];
647
670
  return t16;
648
671
  }
649
- function _temp8(line) {
672
+ function _temp9(line) {
650
673
  return /* @__PURE__ */ jsx("p", {
651
674
  className: "text-sm text-amber-700 dark:text-amber-400",
652
675
  "data-review-line": true,