camox 0.48.0 → 0.52.1

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.
Files changed (127) hide show
  1. package/dist/core/createApp.d.ts +1 -0
  2. package/dist/core/createApp.js +1 -0
  3. package/dist/core/editing/contentEdits.js +78 -0
  4. package/dist/core/editing/createEditableBlock.js +277 -311
  5. package/dist/core/layoutContext.d.ts +1 -0
  6. package/dist/core/lib/contentType.js +2 -2
  7. package/dist/core/recordItem.js +3 -3
  8. package/dist/features/canvas/CamoxCanvas.js +15 -15
  9. package/dist/features/canvas/CanvasLoadingScreen.js +15 -11
  10. package/dist/features/canvas/CanvasPageFrame.js +81 -87
  11. package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -1
  12. package/dist/features/canvas/DerivedPagePathInput.js +12 -12
  13. package/dist/features/canvas/canvasOverlayGeometry.js +1 -1
  14. package/dist/features/canvas/canvasStore.js +2 -2
  15. package/dist/features/canvas/sidebar/CanvasInspector.js +1 -1
  16. package/dist/features/canvas/sidebar/CuratedPageInspector.js +1 -1
  17. package/dist/features/canvas/sidebar/LayoutPageBlocks.js +23 -31
  18. package/dist/features/canvas/useCanvasCamera.js +1 -1
  19. package/dist/features/canvas/useDiscoveredPreviewPaths.js +16 -9
  20. package/dist/features/content/ContentAssets.js +84 -88
  21. package/dist/features/page/CuratedPageContent.js +1 -1
  22. package/dist/features/preview/CamoxPreview.d.ts +8 -4
  23. package/dist/features/preview/CamoxPreview.js +258 -443
  24. package/dist/features/preview/EditablePageContent.js +244 -2
  25. package/dist/features/preview/EditablePageExperience.js +19 -13
  26. package/dist/features/preview/components/AddBlockSheet.js +55 -15
  27. package/dist/features/preview/components/BlockActionsPopover.js +23 -51
  28. package/dist/features/preview/components/BlockPeek.js +66 -0
  29. package/dist/features/preview/components/BlockThumbnail.js +134 -119
  30. package/dist/features/preview/components/CanvasPreview.js +1 -1
  31. package/dist/features/preview/components/CreatePageModal.js +150 -156
  32. package/dist/features/preview/components/FieldToolbar.js +1 -1
  33. package/dist/features/preview/components/Frame.js +27 -4
  34. package/dist/features/preview/components/MobilePreviewDrawer.js +6 -9
  35. package/dist/features/preview/components/PageInfo.js +161 -126
  36. package/dist/features/preview/components/PagePicker.js +2 -2
  37. package/dist/features/preview/components/PageTree.js +174 -190
  38. package/dist/features/preview/components/PreviewPanel.js +13 -67
  39. package/dist/features/preview/components/PreviewToolbar.js +1 -1
  40. package/dist/features/preview/components/ReferenceFieldEditor.js +4 -4
  41. package/dist/features/preview/components/ReferenceListFieldEditor.js +4 -4
  42. package/dist/features/preview/components/RemovedBlockPlaceholder.js +37 -70
  43. package/dist/features/preview/components/RepeatableItemsList.js +1 -1
  44. package/dist/features/preview/components/SelectionEditor.js +248 -256
  45. package/dist/features/preview/components/StudioEditingFallback.js +22 -26
  46. package/dist/features/preview/components/useFieldWriter.js +19 -19
  47. package/dist/features/preview/components/useRecordView.js +105 -147
  48. package/dist/features/preview/components/useRepeatableItemActions.js +0 -2
  49. package/dist/features/preview/pageRecord.js +30 -24
  50. package/dist/features/preview/previewConstants.js +2 -8
  51. package/dist/features/preview/previewStore.js +2 -0
  52. package/dist/features/preview/studioNotice.js +20 -0
  53. package/dist/features/preview/usePreviewViewportActions.js +1 -1
  54. package/dist/features/provider/AuthenticatedCamoxProvider.js +47 -31
  55. package/dist/features/provider/components/CommandPalette.js +2 -5
  56. package/dist/features/provider/signInShortcut.js +1 -2
  57. package/dist/features/provider/useAdminShortcuts.js +47 -53
  58. package/dist/features/renderer/RendererApp.js +542 -0
  59. package/dist/features/renderer/RendererFrames.js +450 -0
  60. package/dist/features/renderer/definitionAnswers.js +26 -0
  61. package/dist/features/renderer/protocol.js +35 -0
  62. package/dist/features/renderer/rendererHost.js +249 -0
  63. package/dist/features/renderer/studioConnection.js +186 -0
  64. package/dist/features/routes/pageRuntime.d.ts +2 -1
  65. package/dist/features/routes/pageRuntime.js +34 -22
  66. package/dist/features/runtime/RuntimeChrome.js +2 -5
  67. package/dist/features/runtime/assetPrefix.js +14 -0
  68. package/dist/features/runtime/breadcrumbs.js +1 -1
  69. package/dist/features/runtime/editingFallback.js +4 -8
  70. package/dist/features/runtime/livePages.js +1 -1
  71. package/dist/features/runtime/pageApp.js +57 -83
  72. package/dist/features/runtime/pageClient.js +1 -1
  73. package/dist/features/runtime/pageNavigation.js +3 -2
  74. package/dist/features/runtime/publicCache.js +95 -0
  75. package/dist/features/runtime/publishingDraft.js +23 -0
  76. package/dist/features/runtime/rendererClient.d.ts +8 -0
  77. package/dist/features/runtime/rendererClient.js +77 -0
  78. package/dist/features/runtime/runtime.d.ts +22 -3
  79. package/dist/features/runtime/runtime.js +209 -96
  80. package/dist/features/runtime/runtimeRoutes.d.ts +2 -0
  81. package/dist/features/runtime/runtimeRoutes.js +2 -0
  82. package/dist/features/runtime/worker.d.ts +14 -1
  83. package/dist/features/runtime/worker.js +34 -4
  84. package/dist/features/settings/AnalyticsSettings.js +622 -0
  85. package/dist/features/settings/CamoxSettings.js +95 -0
  86. package/dist/features/settings/FaviconSettings.js +254 -0
  87. package/dist/features/settings/ProjectNameSettings.js +145 -0
  88. package/dist/features/settings/SettingsPart.js +73 -0
  89. package/dist/features/settings/SocialProfilesSettings.js +245 -0
  90. package/dist/features/settings/useProjectMutation.js +61 -0
  91. package/dist/features/studio/FollowAgentProvider.js +10 -10
  92. package/dist/features/studio/components/DraftsControl.js +136 -131
  93. package/dist/features/studio/components/LocalePicker.js +178 -174
  94. package/dist/features/studio/components/Navbar.js +107 -66
  95. package/dist/features/studio/components/ProjectMenu.js +119 -171
  96. package/dist/features/studio/components/ReviewDraftSheet.js +1151 -991
  97. package/dist/features/studio/components/ThreadMessages.js +100 -65
  98. package/dist/features/studio/components/UserButton.js +2 -2
  99. package/dist/features/studio/routes.js +3 -1
  100. package/dist/features/studio/showInCanvas.js +129 -0
  101. package/dist/features/vite/definitionsSync.js +5 -6
  102. package/dist/features/vite/hostedChecks.js +127 -0
  103. package/dist/features/vite/runtimeDev.js +58 -17
  104. package/dist/features/vite/staticAssetHeaders.js +52 -0
  105. package/dist/features/vite/vite.d.ts +1 -1
  106. package/dist/features/vite/vite.js +49 -9
  107. package/dist/hooks/use-page-destinations.js +10 -10
  108. package/dist/lib/api-client-server.d.ts +1 -1
  109. package/dist/lib/api-client.d.ts +2 -1
  110. package/dist/lib/draft-scope.d.ts +1 -0
  111. package/dist/lib/locale-path.d.ts +3 -11
  112. package/dist/lib/locale-path.js +3 -27
  113. package/dist/lib/queries.js +7 -1
  114. package/dist/lib/revisions.js +20 -0
  115. package/dist/lib/shortcuts.js +29 -0
  116. package/dist/lib/studio-definitions.js +160 -0
  117. package/dist/lib/studio-reads.d.ts +1 -0
  118. package/dist/lib/studio-reads.js +65 -21
  119. package/dist/lib/use-project-room.js +16 -10
  120. package/dist/lib/utils.js +1 -104
  121. package/dist/package.js +1 -1
  122. package/dist/studio.css +1 -1
  123. package/package.json +9 -4
  124. package/skills/camox/SKILL.md +4 -0
  125. package/skills/camox/references/artifacts.md +1 -1
  126. package/dist/features/studio/components/FaviconDialog.js +0 -318
  127. package/dist/features/studio/components/SocialProfilesDialog.js +0 -342
@@ -2,27 +2,33 @@ import { useDraftScope } from "../../../lib/draft-scope.js";
2
2
  import { reads, useReadQuery } from "../../../lib/studio-reads.js";
3
3
  import { cn } from "../../../lib/utils.js";
4
4
  import { draftMutations } from "../../../lib/queries.js";
5
+ import { previewStore } from "../../preview/previewStore.js";
5
6
  import { localeLabel } from "../localeOptions.js";
6
7
  import { draftLabel, plural, timeAgo } from "../draftLabel.js";
7
8
  import { useRenameDraft } from "./RenameDraftDialog.js";
9
+ import { useShowInCanvas } from "../showInCanvas.js";
8
10
  import { c } from "react/compiler-runtime";
9
11
  import * as React from "react";
10
- import { CONFLICTS_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR } from "@camox/api-contract/drafts";
12
+ import { CONFLICTS_CHANGED_ERROR, REVISION_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR } from "@camox/api-contract/drafts";
11
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
14
  import { useMutation } from "@tanstack/react-query";
13
15
  import { Button } from "@camox/ui/button";
14
16
  import { Sheet, SheetContent, SheetDescription, SheetTitle } from "@camox/ui/sheet";
15
- import { Blocks, ChevronRight, CircleCheck, Database, FileText, History, Image, Info, Languages, OctagonX, PanelsTopLeft, Shapes, Trash2, TriangleAlert, Unlink } from "lucide-react";
17
+ import { CircleCheck, OctagonX, Replace, Trash2, TriangleAlert, Unlink } from "lucide-react";
16
18
  import { toast } from "@camox/ui/toaster";
19
+ import { Skeleton } from "@camox/ui/skeleton";
17
20
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
18
21
  import { Spinner } from "@camox/ui/spinner";
19
- import { Accordion, AccordionHeader, AccordionItem, AccordionPanel, AccordionTrigger } from "@camox/ui/accordion";
20
22
 
21
23
  //#region src/features/studio/components/ReviewDraftSheet.tsx
22
24
  const dateFormat = new Intl.DateTimeFormat(void 0, {
23
25
  month: "short",
24
26
  day: "numeric"
25
27
  });
28
+ const listFormat = new Intl.ListFormat("en", {
29
+ style: "long",
30
+ type: "conjunction"
31
+ });
26
32
  /** Where a subject sits: its page or layout, or the files, which belong to neither. */
