@the-portland-company/shell 0.65.1 → 0.66.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.
@@ -1488,6 +1488,8 @@ function SpecOverlayAction({ orgId, orgName } = {}) {
1488
1488
  return () => window.clearTimeout(timer);
1489
1489
  }, [access?.allowed, href, orgId]);
1490
1490
  const captureRun = react.useRef(0);
1491
+ const accessRef = react.useRef(access);
1492
+ accessRef.current = access;
1491
1493
  const runCapture = async (s) => {
1492
1494
  const run = ++captureRun.current;
1493
1495
  const before = s.live_source === "viewer" ? s.finished_at : null;
@@ -1498,6 +1500,7 @@ function SpecOverlayAction({ orgId, orgName } = {}) {
1498
1500
  for (let i = 0; i < 45; i++) {
1499
1501
  await new Promise((r) => setTimeout(r, 3e3));
1500
1502
  if (run !== captureRun.current) return;
1503
+ if (!accessRef.current?.allowed) return;
1501
1504
  const next = await specOverlayFetchJson(specOverlayStatusPath()).catch(() => null);
1502
1505
  if (next && next.matched && next.live_source === "viewer" && next.finished_at !== before) {
1503
1506
  setStatus(next);
@@ -2214,8 +2217,8 @@ function NavSidebar({
2214
2217
  };
2215
2218
  const activeFn = nav.isActive ?? isNavItemActive;
2216
2219
  const ModeIcon = mode?.icon;
2217
- const orgBg = org?.brandColor || ORG_PILL_DEFAULT;
2218
2220
  const orgLogoSrc = resolveOrgLogoUrl(org?.logoUrl);
2221
+ const orgGradient = org?.brandColor ? `linear-gradient(to right, ${org.brandColor}, ${org.brandColorSecondary || org.brandColor})` : "linear-gradient(to right, #007BFF, #A54B7A, #E63946)";
2219
2222
  const activeGroupKey = react.useMemo(() => {
2220
2223
  for (let i = 0; i < nav.items.length; i++) {
2221
2224
  const item = nav.items[i];
@@ -2311,29 +2314,33 @@ function NavSidebar({
2311
2314
  ),
2312
2315
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading organization" })
2313
2316
  ] }) : org.organizations && org.organizations.length > 0 && org.onSwitch ? /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group relative", children: [
2314
- /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex w-full cursor-pointer list-none items-center justify-between gap-2 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 text-left text-[color:var(--foreground)] shadow-sm transition hover:bg-[color:var(--panel)] [&::-webkit-details-marker]:hidden", children: [
2315
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [
2316
- /* @__PURE__ */ jsxRuntime.jsx(
2317
- "span",
2317
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex w-full cursor-pointer list-none flex-col overflow-hidden rounded-[5px] border border-[color:var(--line)] bg-[color:var(--panel-elevated)] text-left text-[color:var(--foreground)] shadow-sm transition hover:bg-[color:var(--panel)] [&::-webkit-details-marker]:hidden", children: [
2318
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-[70px] w-full items-center justify-center bg-white px-3", children: [
2319
+ orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-[70px] max-w-full object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
2320
+ "a",
2318
2321
  {
2319
- style: { backgroundColor: orgBg },
2320
- className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full text-[11px] font-bold text-white",
2321
- children: orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "h-full w-full object-cover" }) : (org.name ?? "Org").slice(0, 2).toUpperCase()
2322
+ href: org.uploadLogoHref ?? "#",
2323
+ onClick: (e) => e.stopPropagation(),
2324
+ className: "text-xs font-semibold text-[color:var(--color-accent)] underline",
2325
+ children: "Upload logo"
2322
2326
  }
2323
- ),
2327
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2328
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2329
+ ] }),
2330
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-2 px-2.5 py-2", children: [
2324
2331
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
2325
2332
  /* @__PURE__ */ jsxRuntime.jsx(
2326
2333
  "span",
2327
2334
  {
2328
2335
  title: org.name ?? void 0,
2329
- className: "truncate text-sm font-semibold",
2336
+ className: "truncate text-[13px] font-semibold",
2330
2337
  children: org.name ?? "No organizations"
2331
2338
  }
2332
2339
  ),
2333
2340
  org.id && !org.loading ? /* @__PURE__ */ jsxRuntime.jsx(OrgIdCopyButton, { id: org.id }) : null
2334
- ] })
2335
- ] }),
2336
- /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {})
2341
+ ] }),
2342
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {})
2343
+ ] })
2337
2344
  ] }),
