@the-portland-company/shell 0.65.0 → 0.66.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.
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { broadcastLogout, watchLogout } from './chunk-LL6LSJAH.js';
3
- import { clearBetaBannerDismissal, standardPolitogyNav, isNavItemActive, NavAppShell, NavChromeProvider, FuelAction, NavDisplayAction, TopBarWidgetSlot, SpecOverlayAction, SupportAction, NotificationsAction, useChromeMe, useThemePreference, useNavChromeFetcher, useChromeOrgs } from './chunk-XK2LWTHJ.js';
3
+ import { clearBetaBannerDismissal, standardPolitogyNav, isNavItemActive, NavAppShell, NavChromeProvider, FuelAction, NavDisplayAction, TopBarWidgetSlot, SpecOverlayAction, SupportAction, NotificationsAction, useChromeMe, useThemePreference, useNavChromeFetcher, useChromeOrgs } from './chunk-SMZ5VNVH.js';
4
4
  import './chunk-JHIFJZ73.js';
5
5
  import { NAV_DISPLAY_DEFAULT, resolveNavDisplay, isNavDisplayPreference, writeNavDisplayCookie, writeNavDisplayLocal, NAV_DISPLAY_STORAGE_KEY, readNavDisplayCookie } from './chunk-6UHJV2FH.js';
6
6
  import { resolveActiveOrg, isOrgId, writeActiveOrgCookie, ACTIVE_ORG_QUERY_PARAM, readActiveOrgCookie } from './chunk-W2HITMV5.js';
@@ -1275,11 +1275,14 @@ function useLocationHref() {
1275
1275
  return href;
1276
1276
  }
