@the-portland-company/shell 0.64.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.
@@ -1,4 +1,4 @@
1
- import { readThemeCookie, THEME_STORAGE_KEY, isThemePreference, applyThemePreference, readPendingThemeChoice, writeThemeCookie, clearPendingThemeChoice, markThemeChoicePending } from './chunk-U4RZPZET.js';
1
+ import { readThemeCookie, THEME_STORAGE_KEY, isThemePreference, applyThemePreference, readPendingThemeChoice, writeThemeCookie, clearPendingThemeChoice, markThemeChoicePending } from './chunk-JHIFJZ73.js';
2
2
  import { createContext, useRef, useState, useEffect, useContext, useCallback, useMemo, useSyncExternalStore } from 'react';
3
3
  import clsx from 'clsx';
4
4
  import { FiUser, FiSettings, FiMessageSquare, FiMail, FiInfo, FiSun, FiMoon, FiHelpCircle, FiLifeBuoy, FiAlertCircle, FiAlertTriangle, FiBell, FiGrid, FiZap, FiBatteryCharging, FiBattery } from 'react-icons/fi';
@@ -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: [
@@ -2333,52 +2338,34 @@ function NavSidebar({
2333
2338
  }
2334
2339
  )
2335
2340
  ] }) : null,
2336
- mode ? /* @__PURE__ */ jsx("div", { className: "mb-4", children: mode.options && mode.options.length > 1 && mode.onSelect ? /* @__PURE__ */ jsxs("details", { "data-nav-details": true, className: "group relative", children: [
2337
- /* @__PURE__ */ jsxs("summary", { className: "flex w-full cursor-pointer list-none items-center justify-between gap-2 rounded-md bg-[color:var(--mode-accent,var(--color-accent))] px-2.5 py-2 text-[color:var(--mode-on-accent,white)] shadow-sm transition hover:bg-[color:var(--mode-accent-strong,var(--color-accent))] hover:opacity-95 [&::-webkit-details-marker]:hidden", children: [
2338
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2.5", children: [
2339
- ModeIcon ? /* @__PURE__ */ jsx(ModeIcon, { size: 16, className: "shrink-0" }) : null,
2340
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tracking-[-0.01em]", children: mode.label })
2341
- ] }),
2342
- /* @__PURE__ */ jsx(ChevronDown, {})
2343
- ] }),
2344
- /* @__PURE__ */ jsx("div", { className: "absolute left-0 right-0 z-40 mt-1 overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: mode.options.map((opt) => {
2345
- const selected = opt.label === mode.label;
2346
- const OptIcon = opt.icon;
2347
- return /* @__PURE__ */ jsxs(
2348
- "button",
2349
- {
2350
- type: "button",
2351
- onClick: (e) => {
2352
- e.currentTarget.closest("details")?.removeAttribute("open");
2353
- if (!selected) mode.onSelect?.(opt.id);
2341
+ mode ? /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
2342
+ /* @__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(
2343
+ (opt) => {
2344
+ const selected = opt.label === mode.label;
2345
+ const OptIcon = opt.icon;
2346
+ return /* @__PURE__ */ jsx(
2347
+ "button",
2348
+ {
2349
+ type: "button",
2350
+ title: opt.label,
2351
+ "aria-label": opt.label,
2352
+ "aria-current": selected ? "true" : void 0,
2353
+ onClick: () => {
2354
+ if (!selected) mode.onSelect?.(opt.id);
2355
+ },
2356
+ disabled: !mode.onSelect && !selected,
2357
+ className: [
2358
+ "flex h-9 flex-1 items-center justify-center rounded transition",
2359
+ 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))]"
2360
+ ].join(" "),
2361
+ children: OptIcon ? /* @__PURE__ */ jsx(OptIcon, { size: 16, className: "shrink-0" }) : null
2354
2362
  },
2355
- "aria-current": selected ? "true" : void 0,
2356
- className: [
2357
- "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm",
2358
- selected ? "font-semibold text-[color:var(--color-accent)]" : "font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]"
2359
- ].join(" "),
2360
- children: [
2361
- OptIcon ? /* @__PURE__ */ jsx(OptIcon, { size: 15, className: "shrink-0 text-current" }) : null,
2362
- opt.label
2363
- ]
2364
- },
2365
- opt.id
2366
- );
2367
- }) })
2368
- ] }) : /* @__PURE__ */ jsxs(
2369
- "button",
2370
- {
2371
- type: "button",
2372
- className: "flex w-full items-center justify-between gap-2 rounded-md bg-[color:var(--mode-accent,var(--color-accent))] px-2.5 py-2 text-[color:var(--mode-on-accent,white)] shadow-sm",
2373
- children: [
2374
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2.5", children: [
2375
- ModeIcon ? /* @__PURE__ */ jsx(ModeIcon, { size: 16, className: "shrink-0" }) : null,
2376
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tracking-[-0.01em]", children: mode.label })
2377
- ] }),
2378
- /* @__PURE__ */ jsx(ChevronDown, {})
2379
- ]
2380
- }
2381
- ) }) : null,
2363
+ opt.id
2364
+ );
2365
+ }
2366
+ ) }),
2367
+ /* @__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 })
2368
+ ] }) : null,
2382
2369
  /* @__PURE__ */ jsxs("nav", { className: "flex flex-col gap-1", children: [
2383
2370
  nav.groupLabel ? /* @__PURE__ */ jsx("p", { className: "px-2 pb-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--sidebar-text-muted,var(--muted))]", children: nav.groupLabel }) : null,
2384
2371
  nav.items.map((item, idx) => {
@@ -2526,6 +2513,27 @@ function HamburgerIcon() {
2526
2513
  }
2527
2514
  );
2528
2515
  }
2516
+ function SearchIcon({ className } = {}) {
2517
+ return /* @__PURE__ */ jsxs(
2518
+ "svg",
2519
+ {
2520
+ width: 16,
2521
+ height: 16,
2522
+ viewBox: "0 0 24 24",
2523
+ fill: "none",
2524
+ stroke: "currentColor",
2525
+ strokeWidth: 2,
2526
+ strokeLinecap: "round",
2527
+ strokeLinejoin: "round",
2528
+ className,
2529
+ "aria-hidden": "true",
2530
+ children: [
2531
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
2532
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })
2533
+ ]
2534
+ }
2535
+ );
2536
+ }
2529
2537
  function CloseIcon() {
2530
2538
  return /* @__PURE__ */ jsxs(
2531
2539
  "svg",
@@ -2820,214 +2828,231 @@ function NavTopBar({
2820
2828
  actions,
2821
2829
  themeToggle,
2822
2830
  onOpenNav,
2823
- navOpen
2831
+ navOpen,
2832
+ search,
2833
+ buildNotes
2824
2834
  }) {
2825
2835
  const rawName = user?.name?.trim() || "";
2826
2836
  const hasRealName = rawName.length > 0 && !rawName.includes("@");
2827
2837
  const displayName = hasRealName ? formatFirstLast(rawName) : user?.email ?? "Signed in";
2828
2838
  const initials = (hasRealName ? rawName : user?.email ?? "P").slice(0, 2).toUpperCase();
2829
2839
  const secondary = hasRealName ? user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member" : [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
2830
- return /* @__PURE__ */ jsxs("header", { className: "sticky top-0 z-20 flex h-20 items-center justify-between gap-4 border-b border-[color:var(--line)] bg-[color:var(--panel)] px-4 backdrop-blur-xl", children: [
2831
- onOpenNav ? /* @__PURE__ */ jsx(
2832
- "button",
2833
- {
2834
- type: "button",
2835
- onClick: onOpenNav,
2836
- "aria-label": "Open menu",
2837
- "aria-expanded": navOpen ?? false,
2838
- "aria-controls": "politogy-nav-drawer",
2839
- className: `${topBarIconButtonClass("default")} mr-3 shrink-0 lg:hidden lg:mr-0`,
2840
- children: /* @__PURE__ */ jsx(HamburgerIcon, {})
2841
- }
2842
- ) : null,
2843
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2844
- /* @__PURE__ */ jsx(
2845
- "h1",
2840
+ return /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-20", children: [
2841
+ /* @__PURE__ */ jsxs("header", { className: "flex h-[var(--topbar-height,60px)] items-center justify-between gap-4 border-b border-[color:var(--line)] bg-[color:var(--panel)] px-[var(--topbar-padding-x,20px)]", children: [
2842
+ onOpenNav ? /* @__PURE__ */ jsx(
2843
+ "button",
2846
2844
  {
2847
- className: "truncate text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]",
2848
- "data-display": "true",
2849
- children: title
2845
+ type: "button",
2846
+ onClick: onOpenNav,
2847
+ "aria-label": "Open menu",
2848
+ "aria-expanded": navOpen ?? false,
2849
+ "aria-controls": "politogy-nav-drawer",
2850
+ className: `${topBarIconButtonClass("default")} mr-1 shrink-0 lg:hidden`,
2851
+ children: /* @__PURE__ */ jsx(HamburgerIcon, {})
2850
2852
  }
2851
- ),
2852
- breadcrumbs && breadcrumbs.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "flex min-w-0 items-center gap-1.5 text-sm text-[color:var(--muted)]", children: breadcrumbs.map((b, i) => {
2853
- const last = i === breadcrumbs.length - 1;
2854
- return /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
2855
- i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[color:var(--muted)] opacity-60", children: "\u203A" }) : null,
2856
- b.href && !last ? /* @__PURE__ */ jsx(
2857
- "a",
2858
- {
2859
- href: safeHref(b.href),
2860
- className: "truncate hover:text-[color:var(--foreground)] hover:underline",
2861
- children: b.label
2862
- }
2863
- ) : /* @__PURE__ */ jsx(
2864
- "span",
2865
- {
2866
- "aria-current": last ? "page" : void 0,
2867
- className: ["truncate", last ? "text-[color:var(--foreground)]" : ""].join(" "),
2868
- children: b.label
2869
- }
2870
- )
2871
- ] }, `${b.label}-${i}`);
2872
- }) }) : subtitle ? /* @__PURE__ */ jsx("p", { className: "truncate text-sm text-[color:var(--muted)]", children: subtitle }) : null
2873
- ] }),
2874
- /* @__PURE__ */ jsxs("div", { className: "relative flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
2875
- actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsx(NavTopBarActionButton, { action }, action.key)) : null,
2876
- actions,
2877
- themeToggle,
2878
- /* @__PURE__ */ jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
2879
- /* @__PURE__ */ jsxs("summary", { className: "group/tbtip relative flex cursor-pointer list-none items-center gap-2.5 rounded-full py-1 pl-1 pr-2 transition hover:bg-[color:var(--panel-elevated)] [&::-webkit-details-marker]:hidden", children: [
2880
- /* @__PURE__ */ jsx("span", { className: "flex h-[var(--topbar-icon-button-size,32px)] w-[var(--topbar-icon-button-size,32px)] items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-accent)] text-xs font-bold text-white", children: user?.avatarUrl || user?.memojiUrl ? /* @__PURE__ */ jsx(
2881
- "img",
2882
- {
2883
- src: user.avatarUrl || user.memojiUrl,
2884
- alt: "",
2885
- className: "h-full w-full object-cover"
2886
- }
2887
- ) : initials }),
2888
- /* @__PURE__ */ jsxs("span", { className: "hidden flex-col leading-tight md:flex", children: [
2889
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-[color:var(--foreground)]", children: displayName }),
2890
- /* @__PURE__ */ jsx("span", { className: "text-xs text-[color:var(--muted)]", children: secondary })
2891
- ] }),
2892
- /* @__PURE__ */ jsx(ChevronDown, {}),
2893
- /* @__PURE__ */ jsx("span", { className: "group-open/acct:hidden", children: /* @__PURE__ */ jsx(
2894
- TopBarTooltip,
2895
- {
2896
- title: "My Account",
2897
- description: /* @__PURE__ */ jsxs(Fragment, { children: [
2898
- hasRealName ? rawName : user?.email ?? "Signed in",
2899
- user?.email ? /* @__PURE__ */ jsxs(Fragment, { children: [
2900
- /* @__PURE__ */ jsx("br", {}),
2901
- user.email
2902
- ] }) : null,
2903
- /* @__PURE__ */ jsx("br", {}),
2904
- "Profile, organizations, appearance and sign out."
2905
- ] })
2906
- }
2907
- ) })
2908
- ] }),
2909
- /* @__PURE__ */ jsxs("div", { className: "absolute right-0 z-30 mt-2 flex max-h-[calc(100vh-5rem)] w-72 flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: [
2910
- /* @__PURE__ */ jsx(TopBarPanelArrow, {}),
2911
- /* @__PURE__ */ jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain", children: [
2912
- userMenu?.myProfileHref ? /* @__PURE__ */ jsxs(
2913
- "a",
2853
+ ) : null,
2854
+ /* @__PURE__ */ jsxs("label", { className: "relative flex w-[320px] max-w-full shrink-0 items-center", children: [
2855
+ /* @__PURE__ */ jsx(SearchIcon, { className: "pointer-events-none absolute left-3 h-4 w-4 text-[color:var(--muted)]" }),
2856
+ /* @__PURE__ */ jsx(
2857
+ "input",
2858
+ {
2859
+ type: "search",
2860
+ placeholder: search?.placeholder ?? "Search",
2861
+ value: search?.value,
2862
+ onChange: search?.onChange ? (e) => search.onChange?.(e.target.value) : void 0,
2863
+ onKeyDown: search?.onSubmit ? (e) => {
2864
+ if (e.key === "Enter") search.onSubmit?.(e.target.value);
2865
+ } : void 0,
2866
+ readOnly: !search?.onChange,
2867
+ className: "w-full rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1.5 pl-9 pr-10 text-sm text-[color:var(--foreground)] placeholder:text-[color:var(--muted)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-accent)]"
2868
+ }
2869
+ ),
2870
+ /* @__PURE__ */ jsx(
2871
+ "kbd",
2872
+ {
2873
+ "aria-hidden": true,
2874
+ className: "pointer-events-none absolute right-2.5 rounded border border-[color:var(--line)] px-1 py-0.5 text-[10px] font-medium text-[color:var(--muted)]",
2875
+ children: "/"
2876
+ }
2877
+ )
2878
+ ] }),
2879
+ /* @__PURE__ */ jsxs("div", { className: "relative ml-auto flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
2880
+ /* @__PURE__ */ jsx(
2881
+ "button",
2882
+ {
2883
+ type: "button",
2884
+ onClick: buildNotes?.onOpen,
2885
+ className: "shrink-0 rounded-md px-2 py-1.5 text-sm font-medium text-[color:var(--muted)] transition hover:bg-[color:var(--panel-elevated)] hover:text-[color:var(--foreground)]",
2886
+ children: buildNotes?.label ?? "Build notes"
2887
+ }
2888
+ ),
2889
+ actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsx(NavTopBarActionButton, { action }, action.key)) : null,
2890
+ actions,
2891
+ themeToggle,
2892
+ /* @__PURE__ */ jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
2893
+ /* @__PURE__ */ jsxs("summary", { className: "group/tbtip relative flex cursor-pointer list-none items-center gap-2.5 rounded-full py-1 pl-1 pr-2 transition hover:bg-[color:var(--panel-elevated)] [&::-webkit-details-marker]:hidden", children: [
2894
+ /* @__PURE__ */ jsx("span", { className: "flex h-[var(--topbar-icon-button-size,32px)] w-[var(--topbar-icon-button-size,32px)] items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-accent)] text-xs font-bold text-white", children: user?.avatarUrl || user?.memojiUrl ? /* @__PURE__ */ jsx(
2895
+ "img",
2914
2896
  {
2915
- href: safeHref(userMenu.myProfileHref),
2916
- className: "flex w-full items-center gap-2.5 px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
2917
- children: [
2918
- /* @__PURE__ */ jsx(ProfileIcon, {}),
2919
- "My Profile"
2920
- ]
2897
+ src: user.avatarUrl || user.memojiUrl,
2898
+ alt: "",
2899
+ className: "h-full w-full object-cover"
2921
2900
  }
2922
- ) : null,
2923
- userMenu?.organizationSettingsHref ? /* @__PURE__ */ jsxs(
2924
- "a",
2901
+ ) : initials }),
2902
+ /* @__PURE__ */ jsxs("span", { className: "hidden flex-col leading-tight md:flex", children: [
2903
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-[color:var(--foreground)]", children: displayName }),
2904
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-[color:var(--muted)]", children: secondary })
2905
+ ] }),
2906
+ /* @__PURE__ */ jsx(ChevronDown, {}),
2907
+ /* @__PURE__ */ jsx("span", { className: "group-open/acct:hidden", children: /* @__PURE__ */ jsx(
2908
+ TopBarTooltip,
2925
2909
  {
2926
- href: safeHref(userMenu.organizationSettingsHref),
2927
- className: "flex w-full items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
2928
- children: [
2929
- /* @__PURE__ */ jsx(BriefcaseIcon, {}),
2930
- "Organization Settings"
2931
- ]
2910
+ title: "My Account",
2911
+ description: /* @__PURE__ */ jsxs(Fragment, { children: [
2912
+ hasRealName ? rawName : user?.email ?? "Signed in",
2913
+ user?.email ? /* @__PURE__ */ jsxs(Fragment, { children: [
2914
+ /* @__PURE__ */ jsx("br", {}),
2915
+ user.email
2916
+ ] }) : null,
2917
+ /* @__PURE__ */ jsx("br", {}),
2918
+ "Profile, organizations, appearance and sign out."
2919
+ ] })
2932
2920
  }
2933
- ) : null,
2934
- userMenu?.roles && userMenu.roles.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
2935
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Roles & Organizations" }),
2936
- /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1.5", children: userMenu.roles.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "flex flex-wrap items-center gap-1.5 text-sm", children: [
2937
- /* @__PURE__ */ jsx("span", { className: "rounded-md bg-[color:var(--panel)] px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-[color:var(--foreground)]", children: r.role }),
2938
- r.orgName ? /* @__PURE__ */ jsxs("span", { className: "text-[color:var(--muted)]", children: [
2939
- "in ",
2940
- r.orgName
2941
- ] }) : null
2942
- ] }, `${r.role}-${i}`)) })
2943
- ] }) : null,
2944
- userMenu?.accounts && userMenu.accounts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
2945
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Accounts" }),
2946
- /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1", children: userMenu.accounts.map((a) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2.5", children: [
2947
- /* @__PURE__ */ jsxs(
2948
- "button",
2921
+ ) })
2922
+ ] }),
2923
+ /* @__PURE__ */ jsxs("div", { className: "absolute right-0 z-30 mt-2 flex max-h-[calc(100vh-5rem)] w-72 flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: [
2924
+ /* @__PURE__ */ jsx(TopBarPanelArrow, {}),
2925
+ /* @__PURE__ */ jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain", children: [
2926
+ userMenu?.myProfileHref ? /* @__PURE__ */ jsxs(
2927
+ "a",
2928
+ {
2929
+ href: safeHref(userMenu.myProfileHref),
2930
+ className: "flex w-full items-center gap-2.5 px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
2931
+ children: [
2932
+ /* @__PURE__ */ jsx(ProfileIcon, {}),
2933
+ "My Profile"
2934
+ ]
2935
+ }
2936
+ ) : null,
2937
+ userMenu?.organizationSettingsHref ? /* @__PURE__ */ jsxs(
2938
+ "a",
2939
+ {
2940
+ href: safeHref(userMenu.organizationSettingsHref),
2941
+ className: "flex w-full items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
2942
+ children: [
2943
+ /* @__PURE__ */ jsx(BriefcaseIcon, {}),
2944
+ "Organization Settings"
2945
+ ]
2946
+ }
2947
+ ) : null,
2948
+ userMenu?.roles && userMenu.roles.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
2949
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Roles & Organizations" }),
2950
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1.5", children: userMenu.roles.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "flex flex-wrap items-center gap-1.5 text-sm", children: [
2951
+ /* @__PURE__ */ jsx("span", { className: "rounded-md bg-[color:var(--panel)] px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-[color:var(--foreground)]", children: r.role }),
2952
+ r.orgName ? /* @__PURE__ */ jsxs("span", { className: "text-[color:var(--muted)]", children: [
2953
+ "in ",
2954
+ r.orgName
2955
+ ] }) : null
2956
+ ] }, `${r.role}-${i}`)) })
2957
+ ] }) : null,
2958
+ userMenu?.accounts && userMenu.accounts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
2959
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Accounts" }),
2960
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1", children: userMenu.accounts.map((a) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2.5", children: [
2961
+ /* @__PURE__ */ jsxs(
2962
+ "button",
2963
+ {
2964
+ type: "button",
2965
+ onClick: () => {
2966
+ if (!a.active) userMenu.onSwitchAccount?.(a.id);
2967
+ },
2968
+ className: "flex min-w-0 flex-1 items-center gap-2.5 rounded-lg px-1 py-1 text-left hover:bg-[color:var(--panel)]",
2969
+ children: [
2970
+ /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-accent)] text-[11px] font-bold text-white", children: a.avatarUrl ? /* @__PURE__ */ jsx("img", { src: a.avatarUrl, alt: "", className: "h-full w-full object-cover" }) : (a.name ?? a.email ?? "?").slice(0, 2).toUpperCase() }),
2971
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col leading-tight", children: [
2972
+ /* @__PURE__ */ jsx(
2973
+ "span",
2974
+ {
2975
+ className: [
2976
+ "truncate text-sm font-semibold",
2977
+ a.active ? "text-[color:var(--color-accent)]" : "text-[color:var(--foreground)]"
2978
+ ].join(" "),
2979
+ children: a.name ?? a.email ?? a.id.slice(0, 8)
2980
+ }
2981
+ ),
2982
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-[color:var(--muted)]", children: a.active ? "Active" : a.email ?? "" })
2983
+ ] })
2984
+ ]
2985
+ }
2986
+ ),
2987
+ !a.active && userMenu.onRemoveAccount ? /* @__PURE__ */ jsx(
2988
+ "button",
2989
+ {
2990
+ type: "button",
2991
+ "aria-label": `Remove ${a.name ?? a.email ?? "account"}`,
2992
+ onClick: () => userMenu.onRemoveAccount?.(a.id),
2993
+ className: "shrink-0 rounded p-1 text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
2994
+ children: /* @__PURE__ */ jsx(TrashIcon, {})
2995
+ }
2996
+ ) : null
2997
+ ] }, a.id)) }),
2998
+ userMenu.addAccountHref || userMenu.onAddAccount ? userMenu.addAccountHref ? /* @__PURE__ */ jsxs(
2999
+ "a",
2949
3000
  {
2950
- type: "button",
2951
- onClick: () => {
2952
- if (!a.active) userMenu.onSwitchAccount?.(a.id);
2953
- },
2954
- className: "flex min-w-0 flex-1 items-center gap-2.5 rounded-lg px-1 py-1 text-left hover:bg-[color:var(--panel)]",
3001
+ href: safeHref(userMenu.addAccountHref),
3002
+ className: "mt-1.5 flex items-center gap-2.5 rounded-lg px-1 py-1.5 text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
2955
3003
  children: [
2956
- /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-accent)] text-[11px] font-bold text-white", children: a.avatarUrl ? /* @__PURE__ */ jsx("img", { src: a.avatarUrl, alt: "", className: "h-full w-full object-cover" }) : (a.name ?? a.email ?? "?").slice(0, 2).toUpperCase() }),
2957
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col leading-tight", children: [
2958
- /* @__PURE__ */ jsx(
2959
- "span",
2960
- {
2961
- className: [
2962
- "truncate text-sm font-semibold",
2963
- a.active ? "text-[color:var(--color-accent)]" : "text-[color:var(--foreground)]"
2964
- ].join(" "),
2965
- children: a.name ?? a.email ?? a.id.slice(0, 8)
2966
- }
2967
- ),
2968
- /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-[color:var(--muted)]", children: a.active ? "Active" : a.email ?? "" })
2969
- ] })
3004
+ /* @__PURE__ */ jsx(AddUserIcon, {}),
3005
+ "Add Account"
2970
3006
  ]
