camox 0.53.1 → 0.54.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.
@@ -5,12 +5,20 @@ import { c } from "react/compiler-runtime";
5
5
  import * as React from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import * as Tooltip$1 from "@camox/ui/tooltip";
8
+ import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
8
9
 
9
10
  //#region src/features/preview/components/SidebarStack.tsx
10
11
  /** How much narrower, on each side, the header right behind the front is than the front's. */
11
12
  const FIRST_STEP_INSET = 9;
13
+ /**
14
+ * How much each step back shades a card, relative to the step in front of it. The selection
15
+ * path collapses its middle, so the stack stays short and its steps can stay even.
16
+ */
17
+ const STEP_FALLOFF = .85;
12
18
  /** How much each step back narrows a header, relative to the step in front of it. */
13
- const STEP_FALLOFF = .65;
19
+ const INSET_FALLOFF = .75;
20
+ /** How much each step back tilts a header, relative to the step in front of it. */
21
+ const TILT_FALLOFF = .65;
14
22
  /** How far the header right behind the front leans back, in degrees. */
15
23
  const FIRST_STEP_TILT = 4;
16
24
  /**
@@ -22,14 +30,17 @@ const FIRST_STEP_SHADE = 1.2;
22
30
  const DARK_SHADE_STRENGTH = 2.5;
23
31
  /** Keeps a sidebar's cards off its sides, so their edges show. */
24
32
  const SIDEBAR_GUTTER = "px-2";
25
- /** The front card's sides and bottom, drawn just outside it, above the bottom of the sidebar. */
26
- const CARD_BODY_EDGES = "rounded-b-lg shadow-[-1px_0_0_var(--color-border),1px_0_0_var(--color-border),0_1px_0_var(--color-border)]";
27
33
  /**
28
- * The bottom card's edges, as it meets the top of a sidebar, which crops anything above it: it
29
- * draws its top edge inside, and nothing lies behind it to cast a shadow on. One border, a pixel
30
- * past each side to meet the sides below, keeps the edge even around the rounded corners.
34
+ * The color of a card's edges: the border's, solid. Dark mode's border is translucent, so it's
35
+ * laid over the Canvas behind the sidebars, to look the same over the card as beside it.
31
36
  */
32
- const BOTTOM_CARD_EDGES = "relative rounded-t-lg before:pointer-events-none before:absolute before:-inset-x-px before:inset-y-0 before:rounded-t-[inherit] before:border before:border-b-0 before:border-border";
37
+ const CARD_EDGE_COLOR = "border-border dark:border-[color-mix(in_srgb,var(--color-muted),white_10%)]";
38
+ /** The front card's sides and bottom, under its header. */
39
+ const CARD_BODY_EDGES = `rounded-b-lg border border-t-0 ${CARD_EDGE_COLOR}`;
40
+ /** The bottom card's top and sides, as it meets the top of a sidebar. */
41
+ const BOTTOM_CARD_EDGES = `rounded-t-lg border border-b-0 ${CARD_EDGE_COLOR}`;
42
+ /** The front card's top and sides, over the cards behind it. */
43
+ const FRONT_CARD_EDGES = `border border-b-0 ${CARD_EDGE_COLOR}`;
33
44
  /**
34
45
  * How much the second card behind the front fades its name, which shows depth on dark
35
46
  * backgrounds too. The card right behind the front doesn't fade.
@@ -38,12 +49,12 @@ const FIRST_STEP_FADE = .05;
38
49
  /** How far away the eye is from the stack, in px: the less, the stronger the depth. */
39
50
  const PERSPECTIVE = 900;
40
51
  /** Sums the steps of a falloff series, `distance` views behind the front. */
41
- function stepSeries(first, distance) {
42
- return first * (1 - STEP_FALLOFF ** distance) / .35;
52
+ function stepSeries(first, distance, falloff = STEP_FALLOFF) {
53
+ return first * (1 - falloff ** distance) / (1 - falloff);
43
54
  }
44
55
  /** A header's inset on each side, `distance` views behind the front. */
45
56
  function stackInset(distance) {
46
- return stepSeries(FIRST_STEP_INSET, distance);
57
+ return stepSeries(FIRST_STEP_INSET, distance, INSET_FALLOFF);
47
58
  }
48
59
  /** Cards settle into place, without bouncing. */
49
60
  const EASE = "cubic-bezier(0.2, 0, 0, 1)";
@@ -100,7 +111,10 @@ const GOING = {
100
111
  },
101
112
  PULLED
102
113
  ],
103
- back: [PLACED, BEHIND],
114
+ back: [PLACED, {
115
+ ...BEHIND,
116
+ opacity: 0
117
+ }],
104
118
  same: [{ opacity: 1 }, { opacity: 0 }]