1277
1277
  function specOverlayFetchJson(path) {
1278
- return fetch(`${SPECS_ORIGIN}${path}`, { credentials: "include" }).then((res) => {
1278
+ return fetch(`${SPECS_ORIGIN}${path}`, { credentials: "include", signal: AbortSignal.timeout(1e4) }).then((res) => {
1279
1279
  if (!res.ok) throw new Error(`spec overlay ${path}: ${res.status}`);
1280
1280
  return res.json();
1281
1281
  });
1282
1282
  }
1283
+ function isAutomatedCaptureSession() {
1284
+ return typeof navigator !== "undefined" && navigator.webdriver === true;
1285
+ }
1283
1286
  function currentChromeTheme() {
1284
1287
  const root = document.documentElement;
1285
1288
  if (root.classList.contains("dark") || root.getAttribute("data-theme") === "dark") return "dark";
@@ -1331,7 +1334,8 @@ async function captureMyView(status, orgId, orgName) {
1331
1334
  method: "POST",
1332
1335
  credentials: "include",
1333
1336
  headers: { "X-Spec-Capture": "1" },
1334
- body: form
1337
+ body: form,
1338
+ signal: AbortSignal.timeout(1e4)
1335
1339
  });
1336
1340
  if (!res.ok) throw new Error(`capture ${res.status}: ${(await res.text()).slice(0, 160)}`);
1337
1341
  }
@@ -1364,8 +1368,9 @@ function SpecOverlayAction({ orgId, orgName } = {}) {
1364
1368
  const [frameKey, setFrameKey] = useState(0);
1365
1369
  const [copied, setCopied] = useState("idle");
1366
1370
  const href = useLocationHref();
1371
+ const automated = isAutomatedCaptureSession();
1367
1372
  useEffect(() => {
1368
- if (access) return;
1373
+ if (access || automated) return;
1369
1374
  let cancelled = false;
1370
1375
  specOverlayFetchJson("/api/overlay/access").then((data) => {
1371
1376
  if (cancelled) return;
@@ -1383,7 +1388,7 @@ function SpecOverlayAction({ orgId, orgName } = {}) {
1383
1388
  };
1384
1389
  }, [access]);
1385
1390
  useEffect(() => {
1386
- if (!access?.allowed || typeof window === "undefined") return;
1391
+ if (automated || !access?.allowed || typeof window === "undefined") return;
1387
1392
  const timer = window.setTimeout(() => {
1388
1393
  specOverlayFetchJson(specOverlayStatusPath()).then((data) => setStatus(data)).catch(() => setStatus(null));
1389
1394
  }, 300);
@@ -1414,13 +1419,13 @@ function SpecOverlayAction({ orgId, orgName } = {}) {
1414
1419
  }
1415
1420
  };
1416
1421
  useEffect(() => {
1417
- if (!open || !status || !status.matched) return;
1422
+ if (automated || !open || !status || !status.matched) return;
1418
1423
  void runCapture(status);
1419
1424
  return () => {
1420
1425
  captureRun.current++;
1421
1426
  };
1422
1427
  }, [open, status && status.matched ? status.target_id : null]);
1423
- if (!access?.allowed) return null;
1428
+ if (automated || !access?.allowed) return null;
1424
1429
  const badgeLabel = status && status.matched ? `${Math.round(status.mismatch_pct)}%` : status ? "\u2014" : void 0;
1425
1430
  const badgeTone = status && status.matched ? status.passed ? "default" : "danger" : "default";
1426
1431
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -2116,8 +2121,8 @@ function NavSidebar({
2116
2121
  };
2117
2122
  const activeFn = nav.isActive ?? isNavItemActive;
2118
2123
  const ModeIcon = mode?.icon;
2119
- const orgBg = org?.brandColor || ORG_PILL_DEFAULT;
2120
2124
  const orgLogoSrc = resolveOrgLogoUrl(org?.logoUrl);
2125
+ const orgGradient = org?.brandColor ? `linear-gradient(to right, ${org.brandColor}, ${org.brandColorSecondary || org.brandColor})` : "linear-gradient(to right, #007BFF, #A54B7A, #E63946)";
2121
2126
  const activeGroupKey = useMemo(() => {
2122
2127
  for (let i = 0; i < nav.items.length; i++) {
2123
2128
  const item = nav.items[i];
@@ -2213,29 +2218,33 @@ function NavSidebar({
2213
2218
  ),
2214
2219
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading organization" })
2215
2220
  ] }) : org.organizations && org.organizations.length > 0 && org.onSwitch ? /* @__PURE__ */ jsxs("details", { "data-nav-details": true, className: "group relative", children: [
2216
- /* @__PURE__ */ 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: [
2217
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [
2218
- /* @__PURE__ */ jsx(
2219
- "span",
2221
+ /* @__PURE__ */ 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: [
2222
+ /* @__PURE__ */ jsxs("span", { className: "relative flex h-[70px] w-full items-center justify-center bg-white px-3", children: [
2223
+ orgLogoSrc ? /* @__PURE__ */ jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-[70px] max-w-full object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsx(
2224
+ "a",
2220
2225
  {
2221
- style: { backgroundColor: orgBg },
2222
- className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full text-[11px] font-bold text-white",
2223
- children: orgLogoSrc ? /* @__PURE__ */ jsx("img", { src: orgLogoSrc, alt: "", className: "h-full w-full object-cover" }) : (org.name ?? "Org").slice(0, 2).toUpperCase()
2226
+ href: org.uploadLogoHref ?? "#",
2227
+ onClick: (e) => e.stopPropagation(),
2228
+ className: "text-xs font-semibold text-[color:var(--color-accent)] underline",
2229
+ children: "Upload logo"
2224
2230
  }
2225
- ),
2231
+ ) : /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2232
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2233
+ ] }),
2234
+ /* @__PURE__ */ jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-2 px-2.5 py-2", children: [
2226
2235
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
2227
2236
  /* @__PURE__ */ jsx(
2228
2237
  "span",
2229
2238
  {
2230
2239
  title: org.name ?? void 0,
2231
- className: "truncate text-sm font-semibold",
2240
+ className: "truncate text-[13px] font-semibold",
2232
2241
  children: org.name ?? "No organizations"
2233
2242
  }
2234
2243
  ),
2235
2244
  org.id && !org.loading ? /* @__PURE__ */ jsx(OrgIdCopyButton, { id: org.id }) : null
2236
- ] })
2237
- ] }),
2238
- /* @__PURE__ */ jsx(ChevronDown, {})
2245
+ ] }),
2246
+ /* @__PURE__ */ jsx(ChevronDown, {})
2247
+ ] })
2239
2248
  ] }),
2240
2249
  /* @__PURE__ */ 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: [
2241
2250
  shouldShowOrgFilter(org.organizations.length) ? /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 bg-[color:var(--panel-elevated)] px-2 pb-1 pt-1", children: /* @__PURE__ */ jsx(
@@ -2305,60 +2314,76 @@ function NavSidebar({
2305
2314
  {
2306
2315
  type: "button",
2307
2316
  onClick: org.onClick,
2308
- 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)]",
2317
+ 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)]",
2309
2318
  children: [
2310
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [
2311
- /* @__PURE__ */ jsx(
2312
- "span",
2319
+ /* @__PURE__ */ jsxs("span", { className: "relative flex h-[70px] w-full items-center justify-center bg-white px-3", children: [
2320
+ orgLogoSrc ? /* @__PURE__ */ jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-[70px] max-w-full object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsx(
2321
+ "a",
2313
2322
  {
2314
- style: { backgroundColor: orgBg },
2315
- className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full text-[11px] font-bold text-white",
2316
- children: orgLogoSrc ? /* @__PURE__ */ jsx("img", { src: orgLogoSrc, alt: "", className: "h-full w-full object-cover" }) : (org.name ?? "Org").slice(0, 2).toUpperCase()
2323
+ href: org.uploadLogoHref ?? "#",
2324
+ onClick: (e) => e.stopPropagation(),
2325
+ className: "text-xs font-semibold text-[color:var(--color-accent)] underline",
2326
+ children: "Upload logo"
2317
2327
  }
2318
- ),
2328
+ ) : /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2329
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2330
+ ] }),
2331
+ /* @__PURE__ */ jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-2 px-2.5 py-2", children: [
2319
2332
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
2320
2333
  /* @__PURE__ */ jsx(
2321
2334
  "span",
2322
2335
  {
2323
2336
  title: org.name ?? void 0,
2324
- className: "truncate text-sm font-semibold",
2337
+ className: "truncate text-[13px] font-semibold",
2325
2338
  children: org.name ?? "No organizations"
2326
2339
  }
2327
2340
  ),
2328
2341
  org.id && !org.loading ? /* @__PURE__ */ jsx(OrgIdCopyButton, { id: org.id }) : null
2329
- ] })
2330
- ] }),
2331
- /* @__PURE__ */ jsx(ChevronDown, {})
2342
+ ] }),
2343
+ /* @__PURE__ */ jsx(ChevronDown, {})
2344
+ ] })
2332
2345
  ]
2333
2346
  }
2334
2347
  )
2335
2348
  ] }) : null,
2336
2349
  mode ? /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
2337
- /* @__PURE__ */ 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(
2338
- (opt) => {
2339
- const selected = opt.label === mode.label;
2340
- const OptIcon = opt.icon;
2341
- return /* @__PURE__ */ jsx(
2342
- "button",
2343
- {
2344
- type: "button",
2345
- title: opt.label,
2346
- "aria-label": opt.label,
2347
- "aria-current": selected ? "true" : void 0,
2348
- onClick: () => {
2349
- if (!selected) mode.onSelect?.(opt.id);
2350
- },
2351
- disabled: !mode.onSelect && !selected,
2352
- className: [
2353
- "flex h-9 flex-1 items-center justify-center rounded transition",
2354
- 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))]"
2355
- ].join(" "),
2356
- children: OptIcon ? /* @__PURE__ */ jsx(OptIcon, { size: 16, className: "shrink-0" }) : null
2357
- },
2358
- opt.id
2359
- );
2350
+ /* @__PURE__ */ jsx(
2351
+ "div",
2352
+ {
2353
+ role: "radiogroup",
2354
+ "aria-label": "Mode",
2355
+ 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]",
2356
+ children: (mode.options && mode.options.length > 0 ? mode.options : [{ id: mode.label, label: mode.label, icon: ModeIcon }]).map(
2357
+ (opt) => {
2358
+ const selected = opt.label === mode.label;
2359
+ const OptIcon = opt.icon;
2360
+ const available = opt.available ?? true;
2361
+ const title = !available ? opt.unavailableTooltip ?? `${opt.label} isn't active for this organization.` : opt.label;
2362
+ return /* @__PURE__ */ jsx(
2363
+ "button",
2364
+ {
2365
+ type: "button",
2366
+ role: "radio",
2367
+ title,
2368
+ "aria-label": title,
2369
+ "aria-checked": selected,
2370
+ "aria-current": selected ? "true" : void 0,
2371
+ onClick: () => {
2372
+ if (available && !selected) mode.onSelect?.(opt.id);
2373
+ },
2374
+ disabled: !available,
2375
+ className: [
2376
+ "flex h-9 items-center justify-center rounded px-[9px] py-[6px] transition",
2377
+ !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))]"
2378
+ ].join(" "),
2379
+ children: OptIcon ? /* @__PURE__ */ jsx(OptIcon, { size: 15, className: "shrink-0" }) : null
2380
+ },
2381
+ opt.id
2382
+ );
2383
+ }
2384
+ )
2360
2385
  }
2361
- ) }),
2386
+ ),
2362
2387
  /* @__PURE__ */ 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 })
2363
2388
  ] }) : null,
2364
2389
  /* @__PURE__ */ jsxs("nav", { className: "flex flex-col gap-1", children: [
@@ -3432,5 +3457,5 @@ function NavAppShell({
3432
3457
  }
3433
3458
 
3434
3459
  export { BETA_BANNER_DISMISS_KEY, CAMPAIGN_FEATURE_AVAILABILITY, CORE_APP_ORIGIN, CORE_BILLING_PATH, FuelAction, NavAppShell, NavBetaBanner, NavChromeProvider, NavDisplayAction, NavSidebar, NavTabStrip, NavThemeControl, NavTopBar, NotificationsAction, SPECS_ORIGIN, SpecOverlayAction, SupportAction, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, clearBetaBannerDismissal, envChipClasses, isNavItemActive, resolveOrgLogoUrl, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
3435
- //# sourceMappingURL=chunk-XK2LWTHJ.js.map
3436
- //# sourceMappingURL=chunk-XK2LWTHJ.js.map
3460
+ //# sourceMappingURL=chunk-SMZ5VNVH.js.map
3461
+ //# sourceMappingURL=chunk-SMZ5VNVH.js.map