2971
3007
  }
2972
- ),
2973
- !a.active && userMenu.onRemoveAccount ? /* @__PURE__ */ jsx(
3008
+ ) : /* @__PURE__ */ jsxs(
2974
3009
  "button",
2975
3010
  {
2976
3011
  type: "button",
2977
- "aria-label": `Remove ${a.name ?? a.email ?? "account"}`,
2978
- onClick: () => userMenu.onRemoveAccount?.(a.id),
2979
- className: "shrink-0 rounded p-1 text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
2980
- children: /* @__PURE__ */ jsx(TrashIcon, {})
3012
+ onClick: userMenu.onAddAccount,
3013
+ className: "mt-1.5 flex w-full items-center gap-2.5 rounded-lg px-1 py-1.5 text-left text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
3014
+ children: [
3015
+ /* @__PURE__ */ jsx(AddUserIcon, {}),
3016
+ "Add Account"
3017
+ ]
2981
3018
  }
2982
3019
  ) : null
2983
- ] }, a.id)) }),
2984
- userMenu.addAccountHref || userMenu.onAddAccount ? userMenu.addAccountHref ? /* @__PURE__ */ jsxs(
2985
- "a",
2986
- {
2987
- href: safeHref(userMenu.addAccountHref),
2988
- className: "mt-1.5 flex items-center gap-2.5 rounded-lg px-1 py-1.5 text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
2989
- children: [
2990
- /* @__PURE__ */ jsx(AddUserIcon, {}),
2991
- "Add Account"
2992
- ]
2993
- }
2994
- ) : /* @__PURE__ */ jsxs(
2995
- "button",
3020
+ ] }) : null,
3021
+ userMenu?.theme ? /* @__PURE__ */ jsx("div", { className: "border-t border-[color:var(--line)]", children: /* @__PURE__ */ jsx(
3022
+ NavThemeControl,
2996
3023
  {
2997
- type: "button",
2998
- onClick: userMenu.onAddAccount,
2999
- className: "mt-1.5 flex w-full items-center gap-2.5 rounded-lg px-1 py-1.5 text-left text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
3000
- children: [
3001
- /* @__PURE__ */ jsx(AddUserIcon, {}),
3002
- "Add Account"
3003
- ]
3024
+ value: userMenu.theme.value,
3025
+ onChange: userMenu.theme.onChange
3004
3026
  }
3005
- ) : null
3006
- ] }) : null,
3007
- userMenu?.theme ? /* @__PURE__ */ jsx("div", { className: "border-t border-[color:var(--line)]", children: /* @__PURE__ */ jsx(
3008
- NavThemeControl,
3027
+ ) }) : null
3028
+ ] }),
3029
+ onSignOut ? /* @__PURE__ */ jsxs(
3030
+ "button",
3009
3031
  {
3010
- value: userMenu.theme.value,
3011
- onChange: userMenu.theme.onChange
3032
+ type: "button",
3033
+ onClick: onSignOut,
3034
+ className: "flex w-full shrink-0 items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-accent)]",
3035
+ children: [
3036
+ /* @__PURE__ */ jsx(SignOutIcon, {}),
3037
+ "Sign out"
3038
+ ]
3012
3039
  }
3013
- ) }) : null
3014
- ] }),
3015
- onSignOut ? /* @__PURE__ */ jsxs(
3016
- "button",
3017
- {
3018
- type: "button",
3019
- onClick: onSignOut,
3020
- className: "flex w-full shrink-0 items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-accent)]",
3021
- children: [
3022
- /* @__PURE__ */ jsx(SignOutIcon, {}),
3023
- "Sign out"
3024
- ]
3025
- }
3026
- ) : null
3027
- ] })
3028
- ] }),
3029
- !hasRealName && user ? /* @__PURE__ */ jsx(NamePromptBubble, { profileHref: userMenu?.myProfileHref }) : null
3030
- ] })
3040
+ ) : null
3041
+ ] })
3042
+ ] }),
3043
+ !hasRealName && user ? /* @__PURE__ */ jsx(NamePromptBubble, { profileHref: userMenu?.myProfileHref }) : null
3044
+ ] })
3045
+ ] }),
3046
+ /* @__PURE__ */ jsx(
3047
+ "div",
3048
+ {
3049
+ "aria-hidden": true,
3050
+ className: "h-[3px] w-full shrink-0",
3051
+ style: {
3052
+ background: "var(--chrome-gradient, linear-gradient(to right, #007BFF, #A54B7A, #E63946))"
3053
+ }
3054
+ }
3055
+ )
3031
3056
  ] });
3032
3057
  }
3033
3058
  function NamePromptBubble({ profileHref }) {
@@ -3389,7 +3414,22 @@ function NavAppShell({
3389
3414
  /* @__PURE__ */ jsxs("div", { className: "lg:pl-[240px]", children: [
3390
3415
  /* @__PURE__ */ jsx(NavTopBar, { ...topBar, onOpenNav: () => setNavOpen(true), navOpen }),
3391
3416
  betaBanner ? /* @__PURE__ */ jsx(NavBetaBanner, { ...betaBanner }) : null,
3392
- contentWrapper === "bare" ? /* @__PURE__ */ jsx("div", { "data-shell-content": "", children }) : /* @__PURE__ */ jsx("main", { "data-shell-content": "", className: "px-6 py-7", children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-7xl", children }) })
3417
+ topBar.title ? /* @__PURE__ */ jsx("h1", { className: "px-6 pt-7 text-xl font-semibold text-[color:var(--foreground)]", children: topBar.title }) : null,
3418
+ contentWrapper === "bare" ? /* @__PURE__ */ jsx("div", { "data-shell-content": "", className: topBar.title ? "mt-[22px]" : void 0, children }) : (
3419
+ // Claude Design: "a rounded, inset frame on a light-grey page
3420
+ // background" — the shell owns the page background and the
3421
+ // gutter; it does not draw a hard border/box around the content
3422
+ // (that reads as a second frame on top of the page header). An
3423
+ // app's own cards are its own furniture and stay app-owned.
3424
+ /* @__PURE__ */ jsx(
3425
+ "main",
3426
+ {
3427
+ "data-shell-content": "",
3428
+ className: `min-h-[calc(100vh-63px)] bg-[color:var(--chrome-page-bg,#F4F5F7)] px-6 ${topBar.title ? "pb-7 pt-[22px]" : "py-7"}`,
3429
+ children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-7xl", children })
3430
+ }
3431
+ )
3432
+ )
3393
3433
  ] })
3394
3434
  ]
3395
3435
  }
@@ -3397,5 +3437,5 @@ function NavAppShell({
3397
3437
  }
3398
3438
 
3399
3439
  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 };
3400
- //# sourceMappingURL=chunk-LFLN5GD6.js.map
3401
- //# sourceMappingURL=chunk-LFLN5GD6.js.map
3440
+ //# sourceMappingURL=chunk-NRKRUM5B.js.map
3441
+ //# sourceMappingURL=chunk-NRKRUM5B.js.map