camox 0.65.1 → 0.67.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.
Files changed (42) hide show
  1. package/dist/features/canvas/CamoxCanvas.js +195 -173
  2. package/dist/features/canvas/canvasFrameCapture.js +5 -12
  3. package/dist/features/canvas/canvasFrameDocument.js +90 -29
  4. package/dist/features/canvas/canvasItems.js +22 -6
  5. package/dist/features/canvas/sidebar/ContentSidebar.js +19 -21
  6. package/dist/features/canvas/sidebar/LayoutPageOverview.js +22 -49
  7. package/dist/features/canvas/sidebar/LayoutPageSeo.js +73 -76
  8. package/dist/features/canvas/sidebar/PageInspector.js +61 -50
  9. package/dist/features/canvas/sidebar/PageInspectorSkeleton.js +4 -4
  10. package/dist/features/canvas/useCanvasCamera.js +22 -5
  11. package/dist/features/content/components/MissingFromLocale.js +1 -1
  12. package/dist/features/page/UnplacedLayoutContent.js +141 -0
  13. package/dist/features/preview/components/ItemFieldsEditor.js +50 -44
  14. package/dist/features/preview/components/PageInfo.js +103 -100
  15. package/dist/features/preview/components/SelectionEditor.js +284 -231
  16. package/dist/features/preview/components/contentFieldSchema.js +5 -1
  17. package/dist/features/runtime/RuntimeChrome.js +66 -40
  18. package/dist/features/runtime/pageApp.js +24 -10
  19. package/dist/features/runtime/runtime.d.ts +13 -0
  20. package/dist/features/runtime/runtime.js +58 -2
  21. package/dist/features/studio/components/AgentSidebar.js +3 -3
  22. package/dist/features/studio/components/ChatWidget.js +34 -29
  23. package/dist/features/studio/components/ContentFindings.js +397 -0
  24. package/dist/features/studio/components/DraftsControl.js +172 -159
  25. package/dist/features/studio/components/Patrol.js +449 -426
  26. package/dist/features/studio/components/ReviewDraftSheet.js +231 -192
  27. package/dist/features/studio/components/Squareling.js +0 -9
  28. package/dist/features/studio/components/ThreadComposer.js +183 -121
  29. package/dist/features/studio/components/ThreadMessages.js +19 -11
  30. package/dist/features/studio/components/UnnamedDraftBar.js +349 -0
  31. package/dist/features/studio/findingSentence.js +3 -5
  32. package/dist/features/studio/patrollerBio.js +39 -0
  33. package/dist/features/studio/reportSentence.js +0 -5
  34. package/dist/features/studio/studioStore.js +13 -0
  35. package/dist/features/studio/workingSentence.js +2 -11
  36. package/dist/lib/revisions.js +25 -3
  37. package/dist/lib/use-thread.js +1 -1
  38. package/dist/package.js +1 -1
  39. package/dist/studio.css +1 -1
  40. package/package.json +4 -4
  41. package/dist/features/canvas/sidebar/DerivedPageInspector.js +0 -49
  42. package/dist/features/canvas/sidebar/SingletonPageInspector.js +0 -39
@@ -10,12 +10,12 @@ import { AssetLightbox } from "../../preview/components/AssetLightbox.js";
10
10
  import { BOTTOM_CARD_EDGES, CARD_BODY_EDGES } from "../../preview/components/SidebarStack.js";
11
11
  import { editCollectionItemPath } from "../routes.js";
12
12
  import { studioStore } from "../studioStore.js";
13
- import { timeAgo } from "../draftLabel.js";
14
13
  import { askAgentMessage, dismissLabel, dismissedSentence, findingSentence, fixLabel } from "../findingSentence.js";
15
14
  import { useShowInCanvas } from "../showInCanvas.js";
16
15
  import { Squareling } from "./Squareling.js";
16
+ import { aboutSentence, whenTag } from "../patrollerBio.js";
17
17
  import { moreSentence, reportSentence, shortTimeAgo, whereReportLeads } from "../reportSentence.js";
18
- import { singleLocaleSentence, workingSentence } from "../workingSentence.js";
18
+ import { workingSentence } from "../workingSentence.js";
19
19
  import { c } from "react/compiler-runtime";
20
20
  import * as React from "react";
21
21
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -59,7 +59,7 @@ function Patrol(t0) {
59
59
  children: "Patrol"
60
60
  })
61
61
  });
62
- t4 = cn("bg-background min-h-0 flex-1 overflow-y-auto", CARD_BODY_EDGES);
62
+ t4 = cn("bg-background flex min-h-0 flex-1 flex-col overflow-y-auto", CARD_BODY_EDGES);
63
63
  $[4] = t3;
64
64
  $[5] = t4;
65
65
  } else {
@@ -100,7 +100,7 @@ function Patrol(t0) {
100
100
  return t7;
101
101
  }
102
102
  function ProjectPatrol(t0) {
103
- const $ = c(53);
103
+ const $ = c(33);
104
104
  const { projectId, inDraft } = t0;
105
105
  let t1;
106
106
  if ($[0] !== projectId) {
@@ -118,203 +118,144 @@ function ProjectPatrol(t0) {
118
118
  const { data: locales } = useReadQuery(t2);
119
119
  const [open, setOpen] = React.useState(null);
120
120
  const now = useNow(3e4);
121
- const [heldOrder, setHeldOrder] = React.useState(null);
122
- const pointerIn = React.useRef(false);
123
- let t3;
124
- if ($[4] !== heldOrder || $[5] !== view) {
125
- t3 = view && inHeldOrder(view, heldOrder);
126
- $[4] = heldOrder;
127
- $[5] = view;
128
- $[6] = t3;
129
- } else t3 = $[6];
130
- const shown = t3;
131
- let t4;
132
- if ($[7] !== shown?.patrollers) {
133
- t4 = shown?.patrollers.map(_temp).join(" ");
134
- $[7] = shown?.patrollers;
135
- $[8] = t4;
136
- } else t4 = $[8];
137
- const roster = useMovingRows(t4);
138
121
  const [openFileId, setOpenFileId] = React.useState(null);
139
122
  const showReport = useShowReport(inDraft, setOpenFileId);
140
123
  const navigate = useNavigate();
141
- let t5;
142
- if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
143
- t5 = patrolMutations.applyFix();
144
- $[9] = t5;
145
- } else t5 = $[9];
146
- const applyFix = useMutation(t5);
124
+ let t3;
125
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
126
+ t3 = patrolMutations.applyFix();
127
+ $[4] = t3;
128
+ } else t3 = $[4];
129
+ const applyFix = useMutation(t3);
130
+ let t4;
131
+ if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
132
+ t4 = patrolMutations.dismissFinding();
133
+ $[5] = t4;
134
+ } else t4 = $[5];
135
+ const dismissFinding = useMutation(t4);
136
+ if (!view) return null;
137
+ const t5 = locales?.length === 1;
147
138
  let t6;
148
- if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
149
- t6 = patrolMutations.dismissFinding();
150
- $[10] = t6;
151
- } else t6 = $[10];
152
- const dismissFinding = useMutation(t6);
153
- if (!shown) return null;
154
- let t7;
155
- if ($[11] !== shown) {
156
- t7 = () => setHeldOrder((held) => held ?? shown.patrollers.map(_temp2));
157
- $[11] = shown;
158
- $[12] = t7;
159
- } else t7 = $[12];
160
- const hold = t7;
161
- let t8;
162
- if ($[13] !== hold) {
163
- t8 = (id_1) => {
164
- setOpen(id_1);
165
- if (id_1) hold();
166
- else if (!pointerIn.current) setHeldOrder(null);
167
- };
168
- $[13] = hold;
169
- $[14] = t8;
170
- } else t8 = $[14];
171
- const openReports = t8;
172
- let t9;
173
- if ($[15] !== hold) {
174
- t9 = () => {
175
- pointerIn.current = true;
176
- hold();
139
+ if ($[6] !== showReport) {
140
+ t6 = (shown) => {
141
+ setOpen(null);
142
+ showReport(shown);
177
143
  };
178
- $[15] = hold;
179
- $[16] = t9;
180
- } else t9 = $[16];
181
- let t10;
182
- if ($[17] !== open) {
183
- t10 = () => {
184
- pointerIn.current = false;
185
- if (!open) setHeldOrder(null);
186
- };
187
- $[17] = open;
188
- $[18] = t10;
189
- } else t10 = $[18];
190
- const t11 = locales?.length === 1;
191
- let t12;
192
- if ($[19] !== openReports || $[20] !== showReport) {
193
- t12 = (shown_0) => {
194
- openReports(null);
195
- showReport(shown_0);
196
- };
197
- $[19] = openReports;
198
- $[20] = showReport;
199
- $[21] = t12;
200
- } else t12 = $[21];
201
- let t13;
202
- if ($[22] !== applyFix || $[23] !== projectId) {
203
- t13 = (finding) => applyFix.mutate({
144
+ $[6] = showReport;
145
+ $[7] = t6;
146
+ } else t6 = $[7];
147
+ let t7;
148
+ if ($[8] !== applyFix || $[9] !== projectId) {
149
+ t7 = (finding) => applyFix.mutate({
204
150
  projectId,
205
151
  findingId: finding.id
206
152
  });
207
- $[22] = applyFix;
208
- $[23] = projectId;
209
- $[24] = t13;
210
- } else t13 = $[24];
211
- let t14;
212
- if ($[25] !== openReports) {
213
- t14 = (patroller, finding_0) => {
214
- openReports(null);
153
+ $[8] = applyFix;
154
+ $[9] = projectId;
155
+ $[10] = t7;
156
+ } else t7 = $[10];
157
+ let t8;
158
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
159
+ t8 = (patroller, finding_0) => {
160
+ setOpen(null);
215
161
  studioStore.trigger.askAgent({ text: askAgentMessage(finding_0, patroller.role) });
216
162
  };
217
- $[25] = openReports;
218
- $[26] = t14;
219
- } else t14 = $[26];
220
- let t15;
221
- if ($[27] !== dismissFinding || $[28] !== projectId) {
222
- t15 = (finding_1) => dismissFinding.mutate({
163
+ $[11] = t8;
164
+ } else t8 = $[11];
165
+ let t9;
166
+ if ($[12] !== dismissFinding || $[13] !== projectId) {
167
+ t9 = (finding_1) => dismissFinding.mutate({
223
168
  projectId,
224
169
  findingId: finding_1.id
225
170
  });
226
- $[27] = dismissFinding;
227
- $[28] = projectId;
228
- $[29] = t15;
229
- } else t15 = $[29];
230
- let t16;
231
- if ($[30] !== navigate || $[31] !== openReports) {
232
- t16 = (draft) => {
233
- openReports(null);
234
- navigate({
171
+ $[12] = dismissFinding;
172
+ $[13] = projectId;
173
+ $[14] = t9;
174
+ } else t9 = $[14];
175
+ let t10;
176
+ if ($[15] !== navigate || $[16] !== showReport) {
177
+ t10 = (draft, finding_2) => {
178
+ setOpen(null);
179
+ const kind = finding_2.place?.kind;
180
+ if (kind === "page" || kind === "record") showReport({
181
+ ...shownOfFinding(finding_2),
182
+ draft
183
+ });
184
+ else navigate({
235
185
  to: window.location.href,
236
186
  draft: draft.id
237
187
  });
238
188
  };
239
- $[30] = navigate;
240
- $[31] = openReports;
241
- $[32] = t16;
242
- } else t16 = $[32];
243
- let t17;
244
- if ($[33] !== inDraft || $[34] !== now || $[35] !== open || $[36] !== openReports || $[37] !== shown || $[38] !== t11 || $[39] !== t12 || $[40] !== t13 || $[41] !== t14 || $[42] !== t15 || $[43] !== t16) {
245
- t17 = /* @__PURE__ */ jsx(PatrolRoster, {
246
- view: shown,
189
+ $[15] = navigate;
190
+ $[16] = showReport;
191
+ $[17] = t10;
192
+ } else t10 = $[17];
193
+ let t11;
194
+ if ($[18] !== inDraft || $[19] !== now || $[20] !== open || $[21] !== t10 || $[22] !== t5 || $[23] !== t6 || $[24] !== t7 || $[25] !== t9 || $[26] !== view) {
195
+ t11 = /* @__PURE__ */ jsx(PatrolRoster, {
196
+ view,
247
197
  now,
248
198
  inDraft,
249
- singleLocale: t11,
199
+ singleLocale: t5,
250
200
  open,
251
- onOpenChange: openReports,
252
- onShow: t12,
253
- onApply: t13,
254
- onAsk: t14,
255
- onDismiss: t15,
256
- onOpenPatrolDraft: t16
201
+ onOpenChange: setOpen,
202
+ onShow: t6,
203
+ onApply: t7,
204
+ onAsk: t8,
205
+ onDismiss: t9,
206
+ onOpenPatrolDraft: t10
257
207
  });
258
- $[33] = inDraft;
259
- $[34] = now;
260
- $[35] = open;
261
- $[36] = openReports;
262
- $[37] = shown;
263
- $[38] = t11;
264
- $[39] = t12;
265
- $[40] = t13;
266
- $[41] = t14;
267
- $[42] = t15;
268
- $[43] = t16;
269
- $[44] = t17;
270
- } else t17 = $[44];
271
- let t18;
272
- if ($[45] !== openFileId) {
273
- t18 = openFileId && /* @__PURE__ */ jsx(AssetLightbox, {
208
+ $[18] = inDraft;
209
+ $[19] = now;
210
+ $[20] = open;
211
+ $[21] = t10;
212
+ $[22] = t5;
213
+ $[23] = t6;
214
+ $[24] = t7;
215
+ $[25] = t9;
216
+ $[26] = view;
217
+ $[27] = t11;
218
+ } else t11 = $[27];
219
+ let t12;
220
+ if ($[28] !== openFileId) {
221
+ t12 = openFileId && /* @__PURE__ */ jsx(AssetLightbox, {
274
222
  open: true,
275
223
  onOpenChange: (open_0) => {
276
224
  if (!open_0) setOpenFileId(null);
277
225
  },
278
226
  fileId: openFileId
279
227
  });
280
- $[45] = openFileId;
281
- $[46] = t18;
282
- } else t18 = $[46];
283
- let t19;
284
- if ($[47] !== roster || $[48] !== t10 || $[49] !== t17 || $[50] !== t18 || $[51] !== t9) {
285
- t19 = /* @__PURE__ */ jsxs("div", {
286
- ref: roster,
287
- className: "relative",
288
- onPointerEnter: t9,
289
- onPointerLeave: t10,
290
- children: [t17, t18]
291
- });
292
- $[47] = roster;
293
- $[48] = t10;
294
- $[49] = t17;
295
- $[50] = t18;
296
- $[51] = t9;
297
- $[52] = t19;
298
- } else t19 = $[52];
299
- return t19;
300
- }
301
- function _temp2(t0) {
302
- const { id: id_0 } = t0;
303
- return id_0;
304
- }
305
- function _temp(t0) {
306
- const { id } = t0;
307
- return id;
228
+ $[28] = openFileId;
229
+ $[29] = t12;
230
+ } else t12 = $[29];
231
+ let t13;
232
+ if ($[30] !== t11 || $[31] !== t12) {
233
+ t13 = /* @__PURE__ */ jsxs("div", { children: [t11, t12] });
234
+ $[30] = t11;
235
+ $[31] = t12;
236
+ $[32] = t13;
237
+ } else t13 = $[32];
238
+ return t13;
308
239
  }
309
240
  /** A report, as the Patrol shows its subject. */
310
241
  const shownOf = (report) => ({
311
242
  ...report,
312
243
  locale: reportLocale(report.summary)
313
244
  });
245
+ /** A finding, as the Patrol shows its subject: its field selected. */
246
+ const shownOfFinding = (finding) => ({
247
+ place: finding.place,
248
+ live: finding.live,
249
+ locale: finding.locale,
250
+ field: {
251
+ name: finding.field,
252
+ kind: finding.fieldKind
253
+ }
254
+ });
314
255
  /**
315
256
  * Shows a report's or a finding's subject where it is, in its locale, and on Live for a Live one
316
- * seen from a draft: a page, block or item selected on the Canvas, a record in its collection, or
317
- * a file, opened over the Canvas.
257
+ * seen from a draft, or in the draft it names: a page, block, item or field selected on the
258
+ * Canvas, a record in its collection, or a file, opened over the Canvas.
318
259
  */
319
260
  function useShowReport(inDraft, openFile) {
320
261
  const $ = c(6);
@@ -326,16 +267,18 @@ function useShowReport(inDraft, openFile) {
326
267
  t0 = (report) => {
327
268
  const { place } = report;
328
269
  if (!place) return;
329
- const toLive = inDraft && report.live ? { draft: null } : {};
270
+ const inScope = report.draft ? { draft: report.draft.id } : inDraft && report.live ? { draft: null } : {};
330
271
  const tag = report.locale;
331
272
  if (place.kind === "page") {
332
273
  const { pageId, blockId, itemId } = place;
274
+ const field = blockId ? report.field : null;
333
275
  showInCanvas({
334
276
  pageId,
335
277
  locale: tag,
336
278
  blockId,
337
279
  itemId,
338
- ...toLive
280
+ field,
281
+ ...inScope
339
282
  });
340
283
  return;
341
284
  }
@@ -344,7 +287,7 @@ function useShowReport(inDraft, openFile) {
344
287
  const path = editCollectionItemPath(place.collectionId, place.recordId);
345
288
  navigate({
346
289
  to: localizedPath(path, locale),
347
- ...toLive
290
+ ...inScope
348
291
  });
349
292
  return;
350
293
  }
@@ -363,70 +306,10 @@ function useShowReport(inDraft, openFile) {
363
306
  } else t0 = $[5];
364
307
  return t0;
365
308
  }
366
- /**
367
- * The view with its patrollers in the order held, if any, and its latest content: patrollers the
368
- * order doesn't hold follow, in the view's order, and those no longer in the view are dropped.
369
- */
370
- function inHeldOrder(view, order) {
371
- if (!order) return view;
372
- const place = (id) => {
373
- const index = order.indexOf(id);
374
- return index === -1 ? order.length : index;
375
- };
376
- return {
377
- ...view,
378
- patrollers: [...view.patrollers].sort((a, b) => place(a.id) - place(b.id))
379
- };
380
- }
381
- /** How long a patroller takes to move to its new place, in ms. */
382
- const MOVE_DURATION = 250;
383
- /** A strong ease-out: the move starts at once and settles gently. */
384
- const MOVE_EASING = "cubic-bezier(0.23, 1, 0.32, 1)";
385
- /**
386
- * Moves each patroller from where it showed to its new place when the order (a key of their ids)
387
- * changes, rather than jumping there. Without motion for editors who reduce it.
388
- */
389
- function useMovingRows(order) {
390
- const $ = c(2);
391
- const node = React.useRef(null);
392
- const last = React.useRef(null);
393
- let t0;
394
- if ($[0] !== order) {
395
- t0 = () => {
396
- const roster = node.current;
397
- if (!roster) return;
398
- const rows = [...roster.querySelectorAll("[data-patroller]")];
399
- const tops = new Map(rows.map(_temp3));
400
- const previous = last.current;
401
- last.current = {
402
- order,
403
- tops
404
- };
405
- if (!previous || previous.order === order) return;
406
- if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
407
- for (const row_0 of rows) {
408
- const from = previous.tops.get(row_0.dataset.patroller);
409
- const to = tops.get(row_0.dataset.patroller);
410
- if (from === void 0 || from === to) continue;
411
- row_0.animate([{ transform: `translateY(${from - to}px)` }, { transform: "none" }], {
412
- duration: MOVE_DURATION,
413
- easing: MOVE_EASING
414
- });
415
- }
416
- };
417
- $[0] = order;
418
- $[1] = t0;
419
- } else t0 = $[1];
420
- React.useLayoutEffect(t0);
421
- return node;
422
- }
423
- function _temp3(row) {
424
- return [row.dataset.patroller, row.offsetTop];
425
- }
426
309
  /** The time now, updated every `intervalMs`. */
427
310
  function useNow(intervalMs) {
428
311
  const $ = c(3);
429
- const [now, setNow] = React.useState(_temp4);
312
+ const [now, setNow] = React.useState(_temp);
430
313
  let t0;
431
314
  let t1;
432
315
  if ($[0] !== intervalMs) {
@@ -445,13 +328,14 @@ function useNow(intervalMs) {
445
328
  React.useEffect(t0, t1);
446
329
  return now;
447
330
  }
448
- function _temp4() {
331
+ function _temp() {
449
332
  return Date.now();
450
333
  }
451
334
  /**
452
- * A `PatrolView`, in the order it gives: each patroller's avatar, role, and when it last worked,
453
- * opening its reports in a popover to the left. Live's reports carry a tag when a draft is viewed. In a
454
- * project with a single locale, the Translator invites the editor to add a language instead.
335
+ * A `PatrolView`, in the order it gives, as avatars in rows of three, each over its role like a
336
+ * story. Each opens its reports in a popover to the left, under its role and when it last worked,
337
+ * or what it's on. Live's reports carry a tag when a draft is viewed. In a project with a single
338
+ * locale, the Translator invites the editor to add a language instead.
455
339
  */
456
340
  function PatrolRoster(t0) {
457
341
  const $ = c(27);
@@ -464,7 +348,7 @@ function PatrolRoster(t0) {
464
348
  patroller,
465
349
  now,
466
350
  inDraft,
467
- idle: singleLocale ? singleLocaleSentence(patroller.id) : void 0,
351
+ singleLocale,
468
352
  open: open === patroller.id,
469
353
  onOpenChange: (next) => onOpenChange(next ? patroller.id : null),
470
354
  onShow,
@@ -504,9 +388,12 @@ function PatrolRoster(t0) {
504
388
  } else t1 = $[12];
505
389
  let t2;
506
390
  if ($[25] !== t1) {
507
- t2 = /* @__PURE__ */ jsx("ul", {
508
- className: "flex flex-col gap-px p-1",
509
- children: t1
391
+ t2 = /* @__PURE__ */ jsx("div", {
392
+ className: "px-1 py-3",
393
+ children: /* @__PURE__ */ jsx("ul", {
394
+ className: "mx-auto grid w-fit grid-cols-[repeat(3,5rem)] gap-y-3.5",
395
+ children: t1
396
+ })
510
397
  });
511
398
  $[25] = t1;
512
399
  $[26] = t2;
@@ -514,8 +401,8 @@ function PatrolRoster(t0) {
514
401
  return t2;
515
402
  }
516
403
  /**
517
- * A thin, low-contrast arc travelling around a working patroller's avatar circle, or the whole
518
- * circle pulsing slowly under reduced motion. The motion lives in `studio.css`.
404
+ * A thin, low-contrast arc travelling around a working patroller's avatar, where its story ring
405
+ * goes, or the whole ring pulsing slowly under reduced motion. The motion lives in `studio.css`.
519
406
  */
520
407
  function WorkingArc() {
521
408
  const $ = c(1);
@@ -524,12 +411,12 @@ function WorkingArc() {
524
411
  t0 = /* @__PURE__ */ jsx("svg", {
525
412
  "data-working-indicator": true,
526
413
  "aria-hidden": true,
527
- viewBox: "0 0 32 32",
528
- className: "patrol-working text-foreground/30 pointer-events-none absolute inset-0 size-full",
414
+ viewBox: "0 0 36 36",
415
+ className: "patrol-working text-foreground/40 pointer-events-none absolute -inset-[3px] size-[calc(100%+6px)]",
529
416
  children: /* @__PURE__ */ jsx("circle", {
530
- cx: "16",
531
- cy: "16",
532
- r: "15.25",
417
+ cx: "18",
418
+ cy: "18",
419
+ r: "17.25",
533
420
  pathLength: "100",
534
421
  fill: "none",
535
422
  stroke: "currentColor",
@@ -543,8 +430,8 @@ function WorkingArc() {
543
430
  return t0;
544
431
  }
545
432
  function PatrollerRow(t0) {
546
- const $ = c(65);
547
- const { patroller, now, inDraft, idle, open, onOpenChange, onShow, onApply, onAsk, onDismiss, patrolDraft, onOpenPatrolDraft } = t0;
433
+ const $ = c(53);
434
+ const { patroller, now, inDraft, singleLocale, open, onOpenChange, onShow, onApply, onAsk, onDismiss, patrolDraft, onOpenPatrolDraft } = t0;
548
435
  const statusId = React.useId();
549
436
  let t1;
550
437
  if ($[0] !== patroller.id || $[1] !== patroller.working) {
@@ -554,209 +441,345 @@ function PatrollerRow(t0) {
554
441
  $[2] = t1;
555
442
  } else t1 = $[2];
556
443
  const working = t1;
557
- let t2;
558
- if ($[3] !== idle || $[4] !== now || $[5] !== patroller.duty || $[6] !== patroller.lastActivityAt || $[7] !== working) {
559
- t2 = working ?? idle ?? (patroller.duty === "atPublish" ? "Checks when you publish" : void 0) ?? (patroller.lastActivityAt === null ? "" : timeAgo(patroller.lastActivityAt, now));
560
- $[3] = idle;
561
- $[4] = now;
562
- $[5] = patroller.duty;
563
- $[6] = patroller.lastActivityAt;
564
- $[7] = working;
565
- $[8] = t2;
566
- } else t2 = $[8];
567
- const subtitle = t2;
568
444
  const count = patroller.findings.length;
569
- const t3 = open || void 0;
570
- const t4 = working ? statusId : void 0;
571
- const t5 = working ? "working" : patroller.duty === "off" ? "asleep" : "idle";
572
- let t6;
573
- if ($[9] !== patroller.id || $[10] !== t5) {
574
- t6 = /* @__PURE__ */ jsx(Squareling, {
575
- variant: patroller.id,
576
- status: t5,
577
- className: "size-5"
445
+ const t2 = open || void 0;
446
+ const t3 = working ? statusId : void 0;
447
+ let t4;
448
+ if ($[3] !== count || $[4] !== working) {
449
+ t4 = !working && /* @__PURE__ */ jsx("span", {
450
+ "aria-hidden": true,
451
+ className: cn("group-focus-visible/patroller:ring-ring/50 pointer-events-none absolute -inset-[3px] rounded-full border group-focus-visible/patroller:ring-[3px]", count > 0 ? "border-foreground border-[1.5px]" : "border-border")
578
452
  });
579
- $[9] = patroller.id;
580
- $[10] = t5;
581
- $[11] = t6;
582
- } else t6 = $[11];
453
+ $[3] = count;
454
+ $[4] = working;
455
+ $[5] = t4;
456
+ } else t4 = $[5];
457
+ let t5;
458
+ if ($[6] !== working) {
459
+ t5 = working && /* @__PURE__ */ jsx(WorkingArc, {});
460
+ $[6] = working;
461
+ $[7] = t5;
462
+ } else t5 = $[7];
463
+ const t6 = working ? "working" : patroller.duty === "off" ? "asleep" : "idle";
583
464
  let t7;
584
- if ($[12] !== working) {
585
- t7 = working && /* @__PURE__ */ jsx(WorkingArc, {});
586
- $[12] = working;
587
- $[13] = t7;
588
- } else t7 = $[13];
465
+ if ($[8] !== patroller.id || $[9] !== t6) {
466
+ t7 = /* @__PURE__ */ jsx("span", {
467
+ className: "bg-muted group-hover/patroller:bg-muted-foreground/15 group-data-popup-open/patroller:bg-muted-foreground/15 flex size-full items-center justify-center rounded-full transition-colors",
468
+ children: /* @__PURE__ */ jsx(Squareling, {
469
+ variant: patroller.id,
470
+ status: t6,
471
+ className: "size-6"
472
+ })
473
+ });
474
+ $[8] = patroller.id;
475
+ $[9] = t6;
476
+ $[10] = t7;
477
+ } else t7 = $[10];
589
478
  let t8;
590
- if ($[14] !== t6 || $[15] !== t7) {
591
- t8 = /* @__PURE__ */ jsxs("span", {
592
- className: "bg-muted relative flex size-8 shrink-0 items-center justify-center rounded-full",
593
- children: [t6, t7]
479
+ if ($[11] !== count) {
480
+ t8 = count > 0 && /* @__PURE__ */ jsx("span", {
481
+ "data-findings-count": true,
482
+ "aria-label": `${count} open ${count === 1 ? "finding" : "findings"}`,
483
+ className: "bg-foreground text-background ring-background absolute -top-1.5 -right-1.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium tabular-nums ring-2",
484
+ children: count
485
+ });
486
+ $[11] = count;
487
+ $[12] = t8;
488
+ } else t8 = $[12];
489
+ let t9;
490
+ if ($[13] !== t4 || $[14] !== t5 || $[15] !== t7 || $[16] !== t8) {
491
+ t9 = /* @__PURE__ */ jsxs("span", {
492
+ className: "relative flex size-10 shrink-0 transition-[scale] duration-200 ease-out group-hover/patroller:scale-105 group-active/patroller:scale-95 motion-reduce:transition-none",
493
+ children: [
494
+ t4,
495
+ t5,
496
+ t7,
497
+ t8
498
+ ]
594
499
  });
595
- $[14] = t6;
500
+ $[13] = t4;
501
+ $[14] = t5;
596
502
  $[15] = t7;
597
503
  $[16] = t8;
598
- } else t8 = $[16];
599
- let t9;
600
- if ($[17] !== patroller.role) {
601
- t9 = /* @__PURE__ */ jsx("span", {
504
+ $[17] = t9;
505
+ } else t9 = $[17];
506
+ let t10;
507
+ if ($[18] !== patroller.role) {
508
+ t10 = /* @__PURE__ */ jsx("span", {
602
509
  "data-patroller-role": true,
603
- className: "truncate text-sm font-medium",
510
+ className: "max-w-full truncate text-[11px] leading-4 font-medium",
604
511
  children: patroller.role
605
512
  });
606
- $[17] = patroller.role;
607
- $[18] = t9;
608
- } else t9 = $[18];
609
- const t10 = working ? true : void 0;
513
+ $[18] = patroller.role;
514
+ $[19] = t10;
515
+ } else t10 = $[19];
610
516
  let t11;
611
- if ($[19] !== subtitle || $[20] !== t10) {
612
- t11 = /* @__PURE__ */ jsx("span", {
613
- "data-patroller-subtitle": true,
614
- "aria-hidden": t10,
615
- className: "text-muted-foreground truncate text-xs",
616
- children: subtitle
517
+ if ($[20] !== t10 || $[21] !== t3 || $[22] !== t9) {
518
+ t11 = /* @__PURE__ */ jsxs(PopoverTrigger, {
519
+ "aria-describedby": t3,
520
+ className: "group/patroller flex max-w-full min-w-0 cursor-pointer flex-col items-center gap-1 pt-[3px] outline-none",
521
+ children: [t9, t10]
617
522
  });
618
- $[19] = subtitle;
619
523
  $[20] = t10;
620
- $[21] = t11;
621
- } else t11 = $[21];
524
+ $[21] = t3;
525
+ $[22] = t9;
526
+ $[23] = t11;
527
+ } else t11 = $[23];
622
528
  let t12;
623
- if ($[22] !== t11 || $[23] !== t9) {
624
- t12 = /* @__PURE__ */ jsxs("span", {
625
- className: "flex min-w-0 flex-col",
626
- children: [t9, t11]
627
- });
628
- $[22] = t11;
629
- $[23] = t9;
630
- $[24] = t12;
631
- } else t12 = $[24];
529
+ if ($[24] !== onAsk || $[25] !== patroller) {
530
+ t12 = (finding) => onAsk(patroller, finding);
531
+ $[24] = onAsk;
532
+ $[25] = patroller;
533
+ $[26] = t12;
534
+ } else t12 = $[26];
632
535
  let t13;
633
- if ($[25] !== count) {
634
- t13 = count > 0 && /* @__PURE__ */ jsx("span", {
635
- "data-findings-count": true,
636
- "aria-label": `${count} open ${count === 1 ? "finding" : "findings"}`,
637
- className: "bg-foreground text-background ml-auto flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 text-xs font-medium tabular-nums",
638
- children: count
536
+ if ($[27] !== inDraft || $[28] !== now || $[29] !== onApply || $[30] !== onDismiss || $[31] !== onOpenPatrolDraft || $[32] !== onShow || $[33] !== patrolDraft || $[34] !== patroller || $[35] !== singleLocale || $[36] !== t12) {
537
+ t13 = /* @__PURE__ */ jsx(PopoverContent, {
538
+ sideOffset: 8,
539
+ className: "w-96 gap-3 p-4",
540
+ children: /* @__PURE__ */ jsx(PatrollerCard, {
541
+ patroller,
542
+ now,
543
+ inDraft,
544
+ singleLocale,
545
+ onShow,
546
+ onApply,
547
+ onAsk: t12,
548
+ onDismiss,
549
+ patrolDraft,
550
+ onOpenPatrolDraft
551
+ })
639
552
  });
640
- $[25] = count;
641
- $[26] = t13;
642
- } else t13 = $[26];
553
+ $[27] = inDraft;
554
+ $[28] = now;
555
+ $[29] = onApply;
556
+ $[30] = onDismiss;
557
+ $[31] = onOpenPatrolDraft;
558
+ $[32] = onShow;
559
+ $[33] = patrolDraft;
560
+ $[34] = patroller;
561
+ $[35] = singleLocale;
562
+ $[36] = t12;
563
+ $[37] = t13;
564
+ } else t13 = $[37];
643
565
  let t14;
644
- if ($[27] !== t12 || $[28] !== t13 || $[29] !== t4 || $[30] !== t8) {
645
- t14 = /* @__PURE__ */ jsxs(PopoverTrigger, {
646
- "aria-describedby": t4,
647
- className: "hover:bg-muted/60 data-popup-open:bg-muted/60 focus-visible:ring-ring/50 flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 text-left outline-none focus-visible:ring-[3px]",
648
- children: [
649
- t8,
650
- t12,
651
- t13
652
- ]
653
- });
654
- $[27] = t12;
655
- $[28] = t13;
656
- $[29] = t4;
657
- $[30] = t8;
658
- $[31] = t14;
659
- } else t14 = $[31];
660
- let t15;
661
- if ($[32] !== patroller.role) {
662
- t15 = /* @__PURE__ */ jsx(PopoverTitle, {
663
- className: "text-sm",
664
- children: patroller.role
665
- });
666
- $[32] = patroller.role;
667
- $[33] = t15;
668
- } else t15 = $[33];
669
- let t16;
670
- if ($[34] !== onAsk || $[35] !== patroller) {
671
- t16 = (finding) => onAsk(patroller, finding);
672
- $[34] = onAsk;
673
- $[35] = patroller;
674
- $[36] = t16;
675
- } else t16 = $[36];
676
- let t17;
677
- if ($[37] !== inDraft || $[38] !== now || $[39] !== onApply || $[40] !== onDismiss || $[41] !== onOpenPatrolDraft || $[42] !== onShow || $[43] !== patrolDraft || $[44] !== patroller || $[45] !== t16) {
678
- t17 = /* @__PURE__ */ jsx(PatrollerDetails, {
679
- patroller,
680
- now,
681
- inDraft,
682
- onShow,
683
- onApply,
684
- onAsk: t16,
685
- onDismiss,
686
- patrolDraft,
687
- onOpenPatrolDraft
688
- });
689
- $[37] = inDraft;
690
- $[38] = now;
691
- $[39] = onApply;
692
- $[40] = onDismiss;
693
- $[41] = onOpenPatrolDraft;
694
- $[42] = onShow;
695
- $[43] = patrolDraft;
696
- $[44] = patroller;
697
- $[45] = t16;
698
- $[46] = t17;
699
- } else t17 = $[46];
700
- let t18;
701
- if ($[47] !== t15 || $[48] !== t17) {
702
- t18 = /* @__PURE__ */ jsxs(PopoverContent, {
703
- side: "left",
704
- align: "start",
705
- sideOffset: 12,
706
- className: "w-80 gap-2 p-3",
707
- children: [t15, t17]
708
- });
709
- $[47] = t15;
710
- $[48] = t17;
711
- $[49] = t18;
712
- } else t18 = $[49];
713
- let t19;
714
- if ($[50] !== onOpenChange || $[51] !== open || $[52] !== t14 || $[53] !== t18) {
715
- t19 = /* @__PURE__ */ jsxs(Popover, {
566
+ if ($[38] !== onOpenChange || $[39] !== open || $[40] !== t11 || $[41] !== t13) {
567
+ t14 = /* @__PURE__ */ jsxs(Popover, {
716
568
  open,
717
569
  onOpenChange,
718
- children: [t14, t18]
570
+ children: [t11, t13]
719
571
  });
720
- $[50] = onOpenChange;
721
- $[51] = open;
722
- $[52] = t14;
723
- $[53] = t18;
724
- $[54] = t19;
725
- } else t19 = $[54];
726
- let t20;
727
- if ($[55] !== working) {
728
- t20 = working && `Working: ${working.charAt(0).toLowerCase()}${working.slice(1)}`;
729
- $[55] = working;
730
- $[56] = t20;
731
- } else t20 = $[56];
732
- let t21;
733
- if ($[57] !== statusId || $[58] !== t20) {
734
- t21 = /* @__PURE__ */ jsx("span", {
572
+ $[38] = onOpenChange;
573
+ $[39] = open;
574
+ $[40] = t11;
575
+ $[41] = t13;
576
+ $[42] = t14;
577
+ } else t14 = $[42];
578
+ let t15;
579
+ if ($[43] !== working) {
580
+ t15 = working && `Working: ${working.charAt(0).toLowerCase()}${working.slice(1)}`;
581
+ $[43] = working;
582
+ $[44] = t15;
583
+ } else t15 = $[44];
584
+ let t16;
585
+ if ($[45] !== statusId || $[46] !== t15) {
586
+ t16 = /* @__PURE__ */ jsx("span", {
735
587
  id: statusId,
736
588
  "data-working-status": true,
737
589
  role: "status",
738
590
  className: "sr-only",
739
- children: t20
591
+ children: t15
740
592
  });
741
- $[57] = statusId;
742
- $[58] = t20;
743
- $[59] = t21;
744
- } else t21 = $[59];
745
- let t22;
746
- if ($[60] !== patroller.id || $[61] !== t19 || $[62] !== t21 || $[63] !== t3) {
747
- t22 = /* @__PURE__ */ jsxs("li", {
593
+ $[45] = statusId;
594
+ $[46] = t15;
595
+ $[47] = t16;
596
+ } else t16 = $[47];
597
+ let t17;
598
+ if ($[48] !== patroller.id || $[49] !== t14 || $[50] !== t16 || $[51] !== t2) {
599
+ t17 = /* @__PURE__ */ jsxs("li", {
748
600
  "data-patroller": patroller.id,
749
- "data-open": t3,
750
- className: "flex flex-col",
751
- children: [t19, t21]
601
+ "data-open": t2,
602
+ className: "flex justify-center",
603
+ children: [t14, t16]
752
604
  });
753
- $[60] = patroller.id;
754
- $[61] = t19;
755
- $[62] = t21;
756
- $[63] = t3;
757
- $[64] = t22;
758
- } else t22 = $[64];
759
- return t22;
605
+ $[48] = patroller.id;
606
+ $[49] = t14;
607
+ $[50] = t16;
608
+ $[51] = t2;
609
+ $[52] = t17;
610
+ } else t17 = $[52];
611
+ return t17;
612
+ }
613
+ /**
614
+ * A patroller's popover, a profile card: its avatar and role, a tag of when it works where the
615
+ * editor is over what it does, what it's on while it works, then what it did.
616
+ */
617
+ function PatrollerCard(t0) {
618
+ const $ = c(47);
619
+ let props;
620
+ let singleLocale;
621
+ if ($[0] !== t0) {
622
+ ({singleLocale, ...props} = t0);
623
+ $[0] = t0;
624
+ $[1] = props;
625
+ $[2] = singleLocale;
626
+ } else {
627
+ props = $[1];
628
+ singleLocale = $[2];
629
+ }
630
+ const { patroller, inDraft } = props;
631
+ let t1;
632
+ if ($[3] !== patroller.id || $[4] !== patroller.working) {
633
+ t1 = patroller.working && workingSentence(patroller.id, patroller.working);
634
+ $[3] = patroller.id;
635
+ $[4] = patroller.working;
636
+ $[5] = t1;
637
+ } else t1 = $[5];
638
+ const working = t1;
639
+ let t2;
640
+ if ($[6] !== inDraft || $[7] !== patroller.duty || $[8] !== patroller.id || $[9] !== singleLocale) {
641
+ t2 = whenTag(patroller.id, patroller.duty, inDraft, singleLocale);
642
+ $[6] = inDraft;
643
+ $[7] = patroller.duty;
644
+ $[8] = patroller.id;
645
+ $[9] = singleLocale;
646
+ $[10] = t2;
647
+ } else t2 = $[10];
648
+ const when = t2;
649
+ const t3 = working ? "working" : patroller.duty === "off" ? "asleep" : "idle";
650
+ let t4;
651
+ if ($[11] !== patroller.id || $[12] !== t3) {
652
+ t4 = /* @__PURE__ */ jsx(Squareling, {
653
+ variant: patroller.id,
654
+ status: t3,
655
+ className: "size-7"
656
+ });
657
+ $[11] = patroller.id;
658
+ $[12] = t3;
659
+ $[13] = t4;
660
+ } else t4 = $[13];
661
+ let t5;
662
+ if ($[14] !== working) {
663
+ t5 = working && /* @__PURE__ */ jsx(WorkingArc, {});
664
+ $[14] = working;
665
+ $[15] = t5;
666
+ } else t5 = $[15];
667
+ let t6;
668
+ if ($[16] !== t4 || $[17] !== t5) {
669
+ t6 = /* @__PURE__ */ jsxs("span", {
670
+ className: "bg-muted relative flex size-12 shrink-0 items-center justify-center rounded-full",
671
+ children: [t4, t5]
672
+ });
673
+ $[16] = t4;
674
+ $[17] = t5;
675
+ $[18] = t6;
676
+ } else t6 = $[18];
677
+ let t7;
678
+ if ($[19] !== patroller.role) {
679
+ t7 = /* @__PURE__ */ jsx(PopoverTitle, {
680
+ className: "min-w-0 text-base",
681
+ children: patroller.role
682
+ });
683
+ $[19] = patroller.role;
684
+ $[20] = t7;
685
+ } else t7 = $[20];
686
+ let t8;
687
+ if ($[21] !== t6 || $[22] !== t7) {
688
+ t8 = /* @__PURE__ */ jsxs("header", {
689
+ className: "flex items-center gap-3",
690
+ children: [t6, t7]
691
+ });
692
+ $[21] = t6;
693
+ $[22] = t7;
694
+ $[23] = t8;
695
+ } else t8 = $[23];
696
+ const t9 = when.runs ? "bg-emerald-500" : "bg-muted-foreground/40";
697
+ let t10;
698
+ if ($[24] !== t9) {
699
+ t10 = cn("size-1.5 rounded-full", t9);
700
+ $[24] = t9;
701
+ $[25] = t10;
702
+ } else t10 = $[25];
703
+ let t11;
704
+ if ($[26] !== t10) {
705
+ t11 = /* @__PURE__ */ jsx("span", {
706
+ "aria-hidden": true,
707
+ className: t10
708
+ });
709
+ $[26] = t10;
710
+ $[27] = t11;
711
+ } else t11 = $[27];
712
+ let t12;
713
+ if ($[28] !== t11 || $[29] !== when.label) {
714
+ t12 = /* @__PURE__ */ jsxs("span", {
715
+ "data-patroller-when": true,
716
+ className: "bg-muted text-muted-foreground inline-flex items-center gap-1.5 rounded-full py-0.5 pr-2.5 pl-2 text-xs font-medium",
717
+ children: [t11, when.label]
718
+ });
719
+ $[28] = t11;
720
+ $[29] = when.label;
721
+ $[30] = t12;
722
+ } else t12 = $[30];
723
+ let t13;
724
+ if ($[31] !== patroller.id) {
725
+ t13 = aboutSentence(patroller.id);
726
+ $[31] = patroller.id;
727
+ $[32] = t13;
728
+ } else t13 = $[32];
729
+ let t14;
730
+ if ($[33] !== t13) {
731
+ t14 = /* @__PURE__ */ jsx("p", {
732
+ "data-patroller-about": true,
733
+ className: "text-sm",
734
+ children: t13
735
+ });
736
+ $[33] = t13;
737
+ $[34] = t14;
738
+ } else t14 = $[34];
739
+ let t15;
740
+ if ($[35] !== t12 || $[36] !== t14) {
741
+ t15 = /* @__PURE__ */ jsxs("div", {
742
+ className: "flex flex-col items-start gap-1.5",
743
+ children: [t12, t14]
744
+ });
745
+ $[35] = t12;
746
+ $[36] = t14;
747
+ $[37] = t15;
748
+ } else t15 = $[37];
749
+ let t16;
750
+ if ($[38] !== working) {
751
+ t16 = working && /* @__PURE__ */ jsx("p", {
752
+ "data-patroller-working": true,
753
+ className: "bg-muted rounded-md px-2.5 py-1.5 text-xs",
754
+ children: working
755
+ });
756
+ $[38] = working;
757
+ $[39] = t16;
758
+ } else t16 = $[39];
759
+ let t17;
760
+ if ($[40] !== props) {
761
+ t17 = /* @__PURE__ */ jsx("div", {
762
+ className: "flex flex-col gap-2 border-t pt-3",
763
+ children: /* @__PURE__ */ jsx(PatrollerDetails, { ...props })
764
+ });
765
+ $[40] = props;
766
+ $[41] = t17;
767
+ } else t17 = $[41];
768
+ let t18;
769
+ if ($[42] !== t15 || $[43] !== t16 || $[44] !== t17 || $[45] !== t8) {
770
+ t18 = /* @__PURE__ */ jsxs(Fragment, { children: [
771
+ t8,
772
+ t15,
773
+ t16,
774
+ t17
775
+ ] });
776
+ $[42] = t15;
777
+ $[43] = t16;
778
+ $[44] = t17;
779
+ $[45] = t8;
780
+ $[46] = t18;
781
+ } else t18 = $[46];
782
+ return t18;
760
783
  }
761
784
  /**
762
785
  * What a patroller's popover shows: its open findings with their actions, then its reports, then
@@ -790,7 +813,7 @@ function PatrollerDetails(t0) {
790
813
  finding.place && /* @__PURE__ */ jsx(Button, {
791
814
  variant: "outline",
792
815
  size: "xs",
793
- onClick: () => onShow(finding),
816
+ onClick: () => onShow(shownOfFinding(finding)),
794
817
  children: "Show"
795
818
  }),
796
819
  finding.fix && !finding.live && /* @__PURE__ */ jsx(Button, {
@@ -808,7 +831,7 @@ function PatrollerDetails(t0) {
808
831
  !inDraft && patrolDraft && /* @__PURE__ */ jsx(Button, {
809
832
  variant: "outline",
810
833
  size: "xs",
811
- onClick: () => onOpenPatrolDraft(patrolDraft),
834
+ onClick: () => onOpenPatrolDraft(patrolDraft, finding),
812
835
  children: "Open the Patrol Draft"
813
836
  }),
814
837
  /* @__PURE__ */ jsx(Button, {
@@ -1026,4 +1049,4 @@ function ReportSentence(t0) {
1026
1049
  }
1027
1050
 
1028
1051
  //#endregion
1029
- export { Patrol, PatrolRoster, PatrollerDetails, PatrollerReports, inHeldOrder };
1052
+ export { Patrol, PatrolRoster, PatrollerCard, PatrollerDetails, PatrollerReports };