105
119
  };
106
120
  const GOING_TIMING = {
@@ -338,7 +352,7 @@ function SidebarStackView(t0) {
338
352
  const { depth, className, children } = t0;
339
353
  const ref = React.useRef(null);
340
354
  useStackCard(ref, depth, true);
341
- const t1 = React.useContext(StackMotionContext) != null && "rounded-b-lg shadow-[-1px_0_0_var(--color-border),1px_0_0_var(--color-border),0_1px_0_var(--color-border)]";
355
+ const t1 = React.useContext(StackMotionContext) != null && "rounded-b-lg border border-t-0 border-border dark:border-[color-mix(in_srgb,var(--color-muted),white_10%)]";
342
356
  let t2;
343
357
  if ($[0] !== className || $[1] !== t1) {
344
358
  t2 = cn("bg-background min-h-0 flex-1 origin-top", t1, className);
@@ -360,8 +374,8 @@ function SidebarStackView(t0) {
360
374
  return t3;
361
375
  }
362
376
  function SidebarStackHeader(t0) {
363
- const $ = c(52);
364
- const { depth, distance: t1, first: t2, onSelect, hoverTarget, tooltip, children } = t0;
377
+ const $ = c(55);
378
+ const { depth, distance: t1, first: t2, onSelect, hoverTarget, tooltip, popover, children } = t0;
365
379
  const distance = t1 === void 0 ? 0 : t1;
366
380
  const first = t2 === void 0 ? false : t2;
367
381
  const covered = distance > 0;
@@ -397,12 +411,13 @@ function SidebarStackHeader(t0) {
397
411
  React.useEffect(t4, t5);
398
412
  const ref = React.useRef(null);
399
413
  useStackCard(ref, depth, false);
400
- const liftable = covered && onSelect != null;
414
+ const [popoverOpen, setPopoverOpen] = React.useState(false);
415
+ const liftable = covered && (onSelect != null || popover != null);
401
416
  const inStack = React.useContext(StackMotionContext) != null;
402
417
  const flat = first && !covered && !inStack;
403
418
  let t6;
404
419
  if ($[8] !== covered || $[9] !== distance) {
405
- t6 = covered ? stepSeries(FIRST_STEP_TILT, distance) : 0;
420
+ t6 = covered ? stepSeries(FIRST_STEP_TILT, distance, TILT_FALLOFF) : 0;
406
421
  $[8] = covered;
407
422
  $[9] = distance;
408
423
  $[10] = t6;
@@ -419,12 +434,12 @@ function SidebarStackHeader(t0) {
419
434
  if ($[13] !== children || $[14] !== liftable || $[15] !== onSelect) {
420
435
  t8 = liftable ? /* @__PURE__ */ jsx("button", {
421
436
  type: "button",
422
- className: "hover:text-foreground flex h-full w-full min-w-0 cursor-pointer items-center justify-center rounded-[inherit] px-3 text-center text-(--ancestor-foreground) transition-colors focus-visible:outline-none",
437
+ className: "hover:text-foreground data-popup-open:text-foreground flex h-full w-full min-w-0 cursor-pointer items-center justify-center rounded-[inherit] px-3 text-center text-(--ancestor-foreground) transition-colors focus-visible:outline-none",
423
438
  onMouseEnter: () => setHovered(true),
424
439
  onMouseLeave: () => setHovered(false),
425
440
  onClick: () => {
426
441
  setHovered(false);
427
- onSelect();
442
+ onSelect?.();
428
443
  },
429
444
  children: /* @__PURE__ */ jsx("span", {
430
445
  className: "truncate opacity-(--fade) transition-opacity",
@@ -446,14 +461,15 @@ function SidebarStackHeader(t0) {
446
461
  } else t10 = $[18];
447
462
  const t11 = !flat && !first && "rounded-t-sm";
448
463
  const t12 = covered ? "h-[38px] pb-1" : "h-11 px-3";
449
- const t13 = first && !flat && "relative rounded-t-lg before:pointer-events-none before:absolute before:-inset-x-px before:inset-y-0 before:rounded-t-[inherit] before:border before:border-b-0 before:border-border";
450
- const t14 = covered && !first && "shadow-[0_0_0_1px_var(--color-border),0_-2px_5px_-3px_rgb(0_0_0/0.08),inset_0_1px_0_rgb(255_255_255/0.5)] dark:shadow-[0_0_0_1px_var(--color-border),0_-2px_5px_-3px_rgb(0_0_0/0.4),inset_0_1px_0_rgb(255_255_255/0.05)]";
451
- const t15 = !covered && !first && (inStack ? "shadow-[-1px_0_0_var(--color-border),1px_0_0_var(--color-border),0_-1px_0_var(--color-border),0_-3px_8px_-4px_rgb(0_0_0/0.08)] dark:shadow-[-1px_0_0_var(--color-border),1px_0_0_var(--color-border),0_-1px_0_var(--color-border),0_-3px_8px_-4px_rgb(0_0_0/0.4)]" : "shadow-[0_-1px_0_var(--color-border),0_-3px_8px_-4px_rgb(0_0_0/0.08)] dark:shadow-[0_-1px_0_var(--color-border),0_-3px_8px_-4px_rgb(0_0_0/0.4)]");
464
+ const t13 = first && !flat && "rounded-t-lg border border-b-0 border-border dark:border-[color-mix(in_srgb,var(--color-muted),white_10%)]";
465
+ const t14 = covered && !first && `border ${CARD_EDGE_COLOR} shadow-[0_-2px_5px_-3px_rgb(0_0_0/0.08)] dark:shadow-[0_-2px_5px_-3px_rgb(0_0_0/0.4)]`;
466
+ const t15 = !covered && !first && (inStack ? `${FRONT_CARD_EDGES} shadow-[0_-3px_8px_-4px_rgb(0_0_0/0.08)] dark:shadow-[0_-3px_8px_-4px_rgb(0_0_0/0.4)]` : `border-t ${CARD_EDGE_COLOR} shadow-[0_-3px_8px_-4px_rgb(0_0_0/0.08)] dark:shadow-[0_-3px_8px_-4px_rgb(0_0_0/0.4)]`);
452
467
  const t16 = liftable && "hover:[--fade:1] hover:[--lift:var(--hover-lift)] hover:[--shade:var(--hover-shade)] hover:[--tilt:var(--hover-tilt)]";
453
468
  const t17 = liftable && "has-focus-visible:[--fade:1] has-focus-visible:[--lift:var(--hover-lift)] has-focus-visible:[--shade:var(--hover-shade)] has-focus-visible:[--tilt:var(--hover-tilt)]";
454
- let t18;
455
- if ($[19] !== t11 || $[20] !== t12 || $[21] !== t13 || $[22] !== t14 || $[23] !== t15 || $[24] !== t16 || $[25] !== t17) {
456
- t18 = cn("relative flex min-w-0 items-center justify-center text-center text-sm", t11, "[--ancestor-foreground:color-mix(in_oklab,var(--color-muted-foreground),var(--color-foreground)_40%)]", "[--fade:var(--rest-fade)] [--lift:0px] [--shade:var(--rest-shade)] [--tilt:var(--rest-tilt)]", "[--shade-color:black] [--shade-strength:1] dark:[--shade-color:white] dark:[--shade-strength:var(--dark-shade-strength)]", "origin-bottom [backface-visibility:hidden] motion-reduce:transition-none!", t12, t13, t14, t15, t16, t17);
469
+ const t18 = liftable && "has-data-popup-open:[--fade:1] has-data-popup-open:[--lift:var(--hover-lift)] has-data-popup-open:[--shade:var(--hover-shade)] has-data-popup-open:[--tilt:var(--hover-tilt)]";
470
+ let t19;
471
+ if ($[19] !== t11 || $[20] !== t12 || $[21] !== t13 || $[22] !== t14 || $[23] !== t15 || $[24] !== t16 || $[25] !== t17 || $[26] !== t18) {
472
+ t19 = cn("relative flex min-w-0 items-center justify-center text-center text-sm", t11, "[--ancestor-foreground:color-mix(in_oklab,var(--color-muted-foreground),var(--color-foreground)_40%)]", "[--fade:var(--rest-fade)] [--lift:0px] [--shade:var(--rest-shade)] [--tilt:var(--rest-tilt)]", "[--shade-color:black] [--shade-strength:1] dark:[--shade-color:white] dark:[--shade-strength:var(--dark-shade-strength)]", "origin-bottom [backface-visibility:hidden] motion-reduce:transition-none!", t12, t13, t14, t15, t16, t17, t18);
457
473
  $[19] = t11;
458
474
  $[20] = t12;
459
475
  $[21] = t13;
@@ -462,91 +478,104 @@ function SidebarStackHeader(t0) {
462
478
  $[24] = t16;
463
479
  $[25] = t17;
464
480
  $[26] = t18;
465
- } else t18 = $[26];
466
- const t19 = `${tilt}deg`;
467
- const t20 = `${tilt / 2}deg`;
468
- const t21 = `${shade}%`;
469
- const t22 = Math.max(0, distance - 1);
470
- let t23;
471
- if ($[27] !== t22) {
472
- t23 = stepSeries(FIRST_STEP_SHADE, t22);
473
- $[27] = t22;
481
+ $[27] = t19;
482
+ } else t19 = $[27];
483
+ const t20 = `${tilt}deg`;
484
+ const t21 = `${tilt / 2}deg`;
485
+ const t22 = `${shade}%`;
486
+ const t23 = Math.max(0, distance - 1);
487
+ let t24;
488
+ if ($[28] !== t23) {
489
+ t24 = stepSeries(FIRST_STEP_SHADE, t23);
474
490
  $[28] = t23;
475
- } else t23 = $[28];
476
- const t24 = `${t23}%`;
477
- const t25 = `${first ? 0 : -1.5}px`;
478
- const t26 = covered ? 1 - stepSeries(FIRST_STEP_FADE, distance - 1) : 1;
479
- let t27;
480
- if ($[29] !== covered || $[30] !== distance) {
481
- t27 = covered ? stackInset(distance) : void 0;
482
- $[29] = covered;
483
- $[30] = distance;
484
- $[31] = t27;
485
- } else t27 = $[31];
491
+ $[29] = t24;
492
+ } else t24 = $[29];
493
+ const t25 = `${t24}%`;
494
+ const t26 = `${first ? 0 : -1.5}px`;
495
+ const t27 = covered ? 1 - stepSeries(FIRST_STEP_FADE, distance - 1) : 1;
486
496
  let t28;
487
- if ($[32] !== t19 || $[33] !== t20 || $[34] !== t21 || $[35] !== t24 || $[36] !== t25 || $[37] !== t26 || $[38] !== t27) {
488
- t28 = {
489
- "--rest-tilt": t19,
490
- "--hover-tilt": t20,
491
- "--rest-shade": t21,
497
+ if ($[30] !== covered || $[31] !== distance) {
498
+ t28 = covered ? stackInset(distance) : void 0;
499
+ $[30] = covered;
500
+ $[31] = distance;
501
+ $[32] = t28;
502
+ } else t28 = $[32];
503
+ let t29;
504
+ if ($[33] !== t20 || $[34] !== t21 || $[35] !== t22 || $[36] !== t25 || $[37] !== t26 || $[38] !== t27 || $[39] !== t28) {
505
+ t29 = {
506
+ "--rest-tilt": t20,
507
+ "--hover-tilt": t21,
508
+ "--rest-shade": t22,
492
509
  "--dark-shade-strength": DARK_SHADE_STRENGTH,
493
- "--hover-shade": t24,
494
- "--hover-lift": t25,
495
- "--rest-fade": t26,
496
- marginInline: t27,
510
+ "--hover-shade": t25,
511
+ "--hover-lift": t26,
512
+ "--rest-fade": t27,
513
+ marginInline: t28,
497
514
  transform: `perspective(${PERSPECTIVE}px) translateY(var(--lift)) rotateX(var(--tilt))`,
498
515
  backgroundColor: "color-mix(in oklab, var(--color-background), var(--shade-color) calc(var(--shade) * var(--shade-strength)))",
499
516
  transition: HEADER_TRANSITION
500
517
  };
501
- $[32] = t19;
502
518
  $[33] = t20;
503
519
  $[34] = t21;
504
- $[35] = t24;
520
+ $[35] = t22;
505
521
  $[36] = t25;
506
522
  $[37] = t26;
507
523
  $[38] = t27;
508
524
  $[39] = t28;
509
- } else t28 = $[39];
510
- const t29 = t28;
511
- let t30;
512
- if ($[40] !== button || $[41] !== children || $[42] !== covered || $[43] !== tooltip) {
513
- t30 = button && tooltip ? /* @__PURE__ */ jsxs(Tooltip$1.Tooltip, { children: [/* @__PURE__ */ jsx(Tooltip$1.TooltipTrigger, { render: button }), /* @__PURE__ */ jsx(Tooltip$1.TooltipContent, {
525
+ $[40] = t29;
526
+ } else t29 = $[40];
527
+ const t30 = t29;
528
+ let t31;
529
+ if ($[41] !== button || $[42] !== children || $[43] !== covered || $[44] !== popover || $[45] !== popoverOpen || $[46] !== tooltip) {
530
+ t31 = button && popover ? /* @__PURE__ */ jsxs(Popover, {
531
+ open: popoverOpen,
532
+ onOpenChange: setPopoverOpen,
533
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: button }), /* @__PURE__ */ jsx(PopoverContent, {
534
+ side: "bottom",
535
+ sideOffset: 8,
536
+ className: "w-48 gap-0 p-1",
537
+ onClick: () => setPopoverOpen(false),
538
+ children: popover
539
+ })]
540
+ }) : button && tooltip ? /* @__PURE__ */ jsxs(Tooltip$1.Tooltip, { children: [/* @__PURE__ */ jsx(Tooltip$1.TooltipTrigger, { render: button }), /* @__PURE__ */ jsx(Tooltip$1.TooltipContent, {
514
541
  side: "bottom",
515
542
  children: tooltip
516
543
  })] }) : button ?? (covered ? /* @__PURE__ */ jsx("span", {
517
544
  className: "truncate px-3 text-(--ancestor-foreground) opacity-(--fade)",
518
545
  children
519
546
  }) : children);
520
- $[40] = button;
521
- $[41] = children;
522
- $[42] = covered;
523
- $[43] = tooltip;
524
- $[44] = t30;
525
- } else t30 = $[44];
526
- let t31;
527
- if ($[45] !== t18 || $[46] !== t29 || $[47] !== t30) {
528
- t31 = /* @__PURE__ */ jsx("div", {
529
- className: t18,
530
- style: t29,
531
- children: t30
532
- });
533
- $[45] = t18;
534
- $[46] = t29;
535
- $[47] = t30;
536
- $[48] = t31;
537
- } else t31 = $[48];
547
+ $[41] = button;
548
+ $[42] = children;
549
+ $[43] = covered;
550
+ $[44] = popover;
551
+ $[45] = popoverOpen;
552
+ $[46] = tooltip;
553
+ $[47] = t31;
554
+ } else t31 = $[47];
538
555
  let t32;
539
- if ($[49] !== t10 || $[50] !== t31) {
556
+ if ($[48] !== t19 || $[49] !== t30 || $[50] !== t31) {
540
557
  t32 = /* @__PURE__ */ jsx("div", {
541
- ref,
542
- className: t10,
558
+ className: t19,
559
+ style: t30,
543
560
  children: t31
544
561
  });
545
- $[49] = t10;
562
+ $[48] = t19;
563
+ $[49] = t30;
546
564
  $[50] = t31;
547
565
  $[51] = t32;
548
566
  } else t32 = $[51];
549
- return t32;
567
+ let t33;
568
+ if ($[52] !== t10 || $[53] !== t32) {
569
+ t33 = /* @__PURE__ */ jsx("div", {
570
+ ref,
571
+ className: t10,
572
+ children: t32
573
+ });
574
+ $[52] = t10;
575
+ $[53] = t32;
576
+ $[54] = t33;
577
+ } else t33 = $[54];
578
+ return t33;
550
579
  }
551
580
 
552
581
  //#endregion
@@ -93,6 +93,11 @@ export interface RuntimeOptions {
93
93
  rendererClientEntryUrl?: string;
94
94
  getCamoxApp?: () => Promise<CamoxApp>;
95
95
  getDocument?: () => Promise<CamoxDocument>;
96
+ /**
97
+ * The app's stylesheet, compiled, which page images render with: a `toImage` styles its
98
+ * elements with the same classes as the site.
99
+ */
100
+ getImageStylesheet?: () => Promise<string>;
96
101
  projectUuid?: string;
97
102
  renderPage?: (input: PageRenderInput) => Promise<string>;
98
103
  renderStudio?: (input: StudioRenderInput) => Promise<string>;
@@ -14,6 +14,7 @@ import { discoverLayoutPages, matchDerivedLayout } from "../../core/derivedRoute
14
14
  import { buildLayoutContext, curatedLayoutContext } from "../../core/layoutContext.js";
15
15
  import { buildCamoxPageHead, buildFaviconUrl, buildPageHead, buildPageMeta, createServerApiClient, createServerStudioCache, curatedMarkdownResponse, declarePage, isNotFoundError, loadCamoxPageForRequest, parseMarkdownPath, prefersMarkdown, readDraftOrLive, readPageMarkdown, readScopeLocales, renderedHref, resolveMemberProject, withFrontMatter } from "../routes/pageRuntime.js";
16
16
  import { assetPrefix } from "./assetPrefix.js";
17
+ import { documentGoogleFonts } from "../og/documentFonts.js";
17
18
  import { alternatesByPage, findAlternates, hreflangLinks } from "./alternates.js";
18
19
  import { configuredProviders, renderAnalyticsScripts } from "./analytics.js";
19
20
  import { omitArtifactSources } from "./artifactSources.js";
@@ -294,16 +295,26 @@ async function createRoutesResponse(request, options) {
294
295
  }
295
296
  /**
296
297
  * The image of the page `/og?path=` names, by its path with its locale's prefix: its layout's
297
- * `toImage`, or Camox's default image, rendered with the page's context. Only real pages have
298
- * one, read as the page itself would be, in the draft the URL names for a member.
298
+ * `toImage`, or Camox's default image, rendered with the page's context and the site's
299
+ * stylesheet and fonts. Only real pages have one, read as the page itself would be, in the draft
300
+ * the URL names for a member.
299
301
  */
300
302
  async function createOgResponse(request, options) {
301
303
  const camoxApp = await options.getCamoxApp?.();
302
304
  if (!camoxApp) return Response.json({ message: "Camox app registry is not available." }, { status: 500 });
303
305
  const source = await readPageImageSource(request, options, camoxApp);
304
306
  if (!source) return new Response("Not found", { status: 404 });
307
+ const [css, document] = await Promise.all([options.getImageStylesheet?.(), options.getDocument?.()]);
308
+ const style = {
309
+ css,
310
+ fonts: documentGoogleFonts(document ?? {})
311
+ };
305
312
  const headers = {
306
- ETag: await etagOf(JSON.stringify([source.layout?.id ?? null, source.context])),
313
+ ETag: await etagOf(JSON.stringify([
314
+ source.layout?.id ?? null,
315
+ source.context,
316
+ style
317
+ ])),
307
318
  "Cache-Control": isPrivateRender(request, options) ? "private, no-store" : "public, no-cache"
308
319
  };
309
320
  if (namesEtag(request, headers.ETag)) return new Response(null, {
@@ -311,7 +322,7 @@ async function createOgResponse(request, options) {
311
322
  headers
312
323
  });
313
324
  const toImage = source.layout?.toImage ?? DefaultPageImage;
314
- const image = await renderPageImage(toImage(source.context));
325
+ const image = await renderPageImage(toImage(source.context), style);
315
326
  for (const [name, value] of Object.entries(headers)) image.headers.set(name, value);
316
327
  return image;
317
328
  }
@@ -7,6 +7,7 @@ import { BOTTOM_CARD_EDGES, CARD_BODY_EDGES, SIDEBAR_GUTTER } from "../../previe
7
7
  import { draftLabel } from "../draftLabel.js";
8
8
  import { FollowAgentContext } from "../followAgentContext.js";
9
9
  import { useThread } from "../../../lib/use-thread.js";
10
+ import { Squareling } from "./Squareling.js";
10
11
  import { ThreadComposer } from "./ThreadComposer.js";
11
12
  import { ThreadMessages } from "./ThreadMessages.js";
12
13
  import { c } from "react/compiler-runtime";
@@ -34,9 +35,12 @@ function ChatSidebar(t0) {
34
35
  t3 = { width: 265 };
35
36
  t4 = /* @__PURE__ */ jsxs("header", {
36
37
  className: cn("bg-background flex h-11 min-w-0 shrink-0 items-center justify-center gap-2 px-3", BOTTOM_CARD_EDGES),
37
- children: [/* @__PURE__ */ jsx(CamoxMark, {}), /* @__PURE__ */ jsx("h2", {
38
+ children: [/* @__PURE__ */ jsx(Squareling, {
39
+ status: "idle",
40
+ className: "size-5"
41
+ }), /* @__PURE__ */ jsx("h2", {
38
42
  className: "truncate text-sm font-medium",
39
- children: "Chat"
43
+ children: "Agent"
40
44
  })]
41
45
  });
42
46
  t5 = /* @__PURE__ */ jsx("div", {
@@ -56,7 +60,7 @@ function ChatSidebar(t0) {
56
60
  let t6;
57
61
  if ($[4] !== hidden) {
58
62
  t6 = /* @__PURE__ */ jsxs("aside", {
59
- "aria-label": "Chat",
63
+ "aria-label": "Agent",
60
64
  "data-chat-sidebar": true,
61
65
  hidden,
62
66
  className: t2,
@@ -68,25 +72,6 @@ function ChatSidebar(t0) {
68
72
  } else t6 = $[5];
69
73
  return t6;
70
74
  }
71
- /** Camox's logo, beside the heading: the agent is Camox. */
72
- function CamoxMark() {
73
- const $ = c(1);
74
- let t0;
75
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
76
- t0 = /* @__PURE__ */ jsx("svg", {
77
- "aria-hidden": true,
78
- viewBox: "0 0 191.03 132",
79
- className: "size-5 shrink-0",
80
- xmlns: "http://www.w3.org/2000/svg",
81
- children: /* @__PURE__ */ jsx("path", {
82
- d: "M0 22.55A22.55 22.55 0 0 1 22.55 0L90.19 0A5.32 5.32 0 0 1 95.52 5.32L95.52 36.48L36.48 36.48L36.48 95.52L5.32 95.52A5.32 5.32 0 0 1 0 90.19ZM95.52 36.48L181.48 36.48A5.32 5.32 0 0 1 186.01 44.61L138.61 121.31A22.55 22.55 0 0 1 119.43 132L41.81 132A5.32 5.32 0 0 1 36.48 126.68L36.48 95.52L95.52 95.52Z",
83
- fill: "#00BC7D"
84
- })
85
- });
86
- $[0] = t0;
87
- } else t0 = $[0];
88
- return t0;
89
- }
90
75
  function CurrentThread() {
91
76
  const $ = c(15);
92
77
  const { apiUrl, projectUuid } = React.useContext(AuthContext);
@@ -164,7 +149,7 @@ function CurrentThread() {
164
149
  return t6;
165
150
  }
166
151
  function Thread(t0) {
167
- const $ = c(31);
152
+ const $ = c(30);
168
153
  const { apiUrl, projectId, draftId, carried, onEnterDraft } = t0;
169
154
  let t1;
170
155
  if ($[0] !== carried || $[1] !== onEnterDraft) {
@@ -212,68 +197,65 @@ function Thread(t0) {
212
197
  $[12] = t5;
213
198
  } else t5 = $[12];
214
199
  const sendFollowing = t5;
215
- const t6 = draftId !== null;
216
- let t7;
217
- if ($[13] !== sending || $[14] !== t6 || $[15] !== view) {
218
- t7 = {
200
+ let t6;
201
+ if ($[13] !== sending || $[14] !== view) {
202
+ t6 = {
219
203
  view,
220
- sending,
221
- showSenders: t6
204
+ sending
222
205
  };
223
206
  $[13] = sending;
224
- $[14] = t6;
225
- $[15] = view;
226
- $[16] = t7;
227
- } else t7 = $[16];
228
- const messages = t7;
207
+ $[14] = view;
208
+ $[15] = t6;
209
+ } else t6 = $[15];
210
+ const messages = t6;
229
211
  const continuedIn = draftId === null ? view.continuedIn?.draftId : void 0;
230
- let t8;
231
- if ($[17] !== continuedIn || $[18] !== messages || $[19] !== projectId) {
232
- t8 = continuedIn ? /* @__PURE__ */ jsx(ContinuedInMessages, {
212
+ let t7;
213
+ if ($[16] !== continuedIn || $[17] !== messages || $[18] !== projectId) {
214
+ t7 = continuedIn ? /* @__PURE__ */ jsx(ContinuedInMessages, {
233
215
  ...messages,
234
216
  projectId,
235
217
  draftId: continuedIn
236
218
  }) : /* @__PURE__ */ jsx(ThreadMessages, { ...messages });
237
- $[17] = continuedIn;
238
- $[18] = messages;
239
- $[19] = projectId;
240
- $[20] = t8;
241
- } else t8 = $[20];
242
- let t9;
243
- if ($[21] !== error) {
244
- t9 = error && /* @__PURE__ */ jsx("p", {
219
+ $[16] = continuedIn;
220
+ $[17] = messages;
221
+ $[18] = projectId;
222
+ $[19] = t7;
223
+ } else t7 = $[19];
224
+ let t8;
225
+ if ($[20] !== error) {
226
+ t8 = error && /* @__PURE__ */ jsx("p", {
245
227
  role: "alert",
246
228
  className: "text-destructive px-2 pt-2 text-sm",
247
229
  children: error
248
230
  });
249
- $[21] = error;
250
- $[22] = t9;
251
- } else t9 = $[22];
252
- let t10;
253
- if ($[23] !== sendFollowing || $[24] !== stop || $[25] !== view.running) {
254
- t10 = /* @__PURE__ */ jsx(ThreadComposer, {
231
+ $[20] = error;
232
+ $[21] = t8;
233
+ } else t8 = $[21];
234
+ let t9;
235
+ if ($[22] !== sendFollowing || $[23] !== stop || $[24] !== view.running) {
236
+ t9 = /* @__PURE__ */ jsx(ThreadComposer, {
255
237
  onSend: sendFollowing,
256
238
  onStop: stop,
257
239
  running: view.running
258
240
  });
259
- $[23] = sendFollowing;
260
- $[24] = stop;
261
- $[25] = view.running;
262
- $[26] = t10;
263
- } else t10 = $[26];
264
- let t11;
265
- if ($[27] !== t10 || $[28] !== t8 || $[29] !== t9) {
266
- t11 = /* @__PURE__ */ jsxs(Fragment, { children: [
241
+ $[22] = sendFollowing;
242
+ $[23] = stop;
243
+ $[24] = view.running;
244
+ $[25] = t9;
245
+ } else t9 = $[25];
246
+ let t10;
247
+ if ($[26] !== t7 || $[27] !== t8 || $[28] !== t9) {
248
+ t10 = /* @__PURE__ */ jsxs(Fragment, { children: [
249
+ t7,
267
250
  t8,
268
- t9,
269
- t10
251
+ t9
270
252
  ] });
271
- $[27] = t10;
272
- $[28] = t8;
273
- $[29] = t9;
274
- $[30] = t11;
275
- } else t11 = $[30];
276
- return t11;
253
+ $[26] = t7;
254
+ $[27] = t8;
255
+ $[28] = t9;
256
+ $[29] = t10;
257
+ } else t10 = $[29];
258
+ return t10;
277
259
  }
278
260
  /**
279
261
  * A fresh Live thread's messages, linking to the draft the editor's previous one continued in,
@@ -0,0 +1,114 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+
5
+ //#region src/features/studio/components/Squareling.tsx
6
+ /**
7
+ * Camox's agent, drawn from the logo's shapes: its square, the soft corner, and the knockout as
8
+ * eyes, looking right like the mark. Its face and motion say what the agent is doing. The
9
+ * animations live in `studio.css`.
10
+ */
11
+ function Squareling(t0) {
12
+ const $ = c(17);
13
+ const { status, className } = t0;
14
+ let t1;
15
+ if ($[0] !== className) {
16
+ t1 = cn("squareling shrink-0 overflow-visible", className);
17
+ $[0] = className;
18
+ $[1] = t1;
19
+ } else t1 = $[1];
20
+ let t2;
21
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
22
+ t2 = /* @__PURE__ */ jsx("path", {
23
+ d: "M20 12H80Q88 12 88 20V64Q88 88 64 88H20Q12 88 12 80V20Q12 12 20 12Z",
24
+ className: "fill-emerald-500"
25
+ });
26
+ $[2] = t2;
27
+ } else t2 = $[2];
28
+ let t3;
29
+ if ($[3] !== status) {
30
+ t3 = (status === "idle" || status === "thinking") && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("rect", {
31
+ className: "squareling-eye",
32
+ x: "50",
33
+ y: "36",
34
+ width: "11",
35
+ height: "17"
36
+ }), /* @__PURE__ */ jsx("rect", {
37
+ className: "squareling-eye",
38
+ x: "69",
39
+ y: "36",
40
+ width: "11",
41
+ height: "17"
42
+ })] });
43
+ $[3] = status;
44
+ $[4] = t3;
45
+ } else t3 = $[4];
46
+ let t4;
47
+ if ($[5] !== status) {
48
+ t4 = status === "acting" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("rect", {
49
+ x: "50",
50
+ y: "44",
51
+ width: "11",
52
+ height: "6"
53
+ }), /* @__PURE__ */ jsx("rect", {
54
+ x: "69",
55
+ y: "44",
56
+ width: "11",
57
+ height: "6"
58
+ })] });
59
+ $[5] = status;
60
+ $[6] = t4;
61
+ } else t4 = $[6];
62
+ let t5;
63
+ if ($[7] !== status) {
64
+ t5 = status === "fixing" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("rect", {
65
+ x: "50",
66
+ y: "36",
67
+ width: "11",
68
+ height: "17"
69
+ }), /* @__PURE__ */ jsx("rect", {
70
+ x: "69",
71
+ y: "44",
72
+ width: "11",
73
+ height: "6"
74
+ })] });
75
+ $[7] = status;
76
+ $[8] = t5;
77
+ } else t5 = $[8];
78
+ let t6;
79
+ if ($[9] !== t3 || $[10] !== t4 || $[11] !== t5) {
80
+ t6 = /* @__PURE__ */ jsxs("g", {
81
+ className: "squareling-body",
82
+ children: [t2, /* @__PURE__ */ jsxs("g", {
83
+ className: "squareling-eyes fill-neutral-950",
84
+ children: [
85
+ t3,
86
+ t4,
87
+ t5
88
+ ]
89
+ })]
90
+ });
91
+ $[9] = t3;
92
+ $[10] = t4;
93
+ $[11] = t5;
94
+ $[12] = t6;
95
+ } else t6 = $[12];
96
+ let t7;
97
+ if ($[13] !== status || $[14] !== t1 || $[15] !== t6) {
98
+ t7 = /* @__PURE__ */ jsx("svg", {
99
+ viewBox: "0 0 100 100",
100
+ "aria-hidden": true,
101
+ "data-squareling": status,
102
+ className: t1,
103
+ children: t6
104
+ });
105
+ $[13] = status;
106
+ $[14] = t1;
107
+ $[15] = t6;
108
+ $[16] = t7;
109
+ } else t7 = $[16];
110
+ return t7;
111
+ }
112
+
113
+ //#endregion
114
+ export { Squareling };