27
33
  function ownerName(owner, entity) {
28
34
  if (!owner) return entity === "file" ? "Files" : "Elsewhere";
@@ -39,75 +45,52 @@ function problemPlace(problem) {
39
45
  if (!problem.owner && problem.entity !== "file") return null;
40
46
  return ownerName(problem.owner, problem.entity);
41
47
  }
42
- const groupKind = ({ owner, entity }) => {
43
- if (owner) return owner.kind;
44
- if (entity === "file") return "files";
45
- return entity === "locale" ? "languages" : "elsewhere";
46
- };
47
- /** Where a change is listed: its page or layout, the files, or the languages for a locale. */
48
- const placeOf = (change) => change.entity === "locale" ? "Languages" : ownerName(change.owner, change.entity);
49
- /** What a change is listed as: a locale added or removed by its name, anything else its label. */
50
- const changeLabel = (change) => change.entity === "locale" ? localeLabel(change.label) : change.label;
51
- const GROUPS = {
52
- page: {
53
- rank: 0,
54
- icon: FileText
55
- },
56
- layout: {
57
- rank: 1,
58
- icon: PanelsTopLeft
59
- },
60
- syncedBlock: {
61
- rank: 2,
62
- icon: Blocks
63
- },
64
- collection: {
65
- rank: 3,
66
- icon: Database
67
- },
68
- files: {
69
- rank: 4,
70
- icon: Image
71
- },
72
- languages: {
73
- rank: 5,
74
- icon: Languages
75
- },
76
- elsewhere: {
77
- rank: 6,
78
- icon: Shapes
79
- }
80
- };
81
- const CHANGES = {
82
- created: {
83
- sign: "+",
84
- className: "text-green-600 dark:text-green-400"
85
- },
86
- changed: {
87
- sign: "~",
88
- className: "text-muted-foreground"
89
- },
90
- deleted: {
91
- sign: "−",
92
- className: "text-destructive"
48
+ /**
49
+ * Where a conflict or lost change sits: its page, layout or collection, and its locale when the
50
+ * draft's change is in another than the default.
51
+ */
52
+ function placeInLocale(subject, defaultLocale) {
53
+ const place = ownerName(subject.owner, subject.entity);
54
+ if (!subject.locale || subject.locale === defaultLocale) return place;
55
+ return `${place} · ${localeLabel(subject.locale)}`;
56
+ }
57
+ /** Where in the Canvas a blocker is, or null when it sits on no page, like a definition. */
58
+ function blockerTarget(problem) {
59
+ if (problem.owner?.kind !== "page") return null;
60
+ return {
61
+ pageId: problem.owner.id,
62
+ locale: problem.locale,
63
+ blockId: problem.blockId,
64
+ itemId: problem.entity === "repeatableItem" ? problem.id : null,
65
+ field: problem.blockId && problem.field ? {
66
+ name: problem.field,
67
+ kind: problem.fieldKind
68
+ } : null
69
+ };
70
+ }
71
+ const isImage = (problem) => problem.fieldKind === "Image" || problem.fieldKind === "ImageList";
72
+ /** What a blocker's action does, named by the fix where it's obvious. */
73
+ function blockerActionLabel(problem) {
74
+ switch (problem.code) {
75
+ case "emptyRequiredFile": return isImage(problem) ? "Choose an image" : "Choose a file";
76
+ case "missingFile":
77
+ case "unacceptedFileType": return isImage(problem) ? "Choose another image" : "Choose another file";
78
+ case "emptyRequiredReference": return "Choose a record";
79
+ case "danglingReference": return "Choose another record";
80
+ case "danglingPageLink": return "Fix the link";
81
+ case "duplicatePath": return "Fix the path";
82
+ case "missingMetaTitle": return "Write a meta title";
83
+ default: return "Show in Canvas";
93
84
  }
94
- };
85
+ }
95
86
  const TONES = {
96
87
  danger: {
97
88
  card: "border-destructive/30 bg-destructive/5",
98
- icon: "bg-destructive/10 text-destructive"
89
+ icon: "text-destructive"
99
90
  },
100
91
  warning: {
101
92
  card: "border-amber-500/30 bg-amber-500/5",
102
- icon: "bg-amber-500/15 text-amber-600 dark:text-amber-400"
103
- },
104
- success: {
105
- card: "border-green-500/30 bg-green-500/5",
106
- icon: "bg-green-500/15 text-green-600 dark:text-green-400"
107
- },
108
- neutral: {
109
- card: "bg-muted/40",
110
- icon: "bg-muted text-muted-foreground"
93
+ icon: "text-amber-600 dark:text-amber-400"
111
94
  }
112
95
  };
113
96
  /** A conflict as Live's version of an entity in a locale, to tell a new one from those shown. */
@@ -117,697 +100,868 @@ const conflictKey = (conflict) => JSON.stringify([
117
100
  conflict.locale,
118
101
  conflict.liveVersion
119
102
  ]);
120
- /** Who made Live's version of a conflicting entity: a member, a release, or nobody known. */
121
- function changedBy(conflict) {
122
- if (conflict.release) return " by a release";
123
- if (conflict.publishedBy) return ` by ${conflict.publishedBy.name}`;
124
- return "";
125
- }
126
103
  const LOST_REASONS = {
127
- parentGone: "What it belongs to is gone from Live and from this draft, so it's dropped.",
128
- writtenAfterDeletion: "This draft deletes what it was added to, so it goes too."
104
+ parentGone: "What it belongs to is gone from Live and from this draft, so publishing drops this change.",
105
+ writtenAfterDeletion: "This draft deletes what it was added to, so publishing deletes it too."
129
106
  };
130
- /** The verdict at the top of the review: can this draft go to Live, and is there a catch? */
131
- function Verdict(t0) {
132
- const $ = c(23);
133
- const { preview } = t0;
134
- const { blockers, conflicts, lost } = preview;
135
- const catches = conflicts.length + lost.length;
136
- let t1;
137
- if ($[0] !== blockers.length || $[1] !== catches) {
138
- t1 = blockers.length ? [
139
- "danger",
140
- OctagonX,
141
- "Not ready to publish",
142
- `Fix ${blockers.length === 1 ? "this problem" : `these ${blockers.length} problems`} in the draft first.`
143
- ] : catches ? [
144
- "warning",
145
- TriangleAlert,
146
- `Ready, with ${plural(catches, "thing")} to know`,
147
- "Publishing replaces Live's version wherever the two differ."
148
- ] : [
149
- "success",
150
- CircleCheck,
151
- "Ready to publish",
152
- "Nothing on Live changed since this draft did."
153
- ];
154
- $[0] = blockers.length;
155
- $[1] = catches;
156
- $[2] = t1;
157
- } else t1 = $[2];
158
- const [tone, Icon, title, description] = t1;
159
- const t2 = TONES[tone];
160
- let t3;
161
- if ($[3] !== t2.card) {
162
- t3 = cn("flex gap-3 rounded-xl border p-4", t2.card);
163
- $[3] = t2.card;
164
- $[4] = t3;
165
- } else t3 = $[4];
166
- const t4 = TONES[tone];
167
- let t5;
168
- if ($[5] !== t4.icon) {
169
- t5 = cn("flex size-9 shrink-0 items-center justify-center rounded-lg", t4.icon);
170
- $[5] = t4.icon;
171
- $[6] = t5;
172
- } else t5 = $[6];
173
- let t6;
174
- if ($[7] !== Icon) {
175
- t6 = /* @__PURE__ */ jsx(Icon, { className: "size-5" });
176
- $[7] = Icon;
177
- $[8] = t6;
178
- } else t6 = $[8];
179
- let t7;
180
- if ($[9] !== t5 || $[10] !== t6) {
181
- t7 = /* @__PURE__ */ jsx("span", {
182
- className: t5,
183
- children: t6
184
- });
185
- $[9] = t5;
186
- $[10] = t6;
187
- $[11] = t7;
188
- } else t7 = $[11];
189
- let t8;
190
- if ($[12] !== title) {
191
- t8 = /* @__PURE__ */ jsx("p", {
192
- className: "font-medium",
193
- children: title
194
- });
195
- $[12] = title;
196
- $[13] = t8;
197
- } else t8 = $[13];
198
- let t9;
199
- if ($[14] !== description) {
200
- t9 = /* @__PURE__ */ jsx("p", {
201
- className: "text-foreground/70 text-sm",
202
- children: description
203
- });
204
- $[14] = description;
205
- $[15] = t9;
206
- } else t9 = $[15];
207
- let t10;
208
- if ($[16] !== t8 || $[17] !== t9) {
209
- t10 = /* @__PURE__ */ jsxs("div", {
210
- className: "flex flex-col gap-0.5",
211
- children: [t8, t9]
212
- });
213
- $[16] = t8;
214
- $[17] = t9;
215
- $[18] = t10;
216
- } else t10 = $[18];
217
- let t11;
218
- if ($[19] !== t10 || $[20] !== t3 || $[21] !== t7) {
219
- t11 = /* @__PURE__ */ jsxs("div", {
220
- className: t3,
221
- children: [t7, t10]
222
- });
223
- $[19] = t10;
224
- $[20] = t3;
225
- $[21] = t7;
226
- $[22] = t11;
227
- } else t11 = $[22];
228
- return t11;
229
- }
230
- const INSIGHT_LIST = "bg-background divide-y overflow-hidden rounded-lg border";
231
- function Insight(t0) {
232
- const $ = c(23);
233
- const { tone, icon: Icon, title, hint, count, children } = t0;
107
+ /**
108
+ * A card for something to know before publishing: blockers in red; removals, conflicts and lost
109
+ * changes in amber.
110
+ */
111
+ function Card(t0) {
112
+ const $ = c(22);
113
+ const { tone, icon: Icon, title, action, children } = t0;
234
114
  const t1 = TONES[tone];
235
115
  let t2;
236
- if ($[0] !== t1.icon) {
237
- t2 = cn("flex size-6 shrink-0 items-center justify-center rounded-md", t1.icon);
238
- $[0] = t1.icon;
116
+ if ($[0] !== t1.card) {
117
+ t2 = cn("flex items-start gap-2 rounded-lg border p-3", t1.card);
118
+ $[0] = t1.card;
239
119
  $[1] = t2;
240
120
  } else t2 = $[1];
241
- let t3;
242
- if ($[2] !== Icon) {
243
- t3 = /* @__PURE__ */ jsx(Icon, { className: "size-3.5" });
244
- $[2] = Icon;
245
- $[3] = t3;
246
- } else t3 = $[3];
121
+ const t3 = TONES[tone];
247
122
  let t4;
248
- if ($[4] !== t2 || $[5] !== t3) {
249
- t4 = /* @__PURE__ */ jsx("span", {
250
- className: t2,
251
- children: t3
252
- });
253
- $[4] = t2;
254
- $[5] = t3;
255
- $[6] = t4;
256
- } else t4 = $[6];
123
+ if ($[2] !== t3.icon) {
124
+ t4 = cn("mt-0.5 size-4 shrink-0", t3.icon);
125
+ $[2] = t3.icon;
126
+ $[3] = t4;
127
+ } else t4 = $[3];
257
128
  let t5;
129
+ if ($[4] !== Icon || $[5] !== t4) {
130
+ t5 = /* @__PURE__ */ jsx(Icon, { className: t4 });
131
+ $[4] = Icon;
132
+ $[5] = t4;
133
+ $[6] = t5;
134
+ } else t5 = $[6];
135
+ let t6;
258
136
  if ($[7] !== title) {
259
- t5 = /* @__PURE__ */ jsx("h3", {
137
+ t6 = /* @__PURE__ */ jsx("p", {
260
138
  className: "text-sm font-medium",
139
+ "data-card-title": true,
261
140
  children: title
262
141
  });
263
142
  $[7] = title;
264
- $[8] = t5;
265
- } else t5 = $[8];
266
- let t6;
267
- if ($[9] !== count) {
268
- t6 = /* @__PURE__ */ jsx("span", {
269
- className: "text-muted-foreground bg-muted rounded-full px-1.5 text-xs tabular-nums",
270
- children: count
271
- });
272
- $[9] = count;
273
- $[10] = t6;
274
- } else t6 = $[10];
143
+ $[8] = t6;
144
+ } else t6 = $[8];
275
145
  let t7;
276
- if ($[11] !== t4 || $[12] !== t5 || $[13] !== t6) {
277
- t7 = /* @__PURE__ */ jsxs("div", {
278
- className: "flex items-center gap-2",
279
- children: [
280
- t4,
281
- t5,
282
- t6
283
- ]
146
+ if ($[9] !== children) {
147
+ t7 = /* @__PURE__ */ jsx("div", {
148
+ className: "text-muted-foreground text-sm",
149
+ children
284
150
  });
285
- $[11] = t4;
286
- $[12] = t5;
287
- $[13] = t6;
288
- $[14] = t7;
289
- } else t7 = $[14];
151
+ $[9] = children;
152
+ $[10] = t7;
153
+ } else t7 = $[10];
290
154
  let t8;
291
- if ($[15] !== hint) {
292
- t8 = /* @__PURE__ */ jsx("p", {
293
- className: "text-muted-foreground text-xs",
294
- children: hint
155
+ if ($[11] !== action) {
156
+ t8 = action && /* @__PURE__ */ jsx("div", {
157
+ className: "pt-1",
158
+ children: action
295
159
  });
296
- $[15] = hint;
297
- $[16] = t8;
298
- } else t8 = $[16];
160
+ $[11] = action;
161
+ $[12] = t8;
162
+ } else t8 = $[12];
299
163
  let t9;
300
- if ($[17] !== children) {
301
- t9 = /* @__PURE__ */ jsx("ul", {
302
- className: INSIGHT_LIST,
303
- children
304
- });
305
- $[17] = children;
306
- $[18] = t9;
307
- } else t9 = $[18];
308
- let t10;
309
- if ($[19] !== t7 || $[20] !== t8 || $[21] !== t9) {
310
- t10 = /* @__PURE__ */ jsxs("section", {
311
- className: "flex flex-col gap-2",
164
+ if ($[13] !== t6 || $[14] !== t7 || $[15] !== t8) {
165
+ t9 = /* @__PURE__ */ jsxs("div", {
166
+ className: "flex min-w-0 flex-1 flex-col gap-1",
312
167
  children: [
168
+ t6,
313
169
  t7,
314
- t8,
315
- t9
170
+ t8
316
171
  ]
317
172
  });
318
- $[19] = t7;
319
- $[20] = t8;
320
- $[21] = t9;
321
- $[22] = t10;
322
- } else t10 = $[22];
323
- return t10;
324
- }
325
- function InsightItem(t0) {
326
- const $ = c(12);
327
- const { label, place, detail } = t0;
328
- let t1;
329
- if ($[0] !== label) {
330
- t1 = /* @__PURE__ */ jsx("span", {
331
- className: "truncate text-sm font-medium",
332
- children: label
333
- });
334
- $[0] = label;
335
- $[1] = t1;
336
- } else t1 = $[1];
337
- let t2;
338
- if ($[2] !== place) {
339
- t2 = place && /* @__PURE__ */ jsx("span", {
340
- className: "text-muted-foreground truncate text-xs",
341
- children: place
342
- });
343
- $[2] = place;
344
- $[3] = t2;
345
- } else t2 = $[3];
346
- let t3;
347
- if ($[4] !== t1 || $[5] !== t2) {
348
- t3 = /* @__PURE__ */ jsxs("div", {
349
- className: "flex min-w-0 items-baseline gap-2",
350
- children: [t1, t2]
351
- });
352
- $[4] = t1;
353
- $[5] = t2;
354
- $[6] = t3;
355
- } else t3 = $[6];
356
- let t4;
357
- if ($[7] !== detail) {
358
- t4 = /* @__PURE__ */ jsx("p", {
359
- className: "text-muted-foreground text-sm",
360
- children: detail
361
- });
362
- $[7] = detail;
363
- $[8] = t4;
364
- } else t4 = $[8];
365
- let t5;
366
- if ($[9] !== t3 || $[10] !== t4) {
367
- t5 = /* @__PURE__ */ jsxs("li", {
368
- className: "flex flex-col gap-0.5 px-3 py-2.5",
369
- children: [t3, t4]
173
+ $[13] = t6;
174
+ $[14] = t7;
175
+ $[15] = t8;
176
+ $[16] = t9;
177
+ } else t9 = $[16];
178
+ let t10;
179
+ if ($[17] !== t2 || $[18] !== t5 || $[19] !== t9 || $[20] !== tone) {
180
+ t10 = /* @__PURE__ */ jsxs("li", {
181
+ className: t2,
182
+ "data-card": tone,
183
+ children: [t5, t9]
370
184
  });
371
- $[9] = t3;
372
- $[10] = t4;
373
- $[11] = t5;
374
- } else t5 = $[11];
375
- return t5;
185
+ $[17] = t2;
186
+ $[18] = t5;
187
+ $[19] = t9;
188
+ $[20] = tone;
189
+ $[21] = t10;
190
+ } else t10 = $[21];
191
+ return t10;
376
192
  }
377
- /** From how many problems sharing a message they read as one item, naming each subject. */
193
+ /** From how many problems sharing a message they fold into one card, naming each subject. */
378
194
  const SHARED_MESSAGE_MIN = 3;
379
195
  /**
380
- * Problems, with those sharing a message folded into one item: a draft can hold dozens of
381
- * definitions to release, and the message is the same for each.
196
+ * Warnings the review shows: what the draft's code removes while Live content uses it, which is
197
+ * about the draft. Other warnings are about problems already on Live, and stay out (ADR 0009).
382
198
  */
383
- function ProblemItems({ problems }) {
199
+ const isShownWarning = (problem) => problem.code === "removedInUse";
200
+ /**
201
+ * One card per problem, saying what's wrong and where. Problems sharing a message fold into one
202
+ * card naming each: a development draft can hold dozens of definitions to release, and a removed
203
+ * block can sit on dozens of pages, with the same message for each. A problem on a page has an
204
+ * action that shows it in the Canvas; a blocker in the draft's code, which only the agent fixes,
205
+ * one that opens the draft's thread.
206
+ */
207
+ function ProblemCards({ problems, tone, icon, onShow, onOpenThread }) {
384
208
  const byMessage = /* @__PURE__ */ new Map();
385
209
  for (const problem of problems) byMessage.set(problem.message, [...byMessage.get(problem.message) ?? [], problem]);
386
210
  return [...byMessage].flatMap(([message, shared]) => {
387
- if (shared.length < SHARED_MESSAGE_MIN) return shared.map((problem) => /* @__PURE__ */ jsx(InsightItem, {
388
- label: problem.label,
389
- place: problemPlace(problem),
390
- detail: problem.message
391
- }, `${problem.code}:${problem.id}:${problem.field}`));
392
- return [/* @__PURE__ */ jsxs("li", {
393
- className: "flex flex-col gap-2 px-3 py-2.5",
394
- children: [/* @__PURE__ */ jsx("p", {
395
- className: "text-sm font-medium",
396
- children: message
397
- }), /* @__PURE__ */ jsx("ul", {
398
- className: "flex flex-wrap gap-1",
211
+ if (shared.length < SHARED_MESSAGE_MIN) return shared.map((problem) => {
212
+ const place = problemPlace(problem);
213
+ const target = blockerTarget(problem);
214
+ return /* @__PURE__ */ jsx(Card, {
215
+ tone,
216
+ icon,
217
+ title: problem.message,
218
+ action: problem.entity === "code" ? /* @__PURE__ */ jsx(Button, {
219
+ variant: "outline",
220
+ size: "sm",
221
+ onClick: onOpenThread,
222
+ children: "Open the thread"
223
+ }) : target && /* @__PURE__ */ jsx(Button, {
224
+ variant: "outline",
225
+ size: "sm",
226
+ onClick: () => onShow(target),
227
+ children: blockerActionLabel(problem)
228
+ }),
229
+ children: place ? `${problem.label} · ${place}` : problem.label
230
+ }, `${problem.code}:${problem.id}:${problem.locale}:${problem.field}`);
231
+ });
232
+ return [/* @__PURE__ */ jsx(Card, {
233
+ tone,
234
+ icon,
235
+ title: message,
236
+ children: /* @__PURE__ */ jsx("ul", {
237
+ className: "flex flex-wrap gap-1 pt-0.5",
399
238
  children: shared.map((problem) => {
400
239
  const place = problemPlace(problem);
401
240
  return /* @__PURE__ */ jsxs("li", {
402
- className: "bg-muted text-muted-foreground rounded-md px-1.5 py-0.5 text-xs",
241
+ className: "bg-background rounded-md border px-1.5 py-0.5 text-xs",
403
242
  children: [/* @__PURE__ */ jsx("span", {
404
243
  className: "text-foreground",
405
244
  children: problem.label
406
245
  }), place && ` · ${place}`]
407
- }, `${problem.code}:${problem.id}:${problem.field}`);
246
+ }, `${problem.code}:${problem.id}:${problem.locale}:${problem.field}`);
408
247
  })
409
- })]
248
+ })
410
249
  }, `shared:${message}`)];
411
250
  });
412
251
  }
413
- /** What publishing will do, in the order ADR 0009 lists it. */
414
- function Insights(t0) {
415
- const $ = c(13);
416
- const { preview } = t0;
417
- const { blockers, conflicts, lost, warnings } = preview;
252
+ /** Who made Live's version of a conflict, as a sentence's subject: a member, a release, or none. */
253
+ function whoChanged(conflict) {
254
+ if (conflict.release) return "A release";
255
+ return conflict.publishedBy?.name ?? null;
256
+ }
257
+ /** Whose edit a conflict replaces, as its card's title: a member's, a release's, or nobody's. */
258
+ function conflictTitle(conflict) {
259
+ if (conflict.liveVersion === null) return `Brings back the ${conflict.label}`;
260
+ if (conflict.release) return `Replaces a release's change to the ${conflict.label}`;
261
+ if (conflict.publishedBy) return `Replaces ${conflict.publishedBy.name}'s edit to the ${conflict.label}`;
262
+ return `Replaces an edit to the ${conflict.label}`;
263
+ }
264
+ /** What publishing does to a conflict's entity, and when Live changed it. */
265
+ function conflictDetail(conflict, draftDeletes) {
266
+ const who = whoChanged(conflict);
267
+ const when = conflict.publishedAt ? ` on ${dateFormat.format(conflict.publishedAt)}` : "";
268
+ if (conflict.liveVersion === null) return `${who ? `${who} deleted it from Live${when}.` : `Live deleted it${when}.`} Publishing brings it back.`;
269
+ const changed = who ? `${who} changed it on Live${when}.` : `Live changed it${when}.`;
270
+ return draftDeletes ? `${changed} This draft deletes it, so publishing deletes it anyway.` : `${changed} Publishing replaces it with this draft's version.`;
271
+ }
272
+ /** Who made Live's version of a conflict and when, labelling Live's values: "On Live now · Ada, Oct 13". */
273
+ function liveValuesLabel(conflict) {
274
+ const made = [whoChanged(conflict), conflict.publishedAt ? dateFormat.format(conflict.publishedAt) : null].filter((part) => part !== null);
275
+ return made.length > 0 ? `On Live now · ${made.join(", ")}` : "On Live now";
276
+ }
277
+ /**
278
+ * The fields a conflict overwrites: Live's value crossed out, above the draft's, and how many
279
+ * more fields differ.
280
+ */
281
+ function ConflictFields(t0) {
282
+ const $ = c(12);
283
+ const { conflict } = t0;
284
+ if (conflict.fields.length === 0) return null;
418
285
  let t1;
419
- if ($[0] !== blockers) {
420
- t1 = blockers.length > 0 && /* @__PURE__ */ jsx("ul", {
421
- className: INSIGHT_LIST,
422
- children: /* @__PURE__ */ jsx(ProblemItems, { problems: blockers })
423
- });
424
- $[0] = blockers;
286
+ if ($[0] !== conflict) {
287
+ t1 = liveValuesLabel(conflict);
288
+ $[0] = conflict;
425
289
  $[1] = t1;
426
290
  } else t1 = $[1];
291
+ const liveLabel = t1;
427
292
  let t2;
428
- if ($[2] !== conflicts) {
429
- t2 = conflicts.length > 0 && /* @__PURE__ */ jsx(Insight, {
430
- tone: "warning",
431
- icon: History,
432
- title: "Changed on Live since this draft",
433
- hint: "This draft's version replaces Live's. Check nothing important gets overwritten.",
434
- count: conflicts.length,
435
- children: conflicts.map(_temp)
436
- });
437
- $[2] = conflicts;
438
- $[3] = t2;
439
- } else t2 = $[3];
293
+ if ($[2] !== conflict.fields || $[3] !== liveLabel) {
294
+ let t3;
295
+ if ($[5] !== liveLabel) {
296
+ t3 = (t4) => {
297
+ const { field, live, draft } = t4;
298
+ return /* @__PURE__ */ jsxs("div", {
299
+ className: "bg-background flex flex-col gap-1 rounded-md border p-2",
300
+ "data-conflict-field": true,
301
+ children: [
302
+ /* @__PURE__ */ jsx("p", {
303
+ className: "text-foreground text-xs font-medium",
304
+ "data-field-title": true,
305
+ children: field
306
+ }),
307
+ /* @__PURE__ */ jsxs("div", {
308
+ className: "flex flex-col",
309
+ children: [/* @__PURE__ */ jsx("span", {
310
+ className: "text-xs",
311
+ children: liveLabel
312
+ }), /* @__PURE__ */ jsx("del", {
313
+ className: "break-words",
314
+ "data-live-value": true,
315
+ children: live
316
+ })]
317
+ }),
318
+ /* @__PURE__ */ jsxs("div", {
319
+ className: "flex flex-col",
320
+ children: [/* @__PURE__ */ jsx("span", {
321
+ className: "text-xs",
322
+ children: "This draft"
323
+ }), /* @__PURE__ */ jsx("span", {
324
+ className: "text-foreground break-words",
325
+ "data-draft-value": true,
326
+ children: draft
327
+ })]
328
+ })
329
+ ]
330
+ }, field);
331
+ };
332
+ $[5] = liveLabel;
333
+ $[6] = t3;
334
+ } else t3 = $[6];
335
+ t2 = conflict.fields.map(t3);
336
+ $[2] = conflict.fields;
337
+ $[3] = liveLabel;
338
+ $[4] = t2;
339
+ } else t2 = $[4];
440
340
  let t3;
441
- if ($[4] !== lost) {
442
- t3 = lost.length > 0 && /* @__PURE__ */ jsx(Insight, {
443
- tone: "warning",
444
- icon: Unlink,
445
- title: "Changes that will be lost",
446
- hint: "These can't be kept, and can't be brought back after publishing.",
447
- count: lost.length,
448
- children: lost.map(_temp2)
341
+ if ($[7] !== conflict.moreFields) {
342
+ t3 = conflict.moreFields > 0 && /* @__PURE__ */ jsxs("p", {
343
+ className: "text-xs",
344
+ children: ["And ", plural(conflict.moreFields, "more field")]
449
345
  });
450
- $[4] = lost;
451
- $[5] = t3;
452
- } else t3 = $[5];
346
+ $[7] = conflict.moreFields;
347
+ $[8] = t3;
348
+ } else t3 = $[8];
453
349
  let t4;
454
- if ($[6] !== warnings) {
455
- t4 = warnings.length > 0 && /* @__PURE__ */ jsx(Insight, {
456
- tone: "neutral",
457
- icon: Info,
458
- title: "Already on Live",
459
- hint: "These don't block publishing, but are worth fixing.",
460
- count: warnings.length,
461
- children: /* @__PURE__ */ jsx(ProblemItems, { problems: warnings })
350
+ if ($[9] !== t2 || $[10] !== t3) {
351
+ t4 = /* @__PURE__ */ jsxs("div", {
352
+ className: "flex flex-col gap-2 pt-1",
353
+ children: [t2, t3]
462
354
  });
463
- $[6] = warnings;
464
- $[7] = t4;
465
- } else t4 = $[7];
466
- let t5;
467
- if ($[8] !== t1 || $[9] !== t2 || $[10] !== t3 || $[11] !== t4) {
468
- t5 = /* @__PURE__ */ jsxs(Fragment, { children: [
469
- t1,
470
- t2,
471
- t3,
472
- t4
473
- ] });
474
- $[8] = t1;
475
355
  $[9] = t2;
476
356
  $[10] = t3;
477
357
  $[11] = t4;
478
- $[12] = t5;
479
- } else t5 = $[12];
480
- return t5;
481
- }
482
- function _temp2(change) {
483
- return /* @__PURE__ */ jsx(InsightItem, {
484
- label: change.label,
485
- place: ownerName(change.owner, change.entity),
486
- detail: LOST_REASONS[change.reason]
487
- }, change.id);
358
+ } else t4 = $[11];
359
+ return t4;
488
360
  }
489
- function _temp(conflict) {
490
- return /* @__PURE__ */ jsx(InsightItem, {
491
- label: conflict.label,
492
- place: ownerName(conflict.owner, conflict.entity),
493
- detail: /* @__PURE__ */ jsxs(Fragment, { children: [
494
- conflict.liveVersion === null ? "Deleted" : "Changed",
495
- changedBy(conflict),
496
- conflict.publishedAt ? `, ${dateFormat.format(conflict.publishedAt)}` : ""
497
- ] })
498
- }, conflict.id);
361
+ /** Whose version of a conflict's entity Live holds, for its "Use … version instead" action. */
362
+ function liveVersionName(conflict) {
363
+ if (conflict.release) return "a release's";
364
+ if (conflict.publishedBy) return `${conflict.publishedBy.name}'s`;
365
+ return "Live's";
499
366
  }
500
- /** Changes grouped by where they're listed: pages first, then layouts, then collections. */
501
- function placesOf(changes) {
502
- const places = /* @__PURE__ */ new Map();
503
- const sorted = [...changes].sort((a, b) => GROUPS[groupKind(a)].rank - GROUPS[groupKind(b)].rank);
504
- for (const change of sorted) {
505
- const name = placeOf(change);
506
- const place = places.get(name) ?? {
507
- kind: groupKind(change),
508
- changes: []
367
+ /**
368
+ * Drops the draft's change to a conflict's entity, so the draft reads Live's version again, then
369
+ * reads the review again: the conflict is gone, and the preview has a new token.
370
+ */
371
+ function UseLiveVersionButton(t0) {
372
+ const $ = c(20);
373
+ const { projectId, conflict, onUsed } = t0;
374
+ let t1;
375
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
376
+ t1 = draftMutations.revertToLive();
377
+ $[0] = t1;
378
+ } else t1 = $[0];
379
+ let t2;
380
+ if ($[1] !== onUsed) {
381
+ t2 = (error) => {
382
+ toast.error(error.message || "Could not use Live's version");
383
+ onUsed();
509
384
  };
510
- place.changes.push(change);
511
- places.set(name, place);
512
- }
513
- return places;
385
+ $[1] = onUsed;
386
+ $[2] = t2;
387
+ } else t2 = $[2];
388
+ let t3;
389
+ if ($[3] !== onUsed || $[4] !== t2) {
390
+ t3 = {
391
+ ...t1,
392
+ onSuccess: onUsed,
393
+ onError: t2
394
+ };
395
+ $[3] = onUsed;
396
+ $[4] = t2;
397
+ $[5] = t3;
398
+ } else t3 = $[5];
399
+ const revert = useMutation(t3);
400
+ const t4 = revert.isPending;
401
+ let t5;
402
+ if ($[6] !== conflict.entity || $[7] !== conflict.id || $[8] !== projectId || $[9] !== revert) {
403
+ t5 = () => revert.mutate({
404
+ projectId,
405
+ entity: conflict.entity,
406
+ id: conflict.id
407
+ });
408
+ $[6] = conflict.entity;
409
+ $[7] = conflict.id;
410
+ $[8] = projectId;
411
+ $[9] = revert;
412
+ $[10] = t5;
413
+ } else t5 = $[10];
414
+ let t6;
415
+ if ($[11] !== revert.isPending) {
416
+ t6 = revert.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
417
+ $[11] = revert.isPending;
418
+ $[12] = t6;
419
+ } else t6 = $[12];
420
+ let t7;
421
+ if ($[13] !== conflict) {
422
+ t7 = liveVersionName(conflict);
423
+ $[13] = conflict;
424
+ $[14] = t7;
425
+ } else t7 = $[14];
426
+ let t8;
427
+ if ($[15] !== revert.isPending || $[16] !== t5 || $[17] !== t6 || $[18] !== t7) {
428
+ t8 = /* @__PURE__ */ jsxs(Button, {
429
+ variant: "outline",
430
+ size: "sm",
431
+ className: "mt-1",
432
+ disabled: t4,
433
+ onClick: t5,
434
+ children: [
435
+ t6,
436
+ "Use ",
437
+ t7,
438
+ " version instead"
439
+ ]
440
+ });
441
+ $[15] = revert.isPending;
442
+ $[16] = t5;
443
+ $[17] = t6;
444
+ $[18] = t7;
445
+ $[19] = t8;
446
+ } else t8 = $[19];
447
+ return t8;
514
448
  }
515
449
  /**
516
- * Changes grouped by locale, the default locale first, then what's stored once, like files,
517
- * under no locale. A draft changing only its default locale names no locale at all.
450
+ * Blockers first, then what the draft's code removes while Live content uses it, then conflicts,
451
+ * then lost changes: one card each, with no section heading.
518
452
  */
519
- function localesOf(changes, defaultLocale) {
520
- const tags = [...new Set(changes.flatMap((change) => change.locale ?? []))];
521
- if (defaultLocale ? tags.every((tag) => tag === defaultLocale) : tags.length <= 1) return [{
522
- locale: null,
523
- places: placesOf(changes)
524
- }];
525
- const rank = (tag) => tag === defaultLocale ? 0 : tag === null ? 2 : 1;
526
- return [...tags, null].sort((a, b) => rank(a) - rank(b) || localeLabel(a ?? "").localeCompare(localeLabel(b ?? ""))).map((locale) => ({
527
- locale,
528
- places: placesOf(changes.filter((change) => change.locale === locale))
529
- })).filter(({ places }) => places.size > 0);
530
- }
531
- /** The changes listed in one place. */
532
- function Place(t0) {
533
- const $ = c(12);
534
- const { name, place } = t0;
535
- const Icon = GROUPS[place.kind].icon;
453
+ function Cards(t0) {
454
+ const $ = c(33);
455
+ const { projectId, preview, onChanged, onShow, onOpenThread } = t0;
456
+ const { blockers, conflicts, lost, changes, defaultLocale } = preview;
536
457
  let t1;
537
- if ($[0] !== Icon) {
538
- t1 = /* @__PURE__ */ jsx(Icon, { className: "size-3.5" });
539
- $[0] = Icon;
458
+ if ($[0] !== preview.warnings) {
459
+ t1 = preview.warnings.filter(isShownWarning);
460
+ $[0] = preview.warnings;
540
461
  $[1] = t1;
541
462
  } else t1 = $[1];
463
+ const warnings = t1;
464
+ if (blockers.length + warnings.length + conflicts.length + lost.length === 0) return null;
542
465
  let t2;
543
- if ($[2] !== name || $[3] !== t1) {
544
- t2 = /* @__PURE__ */ jsxs("h4", {
545
- className: "text-muted-foreground flex items-center gap-1.5 text-xs font-medium",
546
- children: [t1, name]
547
- });
548
- $[2] = name;
549
- $[3] = t1;
550
- $[4] = t2;
551
- } else t2 = $[4];
466
+ if ($[2] !== changes) {
467
+ t2 = new Set(changes.filter(_temp).map(_temp2));
468
+ $[2] = changes;
469
+ $[3] = t2;
470
+ } else t2 = $[3];
471
+ const deleted = t2;
552
472
  let t3;
553
- if ($[5] !== place.changes) {
554
- t3 = place.changes.map(_temp3);
555
- $[5] = place.changes;
556
- $[6] = t3;
557
- } else t3 = $[6];
558
- let t4;
559
- if ($[7] !== t3) {
560
- t4 = /* @__PURE__ */ jsx("ul", {
561
- className: "flex flex-col",
562
- children: t3
473
+ if ($[4] !== blockers || $[5] !== onOpenThread || $[6] !== onShow) {
474
+ t3 = /* @__PURE__ */ jsx(ProblemCards, {
475
+ problems: blockers,
476
+ tone: "danger",
477
+ icon: OctagonX,
478
+ onShow,
479
+ onOpenThread
563
480
  });
481
+ $[4] = blockers;
482
+ $[5] = onOpenThread;
483
+ $[6] = onShow;
564
484
  $[7] = t3;
565
- $[8] = t4;
566
- } else t4 = $[8];
567
- let t5;
568
- if ($[9] !== t2 || $[10] !== t4) {
569
- t5 = /* @__PURE__ */ jsxs("section", {
570
- className: "flex flex-col gap-1",
571
- children: [t2, t4]
485
+ } else t3 = $[7];
486
+ let t4;
487
+ if ($[8] !== onOpenThread || $[9] !== onShow || $[10] !== warnings) {
488
+ t4 = /* @__PURE__ */ jsx(ProblemCards, {
489
+ problems: warnings,
490
+ tone: "warning",
491
+ icon: TriangleAlert,
492
+ onShow,
493
+ onOpenThread
572
494
  });
573
- $[9] = t2;
574
- $[10] = t4;
575
- $[11] = t5;
576
- } else t5 = $[11];
577
- return t5;
578
- }
579
- function _temp3(change) {
580
- return /* @__PURE__ */ jsxs("li", {
581
- className: "flex items-center gap-2 py-0.5 pl-5 text-sm",
582
- title: change.change,
583
- children: [
584
- /* @__PURE__ */ jsx("span", {
585
- "aria-hidden": true,
586
- className: cn("w-2 text-center font-mono", CHANGES[change.change].className),
587
- children: CHANGES[change.change].sign
588
- }),
589
- /* @__PURE__ */ jsx("span", {
590
- className: "truncate",
591
- "data-change-label": true,
592
- children: changeLabel(change)
593
- }),
594
- /* @__PURE__ */ jsxs("span", {
595
- className: "sr-only",
495
+ $[8] = onOpenThread;
496
+ $[9] = onShow;
497
+ $[10] = warnings;
498
+ $[11] = t4;
499
+ } else t4 = $[11];
500
+ let t5;
501
+ if ($[12] !== conflicts || $[13] !== defaultLocale || $[14] !== deleted || $[15] !== onChanged || $[16] !== projectId) {
502
+ let t6;
503
+ if ($[18] !== defaultLocale || $[19] !== deleted || $[20] !== onChanged || $[21] !== projectId) {
504
+ t6 = (conflict) => /* @__PURE__ */ jsxs(Card, {
505
+ tone: "warning",
506
+ icon: Replace,
507
+ title: conflictTitle(conflict),
596
508
  children: [
597
- "(",
598
- change.change,
599
- ")"
509
+ /* @__PURE__ */ jsx("p", { children: placeInLocale(conflict, defaultLocale) }),
510
+ /* @__PURE__ */ jsx("p", { children: conflictDetail(conflict, deleted.has(JSON.stringify([
511
+ conflict.entity,
512
+ conflict.id,
513
+ conflict.locale
514
+ ]))) }),
515
+ /* @__PURE__ */ jsx(ConflictFields, { conflict }),
516
+ conflict.revertible && /* @__PURE__ */ jsx(UseLiveVersionButton, {
517
+ projectId,
518
+ conflict,
519
+ onUsed: onChanged
520
+ })
600
521
  ]
601
- })
602
- ]
603
- }, `${change.entity}:${change.id}`);
522
+ }, conflictKey(conflict));
523
+ $[18] = defaultLocale;
524
+ $[19] = deleted;
525
+ $[20] = onChanged;
526
+ $[21] = projectId;
527
+ $[22] = t6;
528
+ } else t6 = $[22];
529
+ t5 = conflicts.map(t6);
530
+ $[12] = conflicts;
531
+ $[13] = defaultLocale;
532
+ $[14] = deleted;
533
+ $[15] = onChanged;
534
+ $[16] = projectId;
535
+ $[17] = t5;
536
+ } else t5 = $[17];
537
+ let t6;
538
+ if ($[23] !== defaultLocale || $[24] !== lost) {
539
+ let t7;
540
+ if ($[26] !== defaultLocale) {
541
+ t7 = (change_1) => /* @__PURE__ */ jsxs(Card, {
542
+ tone: "warning",
543
+ icon: Unlink,
544
+ title: change_1.reason === "writtenAfterDeletion" ? change_1.label : `Loses the change to the ${change_1.label}`,
545
+ children: [/* @__PURE__ */ jsx("p", { children: placeInLocale(change_1, defaultLocale) }), /* @__PURE__ */ jsx("p", { children: LOST_REASONS[change_1.reason] })]
546
+ }, JSON.stringify([
547
+ change_1.entity,
548
+ change_1.id,
549
+ change_1.locale
550
+ ]));
551
+ $[26] = defaultLocale;
552
+ $[27] = t7;
553
+ } else t7 = $[27];
554
+ t6 = lost.map(t7);
555
+ $[23] = defaultLocale;
556
+ $[24] = lost;
557
+ $[25] = t6;
558
+ } else t6 = $[25];
559
+ let t7;
560
+ if ($[28] !== t3 || $[29] !== t4 || $[30] !== t5 || $[31] !== t6) {
561
+ t7 = /* @__PURE__ */ jsxs("ul", {
562
+ className: "flex flex-col gap-2",
563
+ children: [
564
+ t3,
565
+ t4,
566
+ t5,
567
+ t6
568
+ ]
569
+ });
570
+ $[28] = t3;
571
+ $[29] = t4;
572
+ $[30] = t5;
573
+ $[31] = t6;
574
+ $[32] = t7;
575
+ } else t7 = $[32];
576
+ return t7;
604
577
  }
605
- /**
606
- * The draft's changes, grouped by locale once the draft changes more than its default locale,
607
- * then by page, layout and collection. Collapsed at first: the insights above are what to read
608
- * before publishing.
609
- */
610
- function Changes(t0) {
611
- const $ = c(46);
612
- const { changes, defaultLocale } = t0;
578
+ function _temp2(change_0) {
579
+ return JSON.stringify([
580
+ change_0.entity,
581
+ change_0.id,
582
+ change_0.locale
583
+ ]);
584
+ }
585
+ function _temp(change) {
586
+ return change.change === "deleted";
587
+ }
588
+ /** A quiet line saying something is done, with a check, or still running, with a spinner. */
589
+ function StatusLine(t0) {
590
+ const $ = c(7);
591
+ const { done, children } = t0;
613
592
  let t1;
614
- if ($[0] !== changes) {
615
- t1 = new Set(changes.map(placeOf));
616
- $[0] = changes;
593
+ if ($[0] !== done) {
594
+ t1 = done ? /* @__PURE__ */ jsx(CircleCheck, { className: "mt-0.5 size-4 shrink-0" }) : /* @__PURE__ */ jsx(Spinner, {
595
+ "aria-hidden": true,
596
+ className: "mt-0.5 size-4 shrink-0"
597
+ });
598
+ $[0] = done;
617
599
  $[1] = t1;
618
600
  } else t1 = $[1];
619
- const groups = t1;
620
- let T0;
621
- let T1;
622
- let T2;
601
+ let t2;
602
+ if ($[2] !== children) {
603
+ t2 = /* @__PURE__ */ jsx("span", { children });
604
+ $[2] = children;
605
+ $[3] = t2;
606
+ } else t2 = $[3];
607
+ let t3;
608
+ if ($[4] !== t1 || $[5] !== t2) {
609
+ t3 = /* @__PURE__ */ jsxs("li", {
610
+ className: "text-muted-foreground flex items-start gap-2 text-sm",
611
+ "data-status-line": true,
612
+ children: [t1, t2]
613
+ });
614
+ $[4] = t1;
615
+ $[5] = t2;
616
+ $[6] = t3;
617
+ } else t3 = $[6];
618
+ return t3;
619
+ }
620
+ /** What Publish sends: the review's token, and the revision a draft with code shows. */
621
+ const publishInput = (projectId, shown, publishAnyway) => ({
622
+ projectId,
623
+ token: shown.token,
624
+ ...shown.code?.revision && { revision: shown.code.revision },
625
+ ...publishAnyway && { publishAnyway }
626
+ });
627
+ /** Why a publish with code went back to the review, as the review says it. */
628
+ const PUBLISH_ABORTED = {
629
+ revisionChanged: "The agent changed the code since this review opened, so the publish stopped. Check the preview, then publish again.",
630
+ conflictsChanged: "Live changed while publishing, so the publish stopped and Live is as it was. Check the new list.",
631
+ blocked: "Something now needs fixing before publishing, so the publish stopped.",
632
+ codeDoesNotMerge: "Live's code changed while publishing, and it doesn't merge with this draft's yet, so the publish stopped. Camox's agent is fixing it in the draft's thread: publish again once it's done.",
633
+ liveCodeMoved: "Live's code changed while publishing, and the draft took too long to take it in, so the publish stopped. Try again.",
634
+ failed: "The publish couldn't finish on Camox's side, and Live is as it was. Try again."
635
+ };
636
+ /**
637
+ * What's fine or still running: the draft is up to date with Live, its latest code changes
638
+ * building, its translations, and the page SEO being written.
639
+ */
640
+ function StatusLines(t0) {
641
+ const $ = c(34);
642
+ const { preview, locales, waiting } = t0;
643
+ const { conflicts, translating, warnings, code } = preview;
644
+ let seoPages;
645
+ let t1;
623
646
  let t2;
624
647
  let t3;
625
648
  let t4;
626
649
  let t5;
627
650
  let t6;
628
- if ($[2] !== changes || $[3] !== defaultLocale || $[4] !== groups.size) {
629
- t6 = Symbol.for("react.early_return_sentinel");
630
- bb0: {
631
- const locales = localesOf(changes, defaultLocale);
632
- if (groups.size === 0) {
633
- let t7;
634
- if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
635
- t7 = /* @__PURE__ */ jsx("p", {
636
- className: "text-muted-foreground text-sm",
637
- children: "This draft has no changes."
638
- });
639
- $[13] = t7;
640
- } else t7 = $[13];
641
- t6 = t7;
642
- break bb0;
643
- }
644
- let t7;
645
- if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
646
- t7 = Object.keys(CHANGES);
647
- $[14] = t7;
648
- } else t7 = $[14];
649
- let t8;
650
- if ($[15] !== changes) {
651
- t8 = t7.map((kind) => [kind, changes.filter((change) => change.change === kind).length]).filter(_temp4);
652
- $[15] = changes;
653
- $[16] = t8;
654
- } else t8 = $[16];
655
- const counts = t8;
656
- T2 = Accordion;
657
- t5 = "rounded-lg border";
658
- T1 = AccordionItem;
659
- let t9;
660
- if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
661
- t9 = /* @__PURE__ */ jsx(ChevronRight, { className: "text-muted-foreground size-4 shrink-0 transition-transform group-data-panel-open:rotate-90" });
662
- $[17] = t9;
663
- } else t9 = $[17];
664
- let t10;
665
- if ($[18] !== changes.length) {
666
- t10 = plural(changes.length, "change");
667
- $[18] = changes.length;
668
- $[19] = t10;
669
- } else t10 = $[19];
670
- let t11;
671
- if ($[20] !== t10) {
672
- t11 = /* @__PURE__ */ jsx("span", {
673
- className: "text-sm font-medium",
674
- children: t10
675
- });
676
- $[20] = t10;
677
- $[21] = t11;
678
- } else t11 = $[21];
679
- let t12;
680
- if ($[22] !== groups.size) {
681
- t12 = plural(groups.size, "place");
682
- $[22] = groups.size;
683
- $[23] = t12;
684
- } else t12 = $[23];
685
- let t13;
686
- if ($[24] !== t12) {
687
- t13 = /* @__PURE__ */ jsxs("span", {
688
- className: "text-muted-foreground text-sm",
689
- children: ["in ", t12]
690
- });
691
- $[24] = t12;
692
- $[25] = t13;
693
- } else t13 = $[25];
694
- let t14;
695
- if ($[26] !== counts) {
696
- t14 = /* @__PURE__ */ jsx("span", {
697
- className: "ml-auto flex items-center gap-2 text-xs tabular-nums",
698
- children: counts.map(_temp5)
699
- });
700
- $[26] = counts;
701
- $[27] = t14;
702
- } else t14 = $[27];
703
- if ($[28] !== t11 || $[29] !== t13 || $[30] !== t14) {
704
- t4 = /* @__PURE__ */ jsx(AccordionHeader, { children: /* @__PURE__ */ jsxs(AccordionTrigger, {
705
- className: "group hover:bg-muted/50 flex w-full items-center gap-2 rounded-lg px-3 py-2.5 text-left",
706
- children: [
707
- t9,
708
- t11,
709
- t13,
710
- t14
711
- ]
712
- }) });
713
- $[28] = t11;
714
- $[29] = t13;
715
- $[30] = t14;
716
- $[31] = t4;
717
- } else t4 = $[31];
718
- T0 = AccordionPanel;
719
- t2 = "flex flex-col gap-4 border-t px-3 py-3";
720
- t3 = locales.map(_temp7);
721
- }
722
- $[2] = changes;
723
- $[3] = defaultLocale;
724
- $[4] = groups.size;
725
- $[5] = T0;
726
- $[6] = T1;
727
- $[7] = T2;
651
+ if ($[0] !== code || $[1] !== conflicts.length || $[2] !== locales || $[3] !== translating || $[4] !== waiting || $[5] !== warnings) {
652
+ const translations = locales.filter(_temp3).map(_temp4);
653
+ let t7;
654
+ if ($[13] !== warnings) {
655
+ t7 = new Set(warnings.filter(_temp5).map(_temp6));
656
+ $[13] = warnings;
657
+ $[14] = t7;
658
+ } else t7 = $[14];
659
+ seoPages = t7.size;
660
+ const aborted = code?.publishAborted && !code.publishing ? code.publishAborted : null;
661
+ t1 = "flex flex-col gap-1.5";
662
+ if ($[15] !== aborted) {
663
+ t2 = aborted && /* @__PURE__ */ jsx("li", {
664
+ className: "text-sm text-amber-700 dark:text-amber-400",
665
+ children: PUBLISH_ABORTED[aborted] ?? PUBLISH_ABORTED.failed
666
+ });
667
+ $[15] = aborted;
668
+ $[16] = t2;
669
+ } else t2 = $[16];
670
+ if ($[17] !== code?.includesLive || $[18] !== conflicts.length) {
671
+ t3 = conflicts.length === 0 && (code?.includesLive ?? true) && /* @__PURE__ */ jsx(StatusLine, {
672
+ done: true,
673
+ children: "Includes everything published to Live since this draft started"
674
+ });
675
+ $[17] = code?.includesLive;
676
+ $[18] = conflicts.length;
677
+ $[19] = t3;
678
+ } else t3 = $[19];
679
+ if ($[20] !== code?.building) {
680
+ t4 = code?.building && /* @__PURE__ */ jsx(StatusLine, {
681
+ done: false,
682
+ children: "Building the latest changes…"
683
+ });
684
+ $[20] = code?.building;
685
+ $[21] = t4;
686
+ } else t4 = $[21];
687
+ if ($[22] !== code?.publishing) {
688
+ t5 = code?.publishing && /* @__PURE__ */ jsx(StatusLine, {
689
+ done: false,
690
+ children: "Publishing the new code and content…"
691
+ });
692
+ $[22] = code?.publishing;
693
+ $[23] = t5;
694
+ } else t5 = $[23];
695
+ t6 = translating.length > 0 ? /* @__PURE__ */ jsxs(StatusLine, {
696
+ done: false,
697
+ children: [
698
+ "Translating into ",
699
+ listFormat.format(translating.map(localeLabel)),
700
+ ".",
701
+ " ",
702
+ waiting ? "Publishing once translated." : "Publishing waits for it."
703
+ ]
704
+ }) : translations.length > 0 && /* @__PURE__ */ jsxs(StatusLine, {
705
+ done: true,
706
+ children: ["Translated into ", listFormat.format(translations.map(localeLabel))]
707
+ });
708
+ $[0] = code;
709
+ $[1] = conflicts.length;
710
+ $[2] = locales;
711
+ $[3] = translating;
712
+ $[4] = waiting;
713
+ $[5] = warnings;
714
+ $[6] = seoPages;
715
+ $[7] = t1;
728
716
  $[8] = t2;
729
717
  $[9] = t3;
730
718
  $[10] = t4;
731
719
  $[11] = t5;
732
720
  $[12] = t6;
733
721
  } else {
734
- T0 = $[5];
735
- T1 = $[6];
736
- T2 = $[7];
722
+ seoPages = $[6];
723
+ t1 = $[7];
737
724
  t2 = $[8];
738
725
  t3 = $[9];
739
726
  t4 = $[10];
740
727
  t5 = $[11];
741
728
  t6 = $[12];
742
729
  }
743
- if (t6 !== Symbol.for("react.early_return_sentinel")) return t6;
744
730
  let t7;
745
- if ($[32] !== t2 || $[33] !== t3) {
746
- t7 = /* @__PURE__ */ jsx("div", {
747
- className: t2,
748
- children: t3
731
+ if ($[24] !== seoPages) {
732
+ t7 = seoPages > 0 && /* @__PURE__ */ jsxs(StatusLine, {
733
+ done: false,
734
+ children: [
735
+ "Writing SEO for ",
736
+ plural(seoPages, "page"),
737
+ "…"
738
+ ]
749
739
  });
750
- $[32] = t2;
751
- $[33] = t3;
752
- $[34] = t7;
753
- } else t7 = $[34];
740
+ $[24] = seoPages;
741
+ $[25] = t7;
742
+ } else t7 = $[25];
754
743
  let t8;
755
- if ($[35] !== T0 || $[36] !== t7) {
756
- t8 = /* @__PURE__ */ jsx(T0, { children: t7 });
757
- $[35] = T0;
758
- $[36] = t7;
759
- $[37] = t8;
760
- } else t8 = $[37];
761
- let t9;
762
- if ($[38] !== T1 || $[39] !== t4 || $[40] !== t8) {
763
- t9 = /* @__PURE__ */ jsxs(T1, { children: [t4, t8] });
764
- $[38] = T1;
765
- $[39] = t4;
766
- $[40] = t8;
767
- $[41] = t9;
768
- } else t9 = $[41];
769
- let t10;
770
- if ($[42] !== T2 || $[43] !== t5 || $[44] !== t9) {
771
- t10 = /* @__PURE__ */ jsx(T2, {
772
- className: t5,
773
- children: t9
744
+ if ($[26] !== t1 || $[27] !== t2 || $[28] !== t3 || $[29] !== t4 || $[30] !== t5 || $[31] !== t6 || $[32] !== t7) {
745
+ t8 = /* @__PURE__ */ jsxs("ul", {
746
+ className: t1,
747
+ children: [
748
+ t2,
749
+ t3,
750
+ t4,
751
+ t5,
752
+ t6,
753
+ t7
754
+ ]
774
755
  });
775
- $[42] = T2;
776
- $[43] = t5;
777
- $[44] = t9;
778
- $[45] = t10;
779
- } else t10 = $[45];
780
- return t10;
756
+ $[26] = t1;
757
+ $[27] = t2;
758
+ $[28] = t3;
759
+ $[29] = t4;
760
+ $[30] = t5;
761
+ $[31] = t6;
762
+ $[32] = t7;
763
+ $[33] = t8;
764
+ } else t8 = $[33];
765
+ return t8;
781
766
  }
782
- function _temp7(t0) {
783
- const { locale, places } = t0;
784
- return /* @__PURE__ */ jsxs("div", {
785
- className: "flex flex-col gap-4",
786
- children: [locale && /* @__PURE__ */ jsx("p", {
787
- className: "text-sm font-medium",
788
- "data-change-locale": true,
789
- children: localeLabel(locale)
790
- }), [...places].map(_temp6)]
791
- }, locale ?? "");
767
+ function _temp6(warning_0) {
768
+ return warning_0.id;
792
769
  }
793
- function _temp6(t0) {
794
- const [name, place] = t0;
795
- return /* @__PURE__ */ jsx(Place, {
796
- name,
797
- place
798
- }, name);
770
+ function _temp5(warning) {
771
+ return warning.code === "metaTitlePending";
799
772
  }
800
- function _temp5(t0) {
801
- const [kind_0, count_0] = t0;
802
- return /* @__PURE__ */ jsxs("span", {
803
- title: `${count_0} ${kind_0}`,
804
- className: CHANGES[kind_0].className,
805
- children: [CHANGES[kind_0].sign, count_0]
806
- }, kind_0);
773
+ function _temp4(locale_0) {
774
+ return locale_0.tag;
807
775
  }
808
- function _temp4(t0) {
809
- const [, count] = t0;
810
- return count > 0;
776
+ function _temp3(locale) {
777
+ return !locale.isDefault;
778
+ }
779
+ /**
780
+ * The draft's overview: the bullets AI wrote about its changes, in full, under the headline the
781
+ * header shows, saying it's updating while they describe an older version of the draft. While
782
+ * it's first written, skeleton lines; once it failed, a Retry and a plain count of the changes,
783
+ * so the draft can still be reviewed. Nothing for a draft that gets no overview, as a catch-up
784
+ * draft.
785
+ */
786
+ function DraftOverview(t0) {
787
+ const $ = c(34);
788
+ const { projectId, preview } = t0;
789
+ const { overview, changes } = preview;
790
+ let t1;
791
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
792
+ t1 = {
793
+ ...draftMutations.retryOverview(),
794
+ onError: _temp7
795
+ };
796
+ $[0] = t1;
797
+ } else t1 = $[0];
798
+ const retry = useMutation(t1);
799
+ if (changes.length === 0) {
800
+ let t2;
801
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
802
+ t2 = /* @__PURE__ */ jsx("p", {
803
+ className: "text-muted-foreground text-sm",
804
+ children: "This draft has no changes."
805
+ });
806
+ $[1] = t2;
807
+ } else t2 = $[1];
808
+ return t2;
809
+ }
810
+ if (overview.status === "ready") {
811
+ let t2;
812
+ if ($[2] !== overview.bullets) {
813
+ t2 = overview.bullets.map(_temp8);
814
+ $[2] = overview.bullets;
815
+ $[3] = t2;
816
+ } else t2 = $[3];
817
+ let t3;
818
+ if ($[4] !== t2) {
819
+ t3 = /* @__PURE__ */ jsx("ul", {
820
+ className: "text-foreground/85 flex list-disc flex-col gap-1.5 pl-5 leading-relaxed",
821
+ children: t2
822
+ });
823
+ $[4] = t2;
824
+ $[5] = t3;
825
+ } else t3 = $[5];
826
+ let t4;
827
+ if ($[6] !== overview.stale) {
828
+ t4 = overview.stale && /* @__PURE__ */ jsxs("p", {
829
+ className: "text-muted-foreground flex items-center gap-1.5 text-xs",
830
+ children: [/* @__PURE__ */ jsx(Spinner, {
831
+ "aria-hidden": true,
832
+ className: "size-3"
833
+ }), "Updating…"]
834
+ });
835
+ $[6] = overview.stale;
836
+ $[7] = t4;
837
+ } else t4 = $[7];
838
+ let t5;
839
+ if ($[8] !== t3 || $[9] !== t4) {
840
+ t5 = /* @__PURE__ */ jsxs("div", {
841
+ "data-overview": true,
842
+ className: "flex flex-col gap-2",
843
+ children: [t3, t4]
844
+ });
845
+ $[8] = t3;
846
+ $[9] = t4;
847
+ $[10] = t5;
848
+ } else t5 = $[10];
849
+ return t5;
850
+ }
851
+ if (overview.status === "failed") {
852
+ let t2;
853
+ if ($[11] !== changes) {
854
+ t2 = new Set(changes.map(_temp9));
855
+ $[11] = changes;
856
+ $[12] = t2;
857
+ } else t2 = $[12];
858
+ const places = t2.size;
859
+ let t3;
860
+ if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
861
+ t3 = /* @__PURE__ */ jsx("p", {
862
+ className: "text-sm font-medium",
863
+ children: "Couldn't summarize this draft"
864
+ });
865
+ $[13] = t3;
866
+ } else t3 = $[13];
867
+ let t4;
868
+ if ($[14] !== projectId || $[15] !== retry) {
869
+ t4 = () => retry.mutate({ projectId });
870
+ $[14] = projectId;
871
+ $[15] = retry;
872
+ $[16] = t4;
873
+ } else t4 = $[16];
874
+ let t5;
875
+ if ($[17] !== retry.isPending) {
876
+ t5 = retry.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
877
+ $[17] = retry.isPending;
878
+ $[18] = t5;
879
+ } else t5 = $[18];
880
+ let t6;
881
+ if ($[19] !== retry.isPending || $[20] !== t4 || $[21] !== t5) {
882
+ t6 = /* @__PURE__ */ jsxs("div", {
883
+ className: "flex items-center gap-3",
884
+ children: [t3, /* @__PURE__ */ jsxs(Button, {
885
+ variant: "outline",
886
+ size: "sm",
887
+ className: "ml-auto",
888
+ disabled: retry.isPending,
889
+ onClick: t4,
890
+ children: [t5, "Retry"]
891
+ })]
892
+ });
893
+ $[19] = retry.isPending;
894
+ $[20] = t4;
895
+ $[21] = t5;
896
+ $[22] = t6;
897
+ } else t6 = $[22];
898
+ let t7;
899
+ if ($[23] !== changes.length) {
900
+ t7 = plural(changes.length, "change");
901
+ $[23] = changes.length;
902
+ $[24] = t7;
903
+ } else t7 = $[24];
904
+ let t8;
905
+ if ($[25] !== places) {
906
+ t8 = plural(places, "place");
907
+ $[25] = places;
908
+ $[26] = t8;
909
+ } else t8 = $[26];
910
+ let t9;
911
+ if ($[27] !== t7 || $[28] !== t8) {
912
+ t9 = /* @__PURE__ */ jsxs("p", {
913
+ className: "text-muted-foreground text-sm",
914
+ children: [
915
+ t7,
916
+ " in ",
917
+ t8
918
+ ]
919
+ });
920
+ $[27] = t7;
921
+ $[28] = t8;
922
+ $[29] = t9;
923
+ } else t9 = $[29];
924
+ let t10;
925
+ if ($[30] !== t6 || $[31] !== t9) {
926
+ t10 = /* @__PURE__ */ jsxs("div", {
927
+ "data-overview": true,
928
+ className: "flex flex-col gap-2",
929
+ children: [t6, t9]
930
+ });
931
+ $[30] = t6;
932
+ $[31] = t9;
933
+ $[32] = t10;
934
+ } else t10 = $[32];
935
+ return t10;
936
+ }
937
+ if (overview.status === "none") return null;
938
+ let t2;
939
+ if ($[33] === Symbol.for("react.memo_cache_sentinel")) {
940
+ t2 = /* @__PURE__ */ jsxs("div", {
941
+ "data-overview": true,
942
+ className: "flex flex-col gap-2",
943
+ children: [
944
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-11/12" }),
945
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4/5" }),
946
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-2/3" }),
947
+ /* @__PURE__ */ jsx("p", {
948
+ className: "text-muted-foreground text-sm",
949
+ children: "Summarizing this draft…"
950
+ })
951
+ ]
952
+ });
953
+ $[33] = t2;
954
+ } else t2 = $[33];
955
+ return t2;
956
+ }
957
+ function _temp9(change) {
958
+ return change.entity === "locale" ? "Languages" : ownerName(change.owner, change.entity);
959
+ }
960
+ function _temp8(bullet, index) {
961
+ return /* @__PURE__ */ jsx("li", { children: bullet }, index);
962
+ }
963
+ function _temp7(error) {
964
+ return toast.error(error.message || "Could not summarize the draft");
811
965
  }
812
966
  /**
813
967
  * Switches the studio to Live once its draft ended here, replacing the draft's URL entry. A
@@ -833,8 +987,8 @@ function useLeaveDraft() {
833
987
  * blur, and a blank name clears it; Escape puts the name back.
834
988
  */
835
989
  function DraftNameInput(t0) {
836
- const $ = c(20);
837
- const { projectId, draft, ref } = t0;
990
+ const $ = c(23);
991
+ const { projectId, draft, ref, className } = t0;
838
992
  const rename = useRenameDraft(projectId);
839
993
  const name = draft.name ?? "";
840
994
  let t1;
@@ -872,14 +1026,20 @@ function DraftNameInput(t0) {
872
1026
  $[8] = t3;
873
1027
  } else t3 = $[8];
874
1028
  let t4;
875
- if ($[9] !== save) {
876
- t4 = (event) => save(event.currentTarget);
877
- $[9] = save;
1029
+ if ($[9] !== className) {
1030
+ t4 = cn("hover:border-input focus-visible:border-ring focus-visible:ring-ring/50 placeholder:text-foreground focus:placeholder:text-muted-foreground -mx-1.5 h-8 w-full min-w-0 truncate rounded-md border border-transparent bg-transparent px-1.5 text-base font-medium transition-[color,box-shadow,border-color] outline-none hover:shadow-xs focus-visible:ring-3", className);
1031
+ $[9] = className;
878
1032
  $[10] = t4;
879
1033
  } else t4 = $[10];
880
1034
  let t5;
881
- if ($[11] !== name) {
882
- t5 = (event_0) => {
1035
+ if ($[11] !== save) {
1036
+ t5 = (event) => save(event.currentTarget);
1037
+ $[11] = save;
1038
+ $[12] = t5;
1039
+ } else t5 = $[12];
1040
+ let t6;
1041
+ if ($[13] !== name) {
1042
+ t6 = (event_0) => {
883
1043
  if (event_0.key === "Enter") {
884
1044
  event_0.preventDefault();
885
1045
  event_0.currentTarget.blur();
@@ -889,31 +1049,32 @@ function DraftNameInput(t0) {
889
1049
  event_0.currentTarget.value = name;
890
1050
  event_0.currentTarget.blur();
891
1051
  };
892
- $[11] = name;
893
- $[12] = t5;
894
- } else t5 = $[12];
895
- let t6;
896
- if ($[13] !== name || $[14] !== ref || $[15] !== t2 || $[16] !== t3 || $[17] !== t4 || $[18] !== t5) {
897
- t6 = /* @__PURE__ */ jsx("input", {
1052
+ $[13] = name;
1053
+ $[14] = t6;
1054
+ } else t6 = $[14];
1055
+ let t7;
1056
+ if ($[15] !== name || $[16] !== ref || $[17] !== t2 || $[18] !== t3 || $[19] !== t4 || $[20] !== t5 || $[21] !== t6) {
1057
+ t7 = /* @__PURE__ */ jsx("input", {
898
1058
  ref,
899
1059
  "aria-label": "Draft name",
900
1060
  defaultValue: name,
901
1061
  placeholder: t2,
902
1062
  title: t3,
903
1063
  maxLength: 200,
904
- className: "hover:border-input focus-visible:border-ring focus-visible:ring-ring/50 placeholder:text-foreground focus:placeholder:text-muted-foreground -mx-1.5 h-8 w-full min-w-0 truncate rounded-md border border-transparent bg-transparent px-1.5 text-base font-medium transition-[color,box-shadow,border-color] outline-none hover:shadow-xs focus-visible:ring-3",
905
- onBlur: t4,
906
- onKeyDown: t5
1064
+ className: t4,
1065
+ onBlur: t5,
1066
+ onKeyDown: t6
907
1067
  }, name);
908
- $[13] = name;
909
- $[14] = ref;
910
- $[15] = t2;
911
- $[16] = t3;
912
- $[17] = t4;
913
- $[18] = t5;
914
- $[19] = t6;
915
- } else t6 = $[19];
916
- return t6;
1068
+ $[15] = name;
1069
+ $[16] = ref;
1070
+ $[17] = t2;
1071
+ $[18] = t3;
1072
+ $[19] = t4;
1073
+ $[20] = t5;
1074
+ $[21] = t6;
1075
+ $[22] = t7;
1076
+ } else t7 = $[22];
1077
+ return t7;
917
1078
  }
918
1079
  /**
919
1080
  * Reviews a draft before publishing it whole, or discards it (ADR 0009). Publishing sends back
@@ -921,7 +1082,7 @@ function DraftNameInput(t0) {
921
1082
  * preview is shown. Once the draft ends, the studio switches to Live.
922
1083
  */
923
1084
  function ReviewDraftSheet(t0) {
924
- const $ = c(106);
1085
+ const $ = c(101);
925
1086
  const { projectId, draftId, open, startRenaming: t1, onOpenChange } = t0;
926
1087
  const startRenaming = t1 === void 0 ? false : t1;
927
1088
  const [confirmingDiscard, setConfirmingDiscard] = React.useState(false);
@@ -959,84 +1120,107 @@ function ReviewDraftSheet(t0) {
959
1120
  $[9] = t5;
960
1121
  } else t5 = $[9];
961
1122
  const draft = useReadQuery(t4, t5);
1123
+ let t6;
1124
+ if ($[10] !== projectId) {
1125
+ t6 = reads.localeList({ projectId });
1126
+ $[10] = projectId;
1127
+ $[11] = t6;
1128
+ } else t6 = $[11];
1129
+ let t7;
1130
+ if ($[12] !== open) {
1131
+ t7 = { enabled: open };
1132
+ $[12] = open;
1133
+ $[13] = t7;
1134
+ } else t7 = $[13];
1135
+ const locales = useReadQuery(t6, t7);
962
1136
  const leaveDraft = useLeaveDraft();
1137
+ const showInCanvas = useShowInCanvas();
963
1138
  const popup = React.useRef(null);
964
1139
  const nameInput = React.useRef(null);
965
- let t6;
966
- if ($[10] !== startRenaming) {
967
- t6 = () => {
1140
+ let t8;
1141
+ if ($[14] !== startRenaming) {
1142
+ t8 = () => {
968
1143
  if (startRenaming && nameInput.current) {
969
1144
  nameInput.current.select();
970
1145
  return nameInput.current;
971
1146
  }
972
1147
  return popup.current;
973
1148
  };
974
- $[10] = startRenaming;
975
- $[11] = t6;
976
- } else t6 = $[11];
977
- const initialFocus = t6;
978
- let t7;
979
- if ($[12] !== draft.data?.translatingLocales) {
980
- t7 = draft.data?.translatingLocales.join(",");
981
- $[12] = draft.data?.translatingLocales;
982
- $[13] = t7;
983
- } else t7 = $[13];
984
- const pending = t7;
1149
+ $[14] = startRenaming;
1150
+ $[15] = t8;
1151
+ } else t8 = $[15];
1152
+ const initialFocus = t8;
1153
+ let t9;
1154
+ if ($[16] !== draft.data?.translatingLocales) {
1155
+ t9 = draft.data?.translatingLocales.join(",");
1156
+ $[16] = draft.data?.translatingLocales;
1157
+ $[17] = t9;
1158
+ } else t9 = $[17];
1159
+ const pending = t9;
985
1160
  const seenPending = React.useRef(pending);
986
1161
  const { refetch } = preview;
987
- let t8;
988
- let t9;
989
- if ($[14] !== pending || $[15] !== refetch) {
990
- t8 = () => {
1162
+ let t10;
1163
+ let t11;
1164
+ if ($[18] !== pending || $[19] !== refetch) {
1165
+ t10 = () => {
991
1166
  if (seenPending.current !== void 0 && seenPending.current !== pending) refetch();
992
1167
  seenPending.current = pending;
993
1168
  };
994
- t9 = [pending, refetch];
995
- $[14] = pending;
996
- $[15] = refetch;
997
- $[16] = t8;
998
- $[17] = t9;
1169
+ t11 = [pending, refetch];
1170
+ $[18] = pending;
1171
+ $[19] = refetch;
1172
+ $[20] = t10;
1173
+ $[21] = t11;
999
1174
  } else {
1000
- t8 = $[16];
1001
- t9 = $[17];
1175
+ t10 = $[20];
1176
+ t11 = $[21];
1002
1177
  }
1003
- React.useEffect(t8, t9);
1004
- let t10;
1005
- if ($[18] !== leaveDraft || $[19] !== onOpenChange) {
1006
- t10 = (ended) => {
1178
+ React.useEffect(t10, t11);
1179
+ let t12;
1180
+ if ($[22] !== leaveDraft || $[23] !== onOpenChange) {
1181
+ t12 = (ended) => {
1007
1182
  onOpenChange(false);
1008
1183
  leaveDraft(ended);
1009
1184
  };
1010
- $[18] = leaveDraft;
1011
- $[19] = onOpenChange;
1012
- $[20] = t10;
1013
- } else t10 = $[20];
1014
- const leave = t10;
1015
- let t11;
1016
- if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
1017
- t11 = draftMutations.publish();
1018
- $[21] = t11;
1019
- } else t11 = $[21];
1020
- let t12;
1021
- if ($[22] !== leave || $[23] !== preview) {
1022
- t12 = (t13) => {
1023
- const { empty, ended: ended_0 } = t13;
1185
+ $[22] = leaveDraft;
1186
+ $[23] = onOpenChange;
1187
+ $[24] = t12;
1188
+ } else t12 = $[24];
1189
+ const leave = t12;
1190
+ let t13;
1191
+ if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
1192
+ t13 = draftMutations.publish();
1193
+ $[25] = t13;
1194
+ } else t13 = $[25];
1195
+ let t14;
1196
+ if ($[26] !== leave || $[27] !== preview) {
1197
+ t14 = (result) => {
1198
+ if ("publishing" in result && result.publishing) {
1199
+ preview.refetch();
1200
+ return;
1201
+ }
1202
+ const { empty, ended: ended_0 } = result;
1024
1203
  if (!empty) return leave(ended_0);
1025
1204
  toast.info("This draft has no changes, so there is nothing to publish.");
1026
1205
  preview.refetch();
1027
1206
  };
1028
- $[22] = leave;
1029
- $[23] = preview;
1030
- $[24] = t12;
1031
- } else t12 = $[24];
1032
- let t13;
1033
- if ($[25] !== preview) {
1034
- t13 = (error) => {
1207
+ $[26] = leave;
1208
+ $[27] = preview;
1209
+ $[28] = t14;
1210
+ } else t14 = $[28];
1211
+ let t15;
1212
+ if ($[29] !== preview) {
1213
+ t15 = (error) => {
1035
1214
  if (error.code === CONFLICTS_CHANGED_ERROR) {
1036
1215
  toast.error("Live changed since you opened this review. Check the new list.");
1037
1216
  preview.refetch();
1038
1217
  return;
1039
1218
  }
1219
+ if (error.code === REVISION_CHANGED_ERROR) {
1220
+ toast.error(error.message || "The draft changed since you opened this review.");
1221
+ preview.refetch();
1222
+ return;
1223
+ }
1040
1224
  if (error.code === TRANSLATIONS_PENDING_ERROR) {
1041
1225
  toast.info("Translations are still running. Wait for them, or publish anyway.");
1042
1226
  preview.refetch();
@@ -1045,31 +1229,32 @@ function ReviewDraftSheet(t0) {
1045
1229
  toast.error(error.message || "Could not publish the draft");
1046
1230
  preview.refetch();
1047
1231
  };
1048
- $[25] = preview;
1049
- $[26] = t13;
1050
- } else t13 = $[26];
1051
- let t14;
1052
- if ($[27] !== t12 || $[28] !== t13) {
1053
- t14 = {
1054
- ...t11,
1055
- onSuccess: t12,
1056
- onError: t13
1232
+ $[29] = preview;
1233
+ $[30] = t15;
1234
+ } else t15 = $[30];
1235
+ let t16;
1236
+ if ($[31] !== t14 || $[32] !== t15) {
1237
+ t16 = {
1238
+ ...t13,
1239
+ onSuccess: t14,
1240
+ onError: t15
1057
1241
  };
1058
- $[27] = t12;
1059
- $[28] = t13;
1060
- $[29] = t14;
1061
- } else t14 = $[29];
1062
- const publish = useMutation(t14);
1242
+ $[31] = t14;
1243
+ $[32] = t15;
1244
+ $[33] = t16;
1245
+ } else t16 = $[33];
1246
+ const publish = useMutation(t16);
1063
1247
  const data = preview.data;
1248
+ const headline = data?.overview.status === "ready" ? data.overview.headline : null;
1064
1249
  const busy = publish.isPending;
1065
- const ready = !!data && data.blockers.length === 0 && !busy && !preview.isFetching;
1066
- let t15;
1067
- if ($[30] !== data?.translating) {
1068
- t15 = data?.translating ?? [];
1069
- $[30] = data?.translating;
1070
- $[31] = t15;
1071
- } else t15 = $[31];
1072
- const translating = t15;
1250
+ const ready = !!data && data.blockers.length === 0 && !data.code?.building && !data.code?.publishing && !busy && !preview.isFetching;
1251
+ let t17;
1252
+ if ($[34] !== data?.translating) {
1253
+ t17 = data?.translating ?? [];
1254
+ $[34] = data?.translating;
1255
+ $[35] = t17;
1256
+ } else t17 = $[35];
1257
+ const translating = t17;
1073
1258
  const [waiting, setWaiting] = React.useState(null);
1074
1259
  const translated = !!data && !preview.isFetching && data.translating.length === 0;
1075
1260
  if (waiting && translated) {
@@ -1077,17 +1262,14 @@ function ReviewDraftSheet(t0) {
1077
1262
  if (data.blockers.length > 0 || appeared) setWaiting(null);
1078
1263
  }
1079
1264
  const { mutate } = publish;
1080
- let t16;
1081
- let t17;
1082
- if ($[32] !== busy || $[33] !== data || $[34] !== mutate || $[35] !== projectId || $[36] !== translated || $[37] !== waiting) {
1083
- t16 = () => {
1265
+ let t18;
1266
+ let t19;
1267
+ if ($[36] !== busy || $[37] !== data || $[38] !== mutate || $[39] !== projectId || $[40] !== translated || $[41] !== waiting) {
1268
+ t18 = () => {
1084
1269
  if (!waiting || !translated || !data || busy) return;
1085
- mutate({
1086
- projectId,
1087
- token: data.token
1088
- }, { onSettled: () => setWaiting(null) });
1270
+ mutate(publishInput(projectId, data), { onSettled: () => setWaiting(null) });
1089
1271
  };
1090
- t17 = [
1272
+ t19 = [
1091
1273
  waiting,
1092
1274
  translated,
1093
1275
  data,
@@ -1095,277 +1277,255 @@ function ReviewDraftSheet(t0) {
1095
1277
  mutate,
1096
1278
  projectId
1097
1279
  ];
1098
- $[32] = busy;
1099
- $[33] = data;
1100
- $[34] = mutate;
1101
- $[35] = projectId;
1102
- $[36] = translated;
1103
- $[37] = waiting;
1104
- $[38] = t16;
1105
- $[39] = t17;
1280
+ $[36] = busy;
1281
+ $[37] = data;
1282
+ $[38] = mutate;
1283
+ $[39] = projectId;
1284
+ $[40] = translated;
1285
+ $[41] = waiting;
1286
+ $[42] = t18;
1287
+ $[43] = t19;
1106
1288
  } else {
1107
- t16 = $[38];
1108
- t17 = $[39];
1289
+ t18 = $[42];
1290
+ t19 = $[43];
1109
1291
  }
1110
- React.useEffect(t16, t17);
1111
- let t18;
1112
- if ($[40] !== data || $[41] !== projectId || $[42] !== publish || $[43] !== translating.length) {
1113
- t18 = () => {
1292
+ React.useEffect(t18, t19);
1293
+ let t20;
1294
+ if ($[44] !== data || $[45] !== projectId || $[46] !== publish || $[47] !== translating.length) {
1295
+ t20 = () => {
1114
1296
  if (!data) return;
1115
- if (translating.length === 0) return publish.mutate({
1116
- projectId,
1117
- token: data.token
1118
- });
1297
+ if (translating.length === 0) return publish.mutate(publishInput(projectId, data));
1119
1298
  setWaiting({ conflicts: new Set(data.conflicts.map(conflictKey)) });
1120
1299
  };
1121
- $[40] = data;
1122
- $[41] = projectId;
1123
- $[42] = publish;
1124
- $[43] = translating.length;
1125
- $[44] = t18;
1126
- } else t18 = $[44];
1127
- const publishAll = t18;
1128
- let t19;
1129
- if ($[45] !== draft.data || $[46] !== projectId) {
1130
- t19 = draft.data?.kind === "regular" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SheetTitle, {
1131
- className: "sr-only",
1132
- children: draftLabel(draft.data)
1133
- }), /* @__PURE__ */ jsx(DraftNameInput, {
1134
- ref: nameInput,
1135
- projectId,
1136
- draft: draft.data
1137
- })] }) : /* @__PURE__ */ jsx(SheetTitle, {
1138
- className: "text-base",
1139
- children: draft.data ? draftLabel(draft.data) : "Draft"
1140
- });
1141
- $[45] = draft.data;
1142
- $[46] = projectId;
1143
- $[47] = t19;
1144
- } else t19 = $[47];
1145
- let t20;
1146
- if ($[48] !== draft.data) {
1147
- t20 = draft.data ? `${draft.data.createdBy.name} · started ${timeAgo(draft.data.createdAt)}` : "Publishing applies this whole draft to Live.";
1148
- $[48] = draft.data;
1149
- $[49] = t20;
1150
- } else t20 = $[49];
1300
+ $[44] = data;
1301
+ $[45] = projectId;
1302
+ $[46] = publish;
1303
+ $[47] = translating.length;
1304
+ $[48] = t20;
1305
+ } else t20 = $[48];
1306
+ const publishWhole = t20;
1151
1307
  let t21;
1152
- if ($[50] !== t20) {
1153
- t21 = /* @__PURE__ */ jsx(SheetDescription, { children: t20 });
1154
- $[50] = t20;
1155
- $[51] = t21;
1156
- } else t21 = $[51];
1157
- let t22;
1158
- if ($[52] !== t19 || $[53] !== t21) {
1159
- t22 = /* @__PURE__ */ jsxs("div", {
1308
+ if ($[49] !== draft.data || $[50] !== headline || $[51] !== projectId) {
1309
+ t21 = /* @__PURE__ */ jsx("div", {
1160
1310
  className: "flex flex-col gap-1 border-b p-4 pr-12",
1161
- children: [t19, t21]
1311
+ children: headline ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(SheetDescription, {
1312
+ className: "flex min-w-0 items-center gap-1",
1313
+ children: [draft.data?.kind === "regular" ? /* @__PURE__ */ jsx(DraftNameInput, {
1314
+ ref: nameInput,
1315
+ projectId,
1316
+ draft: draft.data,
1317
+ className: "placeholder:text-muted-foreground text-muted-foreground field-sizing-content h-6 w-auto max-w-full text-sm font-normal"
1318
+ }) : draft.data && /* @__PURE__ */ jsx("span", {
1319
+ className: "truncate",
1320
+ children: draftLabel(draft.data)
1321
+ }), draft.data && /* @__PURE__ */ jsxs("span", {
1322
+ className: "shrink-0",
1323
+ children: [
1324
+ "· ",
1325
+ draft.data.createdBy.name,
1326
+ ", started ",
1327
+ timeAgo(draft.data.createdAt)
1328
+ ]
1329
+ })]
1330
+ }), /* @__PURE__ */ jsx(SheetTitle, {
1331
+ className: "text-lg leading-snug font-semibold",
1332
+ children: headline
1333
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [draft.data?.kind === "regular" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SheetTitle, {
1334
+ className: "sr-only",
1335
+ children: draftLabel(draft.data)
1336
+ }), /* @__PURE__ */ jsx(DraftNameInput, {
1337
+ ref: nameInput,
1338
+ projectId,
1339
+ draft: draft.data
1340
+ })] }) : /* @__PURE__ */ jsx(SheetTitle, {
1341
+ className: "text-base",
1342
+ children: draft.data ? draftLabel(draft.data) : "Draft"
1343
+ }), /* @__PURE__ */ jsx(SheetDescription, { children: draft.data ? `${draft.data.createdBy.name} · started ${timeAgo(draft.data.createdAt)}` : "Publishing applies this whole draft to Live." })] })
1162
1344
  });
1163
- $[52] = t19;
1164
- $[53] = t21;
1165
- $[54] = t22;
1166
- } else t22 = $[54];
1167
- let t23;
1168
- if ($[55] !== data) {
1169
- t23 = data ? /* @__PURE__ */ jsxs("div", {
1345
+ $[49] = draft.data;
1346
+ $[50] = headline;
1347
+ $[51] = projectId;
1348
+ $[52] = t21;
1349
+ } else t21 = $[52];
1350
+ let t22;
1351
+ if ($[53] !== data || $[54] !== locales || $[55] !== onOpenChange || $[56] !== preview || $[57] !== projectId || $[58] !== showInCanvas || $[59] !== waiting) {
1352
+ t22 = data ? /* @__PURE__ */ jsxs("div", {
1170
1353
  className: "flex min-h-0 flex-1 flex-col gap-6 overflow-y-auto p-4",
1171
1354
  children: [
1172
- /* @__PURE__ */ jsx(Verdict, { preview: data }),
1173
- /* @__PURE__ */ jsx(Insights, { preview: data }),
1174
- /* @__PURE__ */ jsx(Changes, {
1175
- changes: data.changes,
1176
- defaultLocale: data.defaultLocale ?? void 0
1355
+ /* @__PURE__ */ jsx(DraftOverview, {
1356
+ projectId,
1357
+ preview: data
1358
+ }),
1359
+ /* @__PURE__ */ jsx(Cards, {
1360
+ projectId,
1361
+ preview: data,
1362
+ onChanged: () => void preview.refetch(),
1363
+ onShow: (target) => {
1364
+ onOpenChange(false);
1365
+ showInCanvas(target);
1366
+ },
1367
+ onOpenThread: () => {
1368
+ onOpenChange(false);
1369
+ previewStore.send({ type: "showCanvas" });
1370
+ }
1371
+ }),
1372
+ /* @__PURE__ */ jsx(StatusLines, {
1373
+ preview: data,
1374
+ locales: locales.data ?? [],
1375
+ waiting: !!waiting
1177
1376
  })
1178
1377
  ]
1179
1378
  }) : /* @__PURE__ */ jsx("div", {
1180
1379
  className: "flex flex-1 items-center justify-center",
1181
1380
  children: /* @__PURE__ */ jsx(Spinner, { className: "text-muted-foreground" })
1182
1381
  });
1183
- $[55] = data;
1184
- $[56] = t23;
1185
- } else t23 = $[56];
1382
+ $[53] = data;
1383
+ $[54] = locales;
1384
+ $[55] = onOpenChange;
1385
+ $[56] = preview;
1386
+ $[57] = projectId;
1387
+ $[58] = showInCanvas;
1388
+ $[59] = waiting;
1389
+ $[60] = t22;
1390
+ } else t22 = $[60];
1391
+ let t23;
1186
1392
  let t24;
1187
- if ($[57] !== translating || $[58] !== waiting) {
1188
- t24 = translating.length > 0 && /* @__PURE__ */ jsxs("p", {
1189
- className: "text-muted-foreground flex items-center gap-2 text-sm",
1190
- children: [
1191
- /* @__PURE__ */ jsx(Spinner, {
1192
- "aria-hidden": true,
1193
- className: "size-3.5 shrink-0"
1194
- }),
1195
- "Translating into ",
1196
- translating.map(localeLabel).join(", "),
1197
- "…",
1198
- " ",
1199
- waiting ? "Publishing once translated." : "Publishing waits for it."
1200
- ]
1201
- });
1202
- $[57] = translating;
1203
- $[58] = waiting;
1204
- $[59] = t24;
1205
- } else t24 = $[59];
1206
- let t25;
1207
- if ($[60] !== data) {
1208
- t25 = data && data.conflicts.length > 0 && /* @__PURE__ */ jsxs("p", {
1209
- className: "text-muted-foreground text-sm",
1210
- children: [plural(data.conflicts.length, "Live change"), " will be overwritten"]
1211
- });
1212
- $[60] = data;
1213
- $[61] = t25;
1214
- } else t25 = $[61];
1215
- let t26;
1216
- let t27;
1217
- if ($[62] === Symbol.for("react.memo_cache_sentinel")) {
1218
- t26 = () => setConfirmingDiscard(true);
1219
- t27 = /* @__PURE__ */ jsx(Trash2, {});
1220
- $[62] = t26;
1221
- $[63] = t27;
1393
+ if ($[61] === Symbol.for("react.memo_cache_sentinel")) {
1394
+ t23 = () => setConfirmingDiscard(true);
1395
+ t24 = /* @__PURE__ */ jsx(Trash2, {});
1396
+ $[61] = t23;
1397
+ $[62] = t24;
1222
1398
  } else {
1223
- t26 = $[62];
1224
- t27 = $[63];
1399
+ t23 = $[61];
1400
+ t24 = $[62];
1225
1401
  }
1226
- let t28;
1227
- if ($[64] !== busy) {
1228
- t28 = /* @__PURE__ */ jsxs(Button, {
1402
+ let t25;
1403
+ if ($[63] !== busy) {
1404
+ t25 = /* @__PURE__ */ jsxs(Button, {
1229
1405
  variant: "ghost",
1230
1406
  className: "text-destructive",
1231
1407
  disabled: busy,
1232
- onClick: t26,
1233
- children: [t27, "Discard draft"]
1408
+ onClick: t23,
1409
+ children: [t24, "Discard draft"]
1234
1410
  });
1235
- $[64] = busy;
1236
- $[65] = t28;
1237
- } else t28 = $[65];
1238
- let t29;
1239
- if ($[66] !== data || $[67] !== projectId || $[68] !== publish || $[69] !== ready || $[70] !== translating.length) {
1240
- t29 = translating.length > 0 && /* @__PURE__ */ jsx(Button, {
1411
+ $[63] = busy;
1412
+ $[64] = t25;
1413
+ } else t25 = $[64];
1414
+ let t26;
1415
+ if ($[65] !== data || $[66] !== projectId || $[67] !== publish || $[68] !== ready || $[69] !== translating.length) {
1416
+ t26 = translating.length > 0 && /* @__PURE__ */ jsx(Button, {
1241
1417
  variant: "outline",
1242
1418
  className: "ml-auto",
1243
1419
  disabled: !ready,
1244
- onClick: () => data && publish.mutate({
1245
- projectId,
1246
- token: data.token,
1247
- publishAnyway: true
1248
- }),
1420
+ onClick: () => data && publish.mutate(publishInput(projectId, data, true)),
1249
1421
  children: "Publish anyway"
1250
1422
  });
1251
- $[66] = data;
1252
- $[67] = projectId;
1253
- $[68] = publish;
1254
- $[69] = ready;
1255
- $[70] = translating.length;
1256
- $[71] = t29;
1257
- } else t29 = $[71];
1258
- const t30 = translating.length === 0 && "ml-auto";
1423
+ $[65] = data;
1424
+ $[66] = projectId;
1425
+ $[67] = publish;
1426
+ $[68] = ready;
1427
+ $[69] = translating.length;
1428
+ $[70] = t26;
1429
+ } else t26 = $[70];
1430
+ const t27 = translating.length === 0 && "ml-auto";
1431
+ let t28;
1432
+ if ($[71] !== t27) {
1433
+ t28 = cn(t27);
1434
+ $[71] = t27;
1435
+ $[72] = t28;
1436
+ } else t28 = $[72];
1437
+ const t29 = !ready || !!waiting;
1438
+ let t30;
1439
+ if ($[73] !== publish.isPending || $[74] !== waiting) {
1440
+ t30 = publish.isPending || waiting ? /* @__PURE__ */ jsx(Spinner, {}) : null;
1441
+ $[73] = publish.isPending;
1442
+ $[74] = waiting;
1443
+ $[75] = t30;
1444
+ } else t30 = $[75];
1259
1445
  let t31;
1260
- if ($[72] !== t30) {
1261
- t31 = cn(t30);
1262
- $[72] = t30;
1263
- $[73] = t31;
1264
- } else t31 = $[73];
1265
- const t32 = !ready || !!waiting;
1266
- let t33;
1267
- if ($[74] !== publish.isPending || $[75] !== waiting) {
1268
- t33 = publish.isPending || waiting ? /* @__PURE__ */ jsx(Spinner, {}) : null;
1269
- $[74] = publish.isPending;
1270
- $[75] = waiting;
1271
- $[76] = t33;
1272
- } else t33 = $[76];
1273
- let t34;
1274
- if ($[77] !== publishAll || $[78] !== t31 || $[79] !== t32 || $[80] !== t33) {
1275
- t34 = /* @__PURE__ */ jsxs(Button, {
1276
- className: t31,
1277
- disabled: t32,
1278
- onClick: publishAll,
1279
- children: [t33, "Publish all"]
1446
+ if ($[76] !== publishWhole || $[77] !== t28 || $[78] !== t29 || $[79] !== t30) {
1447
+ t31 = /* @__PURE__ */ jsxs(Button, {
1448
+ className: t28,
1449
+ disabled: t29,
1450
+ onClick: publishWhole,
1451
+ children: [t30, "Publish"]
1280
1452
  });
1281
- $[77] = publishAll;
1282
- $[78] = t31;
1283
- $[79] = t32;
1284
- $[80] = t33;
1285
- $[81] = t34;
1286
- } else t34 = $[81];
1287
- let t35;
1288
- if ($[82] !== t28 || $[83] !== t29 || $[84] !== t34) {
1289
- t35 = /* @__PURE__ */ jsxs("div", {
1290
- className: "flex items-center gap-2",
1291
- children: [
1292
- t28,
1293
- t29,
1294
- t34
1295
- ]
1296
- });
1297
- $[82] = t28;
1298
- $[83] = t29;
1299
- $[84] = t34;
1300
- $[85] = t35;
1301
- } else t35 = $[85];
1302
- let t36;
1303
- if ($[86] !== t24 || $[87] !== t25 || $[88] !== t35) {
1304
- t36 = /* @__PURE__ */ jsxs("div", {
1453
+ $[76] = publishWhole;
1454
+ $[77] = t28;
1455
+ $[78] = t29;
1456
+ $[79] = t30;
1457
+ $[80] = t31;
1458
+ } else t31 = $[80];
1459
+ let t32;
1460
+ if ($[81] !== t25 || $[82] !== t26 || $[83] !== t31) {
1461
+ t32 = /* @__PURE__ */ jsx("div", {
1305
1462
  className: "flex flex-col gap-3 border-t p-4",
1306
- children: [
1307
- t24,
1308
- t25,
1309
- t35
1310
- ]
1463
+ children: /* @__PURE__ */ jsxs("div", {
1464
+ className: "flex items-center gap-2",
1465
+ children: [
1466
+ t25,
1467
+ t26,
1468
+ t31
1469
+ ]
1470
+ })
1311
1471
  });
1312
- $[86] = t24;
1313
- $[87] = t25;
1314
- $[88] = t35;
1315
- $[89] = t36;
1316
- } else t36 = $[89];
1317
- let t37;
1318
- if ($[90] !== initialFocus || $[91] !== t22 || $[92] !== t23 || $[93] !== t36) {
1319
- t37 = /* @__PURE__ */ jsxs(SheetContent, {
1472
+ $[81] = t25;
1473
+ $[82] = t26;
1474
+ $[83] = t31;
1475
+ $[84] = t32;
1476
+ } else t32 = $[84];
1477
+ let t33;
1478
+ if ($[85] !== initialFocus || $[86] !== t21 || $[87] !== t22 || $[88] !== t32) {
1479
+ t33 = /* @__PURE__ */ jsxs(SheetContent, {
1320
1480
  ref: popup,
1321
1481
  initialFocus,
1322
1482
  side: "right",
1323
1483
  className: "w-full gap-0 data-[side=right]:sm:max-w-lg",
1324
1484
  children: [
1485
+ t21,
1325
1486
  t22,
1326
- t23,
1327
- t36
1487
+ t32
1328
1488
  ]
1329
1489
  });
1330
- $[90] = initialFocus;
1331
- $[91] = t22;
1332
- $[92] = t23;
1333
- $[93] = t36;
1334
- $[94] = t37;
1335
- } else t37 = $[94];
1336
- let t38;
1337
- if ($[95] !== onOpenChange || $[96] !== open || $[97] !== t37) {
1338
- t38 = /* @__PURE__ */ jsx(Sheet, {
1490
+ $[85] = initialFocus;
1491
+ $[86] = t21;
1492
+ $[87] = t22;
1493
+ $[88] = t32;
1494
+ $[89] = t33;
1495
+ } else t33 = $[89];
1496
+ let t34;
1497
+ if ($[90] !== onOpenChange || $[91] !== open || $[92] !== t33) {
1498
+ t34 = /* @__PURE__ */ jsx(Sheet, {
1339
1499
  open,
1340
1500
  onOpenChange,
1341
- children: t37
1501
+ children: t33
1342
1502
  });
1343
- $[95] = onOpenChange;
1344
- $[96] = open;
1345
- $[97] = t37;
1346
- $[98] = t38;
1347
- } else t38 = $[98];
1348
- let t39;
1349
- if ($[99] !== confirmingDiscard || $[100] !== leave || $[101] !== projectId) {
1350
- t39 = /* @__PURE__ */ jsx(DiscardDraftDialog, {
1503
+ $[90] = onOpenChange;
1504
+ $[91] = open;
1505
+ $[92] = t33;
1506
+ $[93] = t34;
1507
+ } else t34 = $[93];
1508
+ let t35;
1509
+ if ($[94] !== confirmingDiscard || $[95] !== leave || $[96] !== projectId) {
1510
+ t35 = /* @__PURE__ */ jsx(DiscardDraftDialog, {
1351
1511
  projectId,
1352
1512
  open: confirmingDiscard,
1353
1513
  onOpenChange: setConfirmingDiscard,
1354
1514
  onDiscarded: leave
1355
1515
  });
1356
- $[99] = confirmingDiscard;
1357
- $[100] = leave;
1358
- $[101] = projectId;
1359
- $[102] = t39;
1360
- } else t39 = $[102];
1361
- let t40;
1362
- if ($[103] !== t38 || $[104] !== t39) {
1363
- t40 = /* @__PURE__ */ jsxs(Fragment, { children: [t38, t39] });
1364
- $[103] = t38;
1365
- $[104] = t39;
1366
- $[105] = t40;
1367
- } else t40 = $[105];
1368
- return t40;
1516
+ $[94] = confirmingDiscard;
1517
+ $[95] = leave;
1518
+ $[96] = projectId;
1519
+ $[97] = t35;
1520
+ } else t35 = $[97];
1521
+ let t36;
1522
+ if ($[98] !== t34 || $[99] !== t35) {
1523
+ t36 = /* @__PURE__ */ jsxs(Fragment, { children: [t34, t35] });
1524
+ $[98] = t34;
1525
+ $[99] = t35;
1526
+ $[100] = t36;
1527
+ } else t36 = $[100];
1528
+ return t36;
1369
1529
  }
1370
1530
  /** Asks before discarding the draft the studio is in, then discards it. */
1371
1531
  function DiscardDraftDialog(t0) {
@@ -1385,7 +1545,7 @@ function DiscardDraftDialog(t0) {
1385
1545
  onOpenChange(false);
1386
1546
  onDiscarded(ended);
1387
1547
  },
1388
- onError: _temp8
1548
+ onError: _temp10
1389
1549
  };
1390
1550
  $[1] = onDiscarded;
1391
1551
  $[2] = onOpenChange;
@@ -1464,7 +1624,7 @@ function DiscardDraftDialog(t0) {
1464
1624
  } else t10 = $[25];
1465
1625
  return t10;
1466
1626
  }
1467
- function _temp8(error) {
1627
+ function _temp10(error) {
1468
1628
  return toast.error(error.message || "Could not discard the draft");
1469
1629
  }
1470
1630