2338
2345
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 right-0 z-40 mt-1 max-h-[min(60vh,520px)] overflow-y-auto rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: [
2339
2346
  shouldShowOrgFilter(org.organizations.length) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-[color:var(--panel-elevated)] px-2 pb-1 pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2403,60 +2410,76 @@ function NavSidebar({
2403
2410
  {
2404
2411
  type: "button",
2405
2412
  onClick: org.onClick,
2406
- className: "flex w-full items-center justify-between gap-2 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 text-left text-[color:var(--foreground)] shadow-sm transition hover:bg-[color:var(--panel)]",
2413
+ className: "flex w-full flex-col overflow-hidden rounded-[5px] border border-[color:var(--line)] bg-[color:var(--panel-elevated)] text-left text-[color:var(--foreground)] shadow-sm transition hover:bg-[color:var(--panel)]",
2407
2414
  children: [
2408
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [
2409
- /* @__PURE__ */ jsxRuntime.jsx(
2410
- "span",
2415
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-[70px] w-full items-center justify-center bg-white px-3", children: [
2416
+ orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-[70px] max-w-full object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
2417
+ "a",
2411
2418
  {
2412
- style: { backgroundColor: orgBg },
2413
- className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full text-[11px] font-bold text-white",
2414
- children: orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "h-full w-full object-cover" }) : (org.name ?? "Org").slice(0, 2).toUpperCase()
2419
+ href: org.uploadLogoHref ?? "#",
2420
+ onClick: (e) => e.stopPropagation(),
2421
+ className: "text-xs font-semibold text-[color:var(--color-accent)] underline",
2422
+ children: "Upload logo"
2415
2423
  }
2416
- ),
2424
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2425
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2426
+ ] }),
2427
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-2 px-2.5 py-2", children: [
2417
2428
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
2418
2429
  /* @__PURE__ */ jsxRuntime.jsx(
2419
2430
  "span",
2420
2431
  {
2421
2432
  title: org.name ?? void 0,
2422
- className: "truncate text-sm font-semibold",
2433
+ className: "truncate text-[13px] font-semibold",
2423
2434
  children: org.name ?? "No organizations"
2424
2435
  }
2425
2436
  ),
2426
2437
  org.id && !org.loading ? /* @__PURE__ */ jsxRuntime.jsx(OrgIdCopyButton, { id: org.id }) : null
2427
- ] })
2428
- ] }),
2429
- /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {})
2438
+ ] }),
2439
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {})
2440
+ ] })
2430
2441
  ]
2431
2442
  }
2432
2443
  )
2433
2444
  ] }) : null,
2434
2445
  mode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
2435
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center gap-2 rounded-md bg-[color:var(--panel-elevated)] p-1", children: (mode.options && mode.options.length > 0 ? mode.options : [{ id: mode.label, label: mode.label, icon: ModeIcon }]).map(
2436
- (opt) => {
2437
- const selected = opt.label === mode.label;
2438
- const OptIcon = opt.icon;
2439
- return /* @__PURE__ */ jsxRuntime.jsx(
2440
- "button",
2441
- {
2442
- type: "button",
2443
- title: opt.label,
2444
- "aria-label": opt.label,
2445
- "aria-current": selected ? "true" : void 0,
2446
- onClick: () => {
2447
- if (!selected) mode.onSelect?.(opt.id);
2448
- },
2449
- disabled: !mode.onSelect && !selected,
2450
- className: [
2451
- "flex h-9 flex-1 items-center justify-center rounded transition",
2452
- selected ? "bg-[color:var(--mode-accent,var(--color-accent))] text-[color:var(--mode-on-accent,white)] shadow-sm" : "text-[color:var(--sidebar-text-muted,var(--muted))] hover:bg-[color:var(--panel)] hover:text-[color:var(--sidebar-text,var(--foreground))]"
2453
- ].join(" "),
2454
- children: OptIcon ? /* @__PURE__ */ jsxRuntime.jsx(OptIcon, { size: 16, className: "shrink-0" }) : null
2455
- },
2456
- opt.id
2457
- );
2446
+ /* @__PURE__ */ jsxRuntime.jsx(
2447
+ "div",
2448
+ {
2449
+ role: "radiogroup",
2450
+ "aria-label": "Mode",
2451
+ className: "flex items-center justify-start gap-0.5 rounded-lg border border-[color:var(--border-inverse,var(--line))] bg-[color:var(--mode-track-bg,var(--panel-elevated))] p-[3px]",
2452
+ children: (mode.options && mode.options.length > 0 ? mode.options : [{ id: mode.label, label: mode.label, icon: ModeIcon }]).map(
2453
+ (opt) => {
2454
+ const selected = opt.label === mode.label;
2455
+ const OptIcon = opt.icon;
2456
+ const available = opt.available ?? true;
2457
+ const title = !available ? opt.unavailableTooltip ?? `${opt.label} isn't active for this organization.` : opt.label;
2458
+ return /* @__PURE__ */ jsxRuntime.jsx(
2459
+ "button",
2460
+ {
2461
+ type: "button",
2462
+ role: "radio",
2463
+ title,
2464
+ "aria-label": title,
2465
+ "aria-checked": selected,
2466
+ "aria-current": selected ? "true" : void 0,
2467
+ onClick: () => {
2468
+ if (available && !selected) mode.onSelect?.(opt.id);
2469
+ },
2470
+ disabled: !available,
2471
+ className: [
2472
+ "flex h-9 items-center justify-center rounded px-[9px] py-[6px] transition",
2473
+ !available ? "cursor-not-allowed text-[color:var(--sidebar-text-muted,var(--muted))] opacity-35" : selected ? "bg-[color:var(--mode-accent,var(--color-accent))] text-[color:var(--mode-on-accent,white)] shadow-sm" : "text-[color:var(--sidebar-text-muted,var(--muted))] hover:bg-white/5 hover:text-[color:var(--sidebar-text,var(--foreground))]"
2474
+ ].join(" "),
2475
+ children: OptIcon ? /* @__PURE__ */ jsxRuntime.jsx(OptIcon, { size: 15, className: "shrink-0" }) : null
2476
+ },
2477
+ opt.id
2478
+ );
2479
+ }
2480
+ )
2458
2481
  }
2459
- ) }),
2482
+ ),
2460
2483
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-center text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--sidebar-text-muted,var(--muted))]", children: mode.label })
2461
2484
  ] }) : null,
2462
2485
  /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "flex flex-col gap-1", children: [