camox 0.62.0 → 0.65.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.
- package/dist/core/createApp.d.ts +28 -28
- package/dist/core/createLayout.d.ts +1 -1
- package/dist/core/derivedRoutes.js +3 -30
- package/dist/core/editing/createEditableBlock.d.ts +604 -604
- package/dist/features/canvas/canvasCamera.js +11 -2
- package/dist/features/canvas/useCanvasCamera.js +14 -10
- package/dist/features/page/CuratedPageContent.js +2 -1
- package/dist/features/page/UnplacedBlockContent.js +52 -0
- package/dist/features/preview/components/PreviewPanel.js +40 -12
- package/dist/features/preview/components/SidebarStack.js +78 -9
- package/dist/features/preview/strayCaretGuard.js +34 -0
- package/dist/features/provider/CoreCamoxProvider.js +5 -3
- package/dist/features/routes/pageRuntime.d.ts +2 -0
- package/dist/features/routes/pageRuntime.js +8 -5
- package/dist/features/runtime/pageApp.js +111 -74
- package/dist/features/runtime/pageClient.js +22 -2
- package/dist/features/runtime/runtime.d.ts +10 -0
- package/dist/features/runtime/runtime.js +314 -4
- package/dist/features/runtime/runtimeRoutes.d.ts +5 -0
- package/dist/features/runtime/runtimeRoutes.js +5 -0
- package/dist/features/studio/components/ChatWidget.js +88 -62
- package/dist/features/studio/components/ConnectAgent.js +313 -0
- package/dist/features/studio/components/Patrol.js +455 -205
- package/dist/features/studio/components/ReviewDraftSheet.js +431 -334
- package/dist/features/studio/components/Squareling.js +74 -41
- package/dist/features/studio/components/ThreadComposer.js +130 -107
- package/dist/features/studio/components/ThreadMessages.js +136 -30
- package/dist/features/studio/components/clientLogoPaths.js +10 -0
- package/dist/features/studio/findingSentence.js +37 -0
- package/dist/features/studio/reportSentence.js +15 -0
- package/dist/features/studio/studioStore.js +23 -1
- package/dist/features/studio/workingSentence.js +8 -0
- package/dist/lib/api-client.d.ts +1 -0
- package/dist/lib/auth.js +34 -32
- package/dist/lib/locale-path.js +1 -7
- package/dist/lib/queries.js +9 -1
- package/dist/lib/server-auth-cookie.js +17 -4
- package/dist/lib/studio-reads.d.ts +1 -1
- package/dist/lib/studio-reads.js +5 -1
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +16 -5
|
@@ -3,7 +3,7 @@ import { Squareling } from "./Squareling.js";
|
|
|
3
3
|
import { ThreadMarkdown } from "./ThreadMarkdown.js";
|
|
4
4
|
import { c } from "react/compiler-runtime";
|
|
5
5
|
import * as React from "react";
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { Avatar, AvatarFallback, AvatarImage } from "@camox/ui/avatar";
|
|
8
8
|
import { Bubble, BubbleContent } from "@camox/ui/bubble";
|
|
9
9
|
import { Message, MessageAvatar, MessageContent, MessageHeader } from "@camox/ui/message";
|
|
@@ -274,6 +274,7 @@ const SQUARELING_STATUSES = {
|
|
|
274
274
|
exploring: "exploring",
|
|
275
275
|
changing: "changing",
|
|
276
276
|
building: "building",
|
|
277
|
+
checking: "checking",
|
|
277
278
|
fixing: "fixing",
|
|
278
279
|
startingDraft: "changing"
|
|
279
280
|
};
|
|
@@ -282,6 +283,7 @@ const ACTIVITY_LINES = {
|
|
|
282
283
|
exploring: "Looking around…",
|
|
283
284
|
changing: "Making changes…",
|
|
284
285
|
building: "Building…",
|
|
286
|
+
checking: "Checking the design…",
|
|
285
287
|
fixing: "Fixing the build…",
|
|
286
288
|
startingDraft: "Starting a draft…"
|
|
287
289
|
};
|
|
@@ -292,7 +294,7 @@ const PUSH_OUTCOMES = {
|
|
|
292
294
|
notPreviewed: "Built, but the preview can’t show it."
|
|
293
295
|
};
|
|
294
296
|
function ThreadMessageRow(t0) {
|
|
295
|
-
const $ = c(
|
|
297
|
+
const $ = c(44);
|
|
296
298
|
const { message, onOpenDraft } = t0;
|
|
297
299
|
if (message.from === "draft") {
|
|
298
300
|
let t1;
|
|
@@ -399,60 +401,88 @@ function ThreadMessageRow(t0) {
|
|
|
399
401
|
} else t10 = $[25];
|
|
400
402
|
return t10;
|
|
401
403
|
}
|
|
404
|
+
if (message.from === "connectedAgent") {
|
|
405
|
+
const { member, client } = message;
|
|
406
|
+
const t1 = client.verified ? void 0 : client.name;
|
|
407
|
+
const t2 = `${member.name}’s ${client.verified ? client.name : "agent"}`;
|
|
408
|
+
let t3;
|
|
409
|
+
if ($[26] !== t1 || $[27] !== t2) {
|
|
410
|
+
t3 = /* @__PURE__ */ jsx(MessageHeader, {
|
|
411
|
+
className: "text-muted-foreground text-xs",
|
|
412
|
+
title: t1,
|
|
413
|
+
children: t2
|
|
414
|
+
});
|
|
415
|
+
$[26] = t1;
|
|
416
|
+
$[27] = t2;
|
|
417
|
+
$[28] = t3;
|
|
418
|
+
} else t3 = $[28];
|
|
419
|
+
let t4;
|
|
420
|
+
if ($[29] !== message.text) {
|
|
421
|
+
t4 = /* @__PURE__ */ jsx(Bubble, {
|
|
422
|
+
variant: "muted",
|
|
423
|
+
className: "max-w-full",
|
|
424
|
+
children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
|
|
425
|
+
});
|
|
426
|
+
$[29] = message.text;
|
|
427
|
+
$[30] = t4;
|
|
428
|
+
} else t4 = $[30];
|
|
429
|
+
let t5;
|
|
430
|
+
if ($[31] !== t3 || $[32] !== t4) {
|
|
431
|
+
t5 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [t3, t4] }) });
|
|
432
|
+
$[31] = t3;
|
|
433
|
+
$[32] = t4;
|
|
434
|
+
$[33] = t5;
|
|
435
|
+
} else t5 = $[33];
|
|
436
|
+
return t5;
|
|
437
|
+
}
|
|
402
438
|
if (message.from === "camox") {
|
|
403
439
|
let t1;
|
|
404
|
-
if ($[
|
|
440
|
+
if ($[34] === Symbol.for("react.memo_cache_sentinel")) {
|
|
405
441
|
t1 = /* @__PURE__ */ jsx(MessageHeader, {
|
|
406
442
|
className: "text-muted-foreground text-xs",
|
|
407
443
|
children: "Camox"
|
|
408
444
|
});
|
|
409
|
-
$[
|
|
410
|
-
} else t1 = $[
|
|
445
|
+
$[34] = t1;
|
|
446
|
+
} else t1 = $[34];
|
|
411
447
|
let t2;
|
|
412
|
-
if ($[
|
|
448
|
+
if ($[35] !== message.text) {
|
|
413
449
|
t2 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [t1, /* @__PURE__ */ jsx(Bubble, {
|
|
414
450
|
variant: "muted",
|
|
415
451
|
className: "max-w-full",
|
|
416
|
-
children: /* @__PURE__ */ jsx(BubbleContent, {
|
|
417
|
-
className: "whitespace-pre-wrap",
|
|
418
|
-
children: message.text
|
|
419
|
-
})
|
|
452
|
+
children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
|
|
420
453
|
})] }) });
|
|
421
|
-
$[
|
|
422
|
-
$[
|
|
423
|
-
} else t2 = $[
|
|
454
|
+
$[35] = message.text;
|
|
455
|
+
$[36] = t2;
|
|
456
|
+
} else t2 = $[36];
|
|
424
457
|
return t2;
|
|
425
458
|
}
|
|
426
459
|
let t1;
|
|
427
|
-
if ($[
|
|
460
|
+
if ($[37] !== message.sender) {
|
|
428
461
|
t1 = /* @__PURE__ */ jsx(MessageAvatar, { children: /* @__PURE__ */ jsx(SenderAvatar, { sender: message.sender }) });
|
|
429
|
-
$[
|
|
430
|
-
$[
|
|
431
|
-
} else t1 = $[
|
|
462
|
+
$[37] = message.sender;
|
|
463
|
+
$[38] = t1;
|
|
464
|
+
} else t1 = $[38];
|
|
432
465
|
let t2;
|
|
433
|
-
if ($[
|
|
466
|
+
if ($[39] !== message.text) {
|
|
434
467
|
t2 = /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Bubble, {
|
|
435
468
|
align: "end",
|
|
436
469
|
variant: "muted",
|
|
437
470
|
className: "max-w-full",
|
|
438
|
-
children: /* @__PURE__ */ jsx(BubbleContent, {
|
|
439
|
-
className: "whitespace-pre-wrap",
|
|
440
|
-
children: message.text
|
|
441
|
-
})
|
|
471
|
+
children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
|
|
442
472
|
}) });
|
|
443
|
-
$[
|
|
444
|
-
$[
|
|
445
|
-
} else t2 = $[
|
|
473
|
+
$[39] = message.text;
|
|
474
|
+
$[40] = t2;
|
|
475
|
+
} else t2 = $[40];
|
|
446
476
|
let t3;
|
|
447
|
-
if ($[
|
|
477
|
+
if ($[41] !== t1 || $[42] !== t2) {
|
|
448
478
|
t3 = /* @__PURE__ */ jsxs(Message, {
|
|
449
479
|
align: "end",
|
|
450
480
|
children: [t1, t2]
|
|
451
481
|
});
|
|
452
|
-
$[
|
|
453
|
-
$[
|
|
454
|
-
$[
|
|
455
|
-
} else t3 = $[
|
|
482
|
+
$[41] = t1;
|
|
483
|
+
$[42] = t2;
|
|
484
|
+
$[43] = t3;
|
|
485
|
+
} else t3 = $[43];
|
|
456
486
|
return t3;
|
|
457
487
|
}
|
|
458
488
|
function _temp(subject, index) {
|
|
@@ -461,6 +491,82 @@ function _temp(subject, index) {
|
|
|
461
491
|
children: subject
|
|
462
492
|
}, index);
|
|
463
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* A message's text, cropped past its fourth line: the next ones fade out, above a button that
|
|
496
|
+
* shows it all. A message that fits shows as is.
|
|
497
|
+
*/
|
|
498
|
+
function CroppedText(t0) {
|
|
499
|
+
const $ = c(17);
|
|
500
|
+
const { text } = t0;
|
|
501
|
+
const node = React.useRef(null);
|
|
502
|
+
const [overflows, setOverflows] = React.useState(false);
|
|
503
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
504
|
+
let t1;
|
|
505
|
+
if ($[0] !== expanded) {
|
|
506
|
+
t1 = () => {
|
|
507
|
+
const element = node.current;
|
|
508
|
+
if (!element || expanded) return;
|
|
509
|
+
const measure = () => setOverflows(element.scrollHeight > element.clientHeight + 1);
|
|
510
|
+
measure();
|
|
511
|
+
const observer = new ResizeObserver(measure);
|
|
512
|
+
observer.observe(element);
|
|
513
|
+
return () => observer.disconnect();
|
|
514
|
+
};
|
|
515
|
+
$[0] = expanded;
|
|
516
|
+
$[1] = t1;
|
|
517
|
+
} else t1 = $[1];
|
|
518
|
+
let t2;
|
|
519
|
+
if ($[2] !== expanded || $[3] !== text) {
|
|
520
|
+
t2 = [text, expanded];
|
|
521
|
+
$[2] = expanded;
|
|
522
|
+
$[3] = text;
|
|
523
|
+
$[4] = t2;
|
|
524
|
+
} else t2 = $[4];
|
|
525
|
+
React.useLayoutEffect(t1, t2);
|
|
526
|
+
const cropped = !expanded && overflows;
|
|
527
|
+
const t3 = cropped || void 0;
|
|
528
|
+
const t4 = !expanded && "max-h-[5.5lh] overflow-hidden";
|
|
529
|
+
const t5 = cropped && "mask-[linear-gradient(to_bottom,black_4lh,transparent)]";
|
|
530
|
+
let t6;
|
|
531
|
+
if ($[5] !== t4 || $[6] !== t5) {
|
|
532
|
+
t6 = cn("whitespace-pre-wrap", t4, t5);
|
|
533
|
+
$[5] = t4;
|
|
534
|
+
$[6] = t5;
|
|
535
|
+
$[7] = t6;
|
|
536
|
+
} else t6 = $[7];
|
|
537
|
+
let t7;
|
|
538
|
+
if ($[8] !== t3 || $[9] !== t6 || $[10] !== text) {
|
|
539
|
+
t7 = /* @__PURE__ */ jsx("div", {
|
|
540
|
+
ref: node,
|
|
541
|
+
"data-thread-cropped": t3,
|
|
542
|
+
className: t6,
|
|
543
|
+
children: text
|
|
544
|
+
});
|
|
545
|
+
$[8] = t3;
|
|
546
|
+
$[9] = t6;
|
|
547
|
+
$[10] = text;
|
|
548
|
+
$[11] = t7;
|
|
549
|
+
} else t7 = $[11];
|
|
550
|
+
let t8;
|
|
551
|
+
if ($[12] !== cropped) {
|
|
552
|
+
t8 = cropped && /* @__PURE__ */ jsx("button", {
|
|
553
|
+
type: "button",
|
|
554
|
+
onClick: () => setExpanded(true),
|
|
555
|
+
className: "focus-visible:ring-ring mt-1 rounded-sm font-medium hover:underline focus-visible:ring-2 focus-visible:outline-none",
|
|
556
|
+
children: "Show full message"
|
|
557
|
+
});
|
|
558
|
+
$[12] = cropped;
|
|
559
|
+
$[13] = t8;
|
|
560
|
+
} else t8 = $[13];
|
|
561
|
+
let t9;
|
|
562
|
+
if ($[14] !== t7 || $[15] !== t8) {
|
|
563
|
+
t9 = /* @__PURE__ */ jsxs(Fragment, { children: [t7, t8] });
|
|
564
|
+
$[14] = t7;
|
|
565
|
+
$[15] = t8;
|
|
566
|
+
$[16] = t9;
|
|
567
|
+
} else t9 = $[16];
|
|
568
|
+
return t9;
|
|
569
|
+
}
|
|
464
570
|
const initials = (name) => name.split(" ").map((part) => part[0]).join("").toUpperCase().slice(0, 2);
|
|
465
571
|
const DRAFT_CARD_CLASSES = "bg-muted/50 flex w-full flex-col items-start gap-0.5 rounded-lg border px-3 py-2 text-left text-sm";
|
|
466
572
|
/**
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/features/studio/components/clientLogoPaths.ts
|
|
2
|
+
/** Each client's mark, as one SVG path on a 24×24 box. */
|
|
3
|
+
const CLIENT_LOGO_PATHS = {
|
|
4
|
+
claude: "m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z",
|
|
5
|
+
chatgpt: "M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z",
|
|
6
|
+
copilot: "M23.922 16.997C23.061 18.492 18.063 22.02 12 22.02 5.937 22.02.939 18.492.078 16.997A.641.641 0 0 1 0 16.741v-2.869a.883.883 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.098 10.098 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952C7.255 2.937 9.248 1.98 11.978 1.98c2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.841.841 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256Zm-11.75-5.992h-.344a4.359 4.359 0 0 1-.355.508c-.77.947-1.918 1.492-3.508 1.492-1.725 0-2.989-.359-3.782-1.259a2.137 2.137 0 0 1-.085-.104L4 11.746v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.359 4.359 0 0 1-.355-.508Zm2.328 3.25c.549 0 1 .451 1 1v2c0 .549-.451 1-1 1-.549 0-1-.451-1-1v-2c0-.549.451-1 1-1Zm-5 0c.549 0 1 .451 1 1v2c0 .549-.451 1-1 1-.549 0-1-.451-1-1v-2c0-.549.451-1 1-1Zm3.313-6.185c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { CLIENT_LOGO_PATHS };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { localeName } from "./localeOptions.js";
|
|
2
|
+
import { findingSentence } from "@camox/api-contract/patrol";
|
|
3
|
+
|
|
4
|
+
//#region src/features/studio/findingSentence.ts
|
|
5
|
+
/** Quoted as editors read it. */
|
|
6
|
+
const quoted = (text) => `“${text}”`;
|
|
7
|
+
/** What a dismissal dismissed, briefly: "Links to About", or the text it was about. */
|
|
8
|
+
function dismissedSentence(about) {
|
|
9
|
+
switch (about.kind) {
|
|
10
|
+
case "missingPage": return `Links to ${about.page ?? "a missing page"}`;
|
|
11
|
+
case "brokenLink": return `Links to ${about.url}`;
|
|
12
|
+
default: return quoted(about.text);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** What dismissing a finding says, as its button says it: a broken link's is "This link is fine". */
|
|
16
|
+
function dismissLabel(about) {
|
|
17
|
+
return about.kind === "brokenLink" ? "This link is fine" : "Dismiss";
|
|
18
|
+
}
|
|
19
|
+
/** What applying a fix does, as its button says it. */
|
|
20
|
+
function fixLabel(fix) {
|
|
21
|
+
switch (fix.kind) {
|
|
22
|
+
case "removeLink": return "Remove the link";
|
|
23
|
+
case "replaceText": return `Replace with ${quoted(fix.replacement)}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* What "Ask the agent" fills the draft's chat with: who found what, where, and the fix it
|
|
28
|
+
* suggests, for the agent to find among the draft's findings and fix.
|
|
29
|
+
*/
|
|
30
|
+
function askAgentMessage(finding, role) {
|
|
31
|
+
const where = `(in ${localeName(finding.locale)}, field ${quoted(finding.field)})`;
|
|
32
|
+
const fix = finding.fix ? ` Suggested fix: ${fixLabel(finding.fix)}.` : "";
|
|
33
|
+
return `${role} finding: ${findingSentence(finding)} ${where}.${fix}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { askAgentMessage, dismissLabel, dismissedSentence, findingSentence, fixLabel };
|
|
@@ -26,6 +26,21 @@ const PHRASES = {
|
|
|
26
26
|
publishedCatchUp: {
|
|
27
27
|
done: "Published the caught-up translations",
|
|
28
28
|
failed: "Couldn't publish the caught-up translations"
|
|
29
|
+
},
|
|
30
|
+
removedLink: {
|
|
31
|
+
done: "Removed a link in",
|
|
32
|
+
failed: "Couldn't remove a link in",
|
|
33
|
+
locale: "in"
|
|
34
|
+
},
|
|
35
|
+
fixedLink: {
|
|
36
|
+
done: "Fixed a link in",
|
|
37
|
+
failed: "Couldn't fix a link in",
|
|
38
|
+
locale: "in"
|
|
39
|
+
},
|
|
40
|
+
fixedMistake: {
|
|
41
|
+
done: "Fixed a typo in",
|
|
42
|
+
failed: "Couldn't fix a typo in",
|
|
43
|
+
locale: "in"
|
|
29
44
|
}
|
|
30
45
|
};
|
|
31
46
|
/** A report as a sentence: "Wrote SEO for Pricing in German", or the text an AI wrote. */
|
|
@@ -11,7 +11,9 @@ const studioStore = createStore({
|
|
|
11
11
|
},
|
|
12
12
|
isDeleteDraftDialogOpen: false,
|
|
13
13
|
localeDialog: null,
|
|
14
|
-
websiteLocation: null
|
|
14
|
+
websiteLocation: null,
|
|
15
|
+
agentAsk: null,
|
|
16
|
+
agentAsks: 0
|
|
15
17
|
},
|
|
16
18
|
on: {
|
|
17
19
|
openCommandPalette: (context) => {
|
|
@@ -88,6 +90,26 @@ const studioStore = createStore({
|
|
|
88
90
|
localeDialog: null
|
|
89
91
|
};
|
|
90
92
|
},
|
|
93
|
+
askAgent: (context, event) => {
|
|
94
|
+
return {
|
|
95
|
+
...context,
|
|
96
|
+
reviewDraftSheet: {
|
|
97
|
+
open: false,
|
|
98
|
+
startRenaming: false
|
|
99
|
+
},
|
|
100
|
+
agentAsk: {
|
|
101
|
+
text: event.text,
|
|
102
|
+
id: context.agentAsks + 1
|
|
103
|
+
},
|
|
104
|
+
agentAsks: context.agentAsks + 1
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
takeAgentAsk: (context) => {
|
|
108
|
+
return {
|
|
109
|
+
...context,
|
|
110
|
+
agentAsk: null
|
|
111
|
+
};
|
|
112
|
+
},
|
|
91
113
|
rememberWebsiteLocation: (context, event) => {
|
|
92
114
|
const previous = context.websiteLocation;
|
|
93
115
|
const { locale, path, search, hash } = event.location;
|
|
@@ -11,6 +11,14 @@ const PHRASES = {
|
|
|
11
11
|
verb: "Writing SEO for",
|
|
12
12
|
verbFor: { file: "Describing" },
|
|
13
13
|
locale: "in"
|
|
14
|
+
},
|
|
15
|
+
linkChecker: {
|
|
16
|
+
verb: "Checking links in",
|
|
17
|
+
locale: "in"
|
|
18
|
+
},
|
|
19
|
+
proofreader: {
|
|
20
|
+
verb: "Proofreading",
|
|
21
|
+
locale: "in"
|
|
14
22
|
}
|
|
15
23
|
};
|
|
16
24
|
/** The most locales a burst names; past it, the first are named and the rest counted. */
|
package/dist/lib/api-client.d.ts
CHANGED
package/dist/lib/auth.js
CHANGED
|
@@ -251,58 +251,60 @@ function useSessionState(authClient, track) {
|
|
|
251
251
|
return React.useSyncExternalStore(track ? subscribe : noSubscription, getSnapshot, getSnapshot);
|
|
252
252
|
}
|
|
253
253
|
function useAuthState() {
|
|
254
|
-
const $ = c(
|
|
255
|
-
const { authClient, initialAuthenticated: t0, exchangingToken: t1 } = useAuthContext();
|
|
254
|
+
const $ = c(10);
|
|
255
|
+
const { authClient, initialAuthenticated: t0, exchangingToken: t1, sessionless: t2 } = useAuthContext();
|
|
256
256
|
const initialAuthenticated = t0 === void 0 ? false : t0;
|
|
257
257
|
const exchangingToken = t1 === void 0 ? false : t1;
|
|
258
|
+
const sessionless = t2 === void 0 ? false : t2;
|
|
258
259
|
const hydrated = React.useSyncExternalStore(subscribeToHydration, _temp2, _temp3);
|
|
259
|
-
let
|
|
260
|
-
if ($[0] !== hydrated || $[1] !== initialAuthenticated) {
|
|
261
|
-
|
|
260
|
+
let t3;
|
|
261
|
+
if ($[0] !== hydrated || $[1] !== initialAuthenticated || $[2] !== sessionless) {
|
|
262
|
+
t3 = !sessionless && (initialAuthenticated || hydrated && hasStoredAuthCookie());
|
|
262
263
|
$[0] = hydrated;
|
|
263
264
|
$[1] = initialAuthenticated;
|
|
264
|
-
$[2] =
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
$[2] = sessionless;
|
|
266
|
+
$[3] = t3;
|
|
267
|
+
} else t3 = $[3];
|
|
268
|
+
const tracksSession = t3;
|
|
267
269
|
const { data: session, isPending } = useSessionState(authClient, tracksSession);
|
|
268
270
|
if (exchangingToken && !initialAuthenticated) {
|
|
269
|
-
let
|
|
270
|
-
if ($[
|
|
271
|
-
|
|
271
|
+
let t4;
|
|
272
|
+
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
|
273
|
+
t4 = {
|
|
272
274
|
isAuthenticated: false,
|
|
273
275
|
isLoading: true
|
|
274
276
|
};
|
|
275
|
-
$[
|
|
276
|
-
} else
|
|
277
|
-
return
|
|
277
|
+
$[4] = t4;
|
|
278
|
+
} else t4 = $[4];
|
|
279
|
+
return t4;
|
|
278
280
|
}
|
|
279
281
|
if (!tracksSession) {
|
|
280
|
-
const
|
|
281
|
-
let
|
|
282
|
-
if ($[
|
|
283
|
-
|
|
282
|
+
const t4 = !hydrated;
|
|
283
|
+
let t5;
|
|
284
|
+
if ($[5] !== t4) {
|
|
285
|
+
t5 = {
|
|
284
286
|
isAuthenticated: false,
|
|
285
|
-
isLoading:
|
|
287
|
+
isLoading: t4
|
|
286
288
|
};
|
|
287
|
-
$[4] = t3;
|
|
288
289
|
$[5] = t4;
|
|
289
|
-
|
|
290
|
-
|
|
290
|
+
$[6] = t5;
|
|
291
|
+
} else t5 = $[6];
|
|
292
|
+
return t5;
|
|
291
293
|
}
|
|
292
294
|
const useInitial = !hydrated || isPending;
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
let
|
|
296
|
-
if ($[
|
|
297
|
-
|
|
298
|
-
isAuthenticated:
|
|
299
|
-
isLoading:
|
|
295
|
+
const t4 = useInitial ? initialAuthenticated : !!session;
|
|
296
|
+
const t5 = useInitial && !initialAuthenticated;
|
|
297
|
+
let t6;
|
|
298
|
+
if ($[7] !== t4 || $[8] !== t5) {
|
|
299
|
+
t6 = {
|
|
300
|
+
isAuthenticated: t4,
|
|
301
|
+
isLoading: t5
|
|
300
302
|
};
|
|
301
|
-
$[6] = t3;
|
|
302
303
|
$[7] = t4;
|
|
303
304
|
$[8] = t5;
|
|
304
|
-
|
|
305
|
-
|
|
305
|
+
$[9] = t6;
|
|
306
|
+
} else t6 = $[9];
|
|
307
|
+
return t6;
|
|
306
308
|
}
|
|
307
309
|
function _temp3() {
|
|
308
310
|
return false;
|
package/dist/lib/locale-path.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LOCALE_HEADER } from "@camox/api-contract/drafts";
|
|
2
|
-
import {
|
|
2
|
+
import { localizedPath, parseLocalePath } from "@camox/api-contract/locales";
|
|
3
3
|
|
|
4
4
|
//#region src/lib/locale-path.ts
|
|
5
5
|
/**
|
|
@@ -22,12 +22,6 @@ const UNNAMED_DEFAULT_LOCALE = {
|
|
|
22
22
|
function localeHeaders(locale) {
|
|
23
23
|
return locale && !locale.isDefault ? { [LOCALE_HEADER]: locale.tag } : {};
|
|
24
24
|
}
|
|
25
|
-
/** A locale-relative path under its locale's prefix, keeping its search and hash: `/` is `/de`. */
|
|
26
|
-
function localizedPath(path, locale) {
|
|
27
|
-
const prefix = localePrefix(locale);
|
|
28
|
-
if (!prefix) return path;
|
|
29
|
-
return path === "/" || /^\/[?#]/.test(path) ? `${prefix}${path.slice(1)}` : `${prefix}${path}`;
|
|
30
|
-
}
|
|
31
25
|
|
|
32
26
|
//#endregion
|
|
33
27
|
export { UNNAMED_DEFAULT_LOCALE, localeHeaders, localizedPath, parseLocalePath };
|
package/dist/lib/queries.js
CHANGED
|
@@ -50,6 +50,14 @@ const draftMutations = {
|
|
|
50
50
|
/** Drops the draft's copy of an entity it conflicts on, to use Live's version instead. */
|
|
51
51
|
revertToLive: () => getOrpc().drafts.revertToLive.mutationOptions()
|
|
52
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* What members do with a patroller's finding (ADR 0034): apply its fix in the draft viewed, or
|
|
55
|
+
* dismiss it for the whole project.
|
|
56
|
+
*/
|
|
57
|
+
const patrolMutations = {
|
|
58
|
+
applyFix: () => getOrpc().patrol.applyFix.mutationOptions(),
|
|
59
|
+
dismissFinding: () => getOrpc().patrol.dismissFinding.mutationOptions()
|
|
60
|
+
};
|
|
53
61
|
/** Adding and removing locales: content writes, so on Live they start a draft (ADR 0015). */
|
|
54
62
|
const localeMutations = {
|
|
55
63
|
add: () => getOrpc().locales.add.mutationOptions(),
|
|
@@ -131,4 +139,4 @@ const fileMutations = {
|
|
|
131
139
|
};
|
|
132
140
|
|
|
133
141
|
//#endregion
|
|
134
|
-
export { blockMutations, collectionMutations, draftMutations, fileMutations, localeMutations, pageMutations, projectMutations, repeatableItemMutations };
|
|
142
|
+
export { blockMutations, collectionMutations, draftMutations, fileMutations, localeMutations, pageMutations, patrolMutations, projectMutations, repeatableItemMutations };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LOOK_TOKEN_COOKIE } from "@camox/api-contract/drafts";
|
|
2
|
+
|
|
1
3
|
//#region src/lib/server-auth-cookie.ts
|
|
2
4
|
const SERVER_AUTH_COOKIE_NAME = "camox_auth_cookie";
|
|
3
5
|
/** How long the mirror lasts. The API still refuses a session that expired before it. */
|
|
@@ -20,14 +22,25 @@ function getServerAuthCookieHeader(headers) {
|
|
|
20
22
|
}
|
|
21
23
|
/** The mirror's session in a `Cookie` header's value, or `document.cookie`. */
|
|
22
24
|
function readServerAuthCookie(cookieHeader) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
return readCookie(cookieHeader, SERVER_AUTH_COOKIE_NAME);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The look token a request carries in `LOOK_TOKEN_COOKIE` (ADR 0032), set by the browser the
|
|
29
|
+
* agent's `look` tool drives for the website's host only. Empty when there's none.
|
|
30
|
+
*/
|
|
31
|
+
function getLookToken(headers) {
|
|
32
|
+
return readCookie(headers.get("Cookie") ?? "", LOOK_TOKEN_COOKIE);
|
|
33
|
+
}
|
|
34
|
+
/** The cookie `name`'s value in a `Cookie` header's value, decoded, or empty when there's none. */
|
|
35
|
+
function readCookie(cookieHeader, name) {
|
|
36
|
+
const cookie = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${name}=`));
|
|
37
|
+
if (!cookie) return "";
|
|
25
38
|
try {
|
|
26
|
-
return decodeURIComponent(
|
|
39
|
+
return decodeURIComponent(cookie.slice(name.length + 1));
|
|
27
40
|
} catch {
|
|
28
41
|
return "";
|
|
29
42
|
}
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
//#endregion
|
|
33
|
-
export { SERVER_AUTH_COOKIE_NAME, buildClearServerAuthCookieHeader, buildServerAuthCookieHeader, getServerAuthCookieHeader, readServerAuthCookie };
|
|
46
|
+
export { SERVER_AUTH_COOKIE_NAME, buildClearServerAuthCookieHeader, buildServerAuthCookieHeader, getLookToken, getServerAuthCookieHeader, readServerAuthCookie };
|
|
@@ -6,8 +6,8 @@ import { ApiClient } from "./api-client.js";
|
|
|
6
6
|
import "./queries.js";
|
|
7
7
|
import "react";
|
|
8
8
|
import "@camox/api-contract/query-keys";
|
|
9
|
-
import { QueryClient } from "@tanstack/react-query";
|
|
10
9
|
import "@camox/api-contract/patrol";
|
|
10
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
11
11
|
//#region src/lib/studio-reads.d.ts
|
|
12
12
|
type LayoutRead = Awaited<ReturnType<ApiClient["layouts"]["get"]>>;
|
|
13
13
|
/** A layout's structure: its blocks before and after the content of its pages. */
|
package/dist/lib/studio-reads.js
CHANGED
|
@@ -5,6 +5,7 @@ import { collectFileIds } from "./normalized-data.js";
|
|
|
5
5
|
import { c } from "react/compiler-runtime";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { inScope, queryKeys, scopeOfKey } from "@camox/api-contract/query-keys";
|
|
8
|
+
import { PATROLLER_IDS } from "@camox/api-contract/patrol";
|
|
8
9
|
import { useQueries, useQuery, useSuspenseQuery } from "@tanstack/react-query";
|
|
9
10
|
|
|
10
11
|
//#region src/lib/studio-reads.ts
|
|
@@ -209,7 +210,10 @@ const reads = {
|
|
|
209
210
|
patrol: entry({
|
|
210
211
|
key: ({ projectId }) => [...queryKeys.patrol.get, projectId],
|
|
211
212
|
everyLocale: true,
|
|
212
|
-
fetch: ({ api, signal }, { projectId }) => api.patrol.get({
|
|
213
|
+
fetch: ({ api, signal }, { projectId }) => api.patrol.get({
|
|
214
|
+
projectId,
|
|
215
|
+
patrollers: [...PATROLLER_IDS]
|
|
216
|
+
}, { signal })
|
|
213
217
|
}),
|
|
214
218
|
publishPreview: entry({
|
|
215
219
|
key: ({ draftId }) => [
|
package/dist/package.js
CHANGED