@the-portland-company/shell 0.71.1 → 0.72.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.
package/dist/chrome.css CHANGED
@@ -421,9 +421,16 @@
421
421
  --sidebar-mode-selected-bg: #2F3136;
422
422
  }
423
423
 
424
+ /* Left-Navigation §5/§12: Campaign rail is Deep Race Red, raised wells
425
+ #A12430, inactive row text #F0CFD2, eyebrow #F6DADD. */
424
426
  [data-politogy-mode="campaign"] {
425
427
  --sidebar-bg: #8F1F2A;
426
428
  --sidebar-hover-bg: #7A1A23;
429
+ --sidebar-card-bg: #A12430;
430
+ --mode-track-bg: #A12430;
431
+ --sidebar-mode-selected-bg: #B32B38;
432
+ --sidebar-row-text: #F0CFD2;
433
+ --sidebar-eyebrow: #F6DADD;
427
434
  }
428
435
 
429
436
 
@@ -6,6 +6,7 @@ import clsx from 'clsx';
6
6
  import { FiUser, FiSettings, FiMessageSquare, FiMail, FiInfo, FiSun, FiMoon, FiHelpCircle, FiLifeBuoy, FiAlertCircle, FiAlertTriangle, FiBell, FiGrid, FiZap, FiBatteryCharging, FiBattery } from 'react-icons/fi';
7
7
  import { createPortal } from 'react-dom';
8
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
+ import { LuSignpost, LuDoorOpen, LuChartNoAxesColumn, LuLandmark, LuCrosshair, LuCircleUser, LuClipboardList, LuMousePointerClick, LuUsersRound, LuLayoutDashboard, LuFlag, LuTarget, LuMapPin, LuMap, LuPhone, LuShare2, LuDollarSign, LuCreditCard, LuSettings, LuBriefcase, LuChartColumn, LuUser, LuClock, LuSend, LuFileText, LuPencil, LuUpload, LuList, LuLayoutGrid, LuLifeBuoy, LuActivity, LuMessageSquare, LuMail, LuUsers, LuHouse } from 'react-icons/lu';
9
10
 
10
11
  function useTopBarIconSlotGlyph(slot) {
11
12
  const [name, setName] = useState(null);
@@ -1749,6 +1750,45 @@ function useThemePreference() {
1749
1750
  );
1750
1751
  return { value, setValue };
1751
1752
  }
1753
+ var standardNavIcons = {
1754
+ home: LuHouse,
1755
+ users: LuUsers,
1756
+ mail: LuMail,
1757
+ messageSquare: LuMessageSquare,
1758
+ layout: LuLayoutDashboard,
1759
+ activity: LuActivity,
1760
+ lifeBuoy: LuLifeBuoy,
1761
+ grid: LuLayoutGrid,
1762
+ list: LuList,
1763
+ upload: LuUpload,
1764
+ edit: LuPencil,
1765
+ fileText: LuFileText,
1766
+ send: LuSend,
1767
+ clock: LuClock,
1768
+ user: LuUser,
1769
+ barChart: LuChartColumn,
1770
+ briefcase: LuBriefcase,
1771
+ settings: LuSettings,
1772
+ creditCard: LuCreditCard,
1773
+ dollarSign: LuDollarSign,
1774
+ share: LuShare2,
1775
+ // Campaign / Petition mode slots.
1776
+ phone: LuPhone,
1777
+ map: LuMap,
1778
+ mapPin: LuMapPin,
1779
+ target: LuTarget,
1780
+ flag: LuFlag,
1781
+ layoutDashboard: LuLayoutDashboard,
1782
+ usersRound: LuUsersRound,
1783
+ mousePointerClick: LuMousePointerClick,
1784
+ clipboardList: LuClipboardList,
1785
+ circleUser: LuCircleUser,
1786
+ crosshair: LuCrosshair,
1787
+ landmark: LuLandmark,
1788
+ chartNoAxes: LuChartNoAxesColumn,
1789
+ doorOpen: LuDoorOpen,
1790
+ signpost: LuSignpost
1791
+ };
1752
1792
 
1753
1793
  // src/native/standardNav.ts
1754
1794
  var CAMPAIGN_FEATURE_AVAILABILITY = {
@@ -1862,7 +1902,7 @@ var APP_SIGNS_CHILDREN = [
1862
1902
  function standardPolitogyNav(opts) {
1863
1903
  const base = opts.coreBaseUrl.replace(/\/+$/, "");
1864
1904
  const abs = (path) => `${base}${path.startsWith("/") ? path : `/${path}`}`;
1865
- const icon = (key) => opts.icons?.[key];
1905
+ const icon = (key) => opts.icons?.[key] ?? standardNavIcons[key];
1866
1906
  const orgParam = opts.activeOrgId ? `org=${opts.activeOrgId}` : "";
1867
1907
  const withOrg = (url) => orgParam ? `${url}${url.includes("?") ? "&" : "?"}${orgParam}` : url;
1868
1908
  const leaves = (children) => children.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(abs(c.path)) }));
@@ -2074,6 +2114,24 @@ function hasActiveChild(item, pathname, activeFn) {
2074
2114
  )
2075
2115
  );
2076
2116
  }
2117
+ function firstLeafHref(item) {
2118
+ for (const c of item.children ?? []) {
2119
+ if (c.kind === "section") continue;
2120
+ if (c.href) return c.href;
2121
+ const deep = firstLeafHref(c);
2122
+ if (deep) return deep;
2123
+ }
2124
+ return void 0;
2125
+ }
2126
+ function modeIdFromLabel(label) {
2127
+ const l = label?.trim().toLowerCase();
2128
+ return l ? l.replace(/\s+mode$/, "") : void 0;
2129
+ }
2130
+ function shortUserName(name) {
2131
+ const parts = name.trim().split(/\s+/).filter(Boolean);
2132
+ if (parts.length < 2) return parts[0] ?? "";
2133
+ return `${parts[0]} ${parts[parts.length - 1][0].toUpperCase()}.`;
2134
+ }
2077
2135
  function shortEnvLabel(label) {
2078
2136
  const l = label.trim().toLowerCase();
2079
2137
  if (l === "production") return "prod";
@@ -2190,7 +2248,6 @@ function NavSidebar({
2190
2248
  useEffect(() => {
2191
2249
  setOpenGroup(activeGroupKey);
2192
2250
  }, [activeGroupKey]);
2193
- const toggleGroup = (key) => setOpenGroup((prev) => prev === key ? null : key);
2194
2251
  return /* @__PURE__ */ jsxs(RailCollapsibleContext.Provider, { value: collapsible, children: [
2195
2252
  open ? /* @__PURE__ */ jsx(
2196
2253
  "div",
@@ -2530,21 +2587,16 @@ function NavSidebar({
2530
2587
  });
2531
2588
  }
2532
2589
  if (item.children && item.children.length > 0) {
2533
- const key = groupKeyOf(item, idx);
2534
2590
  const selfActive = item.href ? activeFn(pathname, item.href) : false;
2535
2591
  const parentActive = selfActive || hasActiveChild(item, pathname, activeFn);
2536
2592
  return /* @__PURE__ */ jsx(
2537
- NavGroup,
2593
+ NavRow,
2538
2594
  {
2539
- item,
2595
+ item: { ...item, href: item.href ?? firstLeafHref(item), children: void 0 },
2540
2596
  active: parentActive,
2541
- open: openGroup === key,
2542
- onToggle: () => toggleGroup(key),
2543
- pathname,
2544
- activeFn,
2545
2597
  Link
2546
2598
  },
2547
- key
2599
+ item.href ?? groupKeyOf(item, idx)
2548
2600
  );
2549
2601
  }
2550
2602
  const active = item.href ? activeFn(pathname, item.href) : false;
@@ -2832,142 +2884,6 @@ function NavRow({
2832
2884
  }
2833
2885
  );
2834
2886
  }
2835
- function NavGroup({
2836
- item,
2837
- active,
2838
- open,
2839
- onToggle,
2840
- pathname,
2841
- activeFn,
2842
- Link
2843
- }) {
2844
- const rc = useRailCollapse();
2845
- const Icon = item.icon;
2846
- const headerClasses = [
2847
- "group relative block w-full overflow-hidden text-left transition",
2848
- open ? "rounded-t-[5px]" : "rounded-[5px]",
2849
- active ? NAV_TOP_ACTIVE_CLASS : open ? "bg-[color:var(--sidebar-row-hover-bg,var(--panel))] text-[color:var(--sidebar-text,var(--foreground))]" : NAV_TOP_INACTIVE_CLASS
2850
- ].join(" ");
2851
- return /* @__PURE__ */ jsxs("div", { children: [
2852
- /* @__PURE__ */ jsxs(
2853
- "button",
2854
- {
2855
- type: "button",
2856
- onClick: () => {
2857
- onToggle();
2858
- item.onClick?.();
2859
- },
2860
- "aria-expanded": open,
2861
- title: item.label,
2862
- className: headerClasses,
2863
- children: [
2864
- active ? /* @__PURE__ */ jsx(NavActiveRail, {}) : null,
2865
- /* @__PURE__ */ jsxs("span", { className: `relative z-10 flex items-center ${NAV_TOP_ROW_CLASS(active)} ${rc("max-md:justify-center max-md:px-0")}`, children: [
2866
- Icon ? /* @__PURE__ */ jsx(Icon, { size: NAV_TOP_ICON_SIZE, className: "shrink-0 text-current" }) : null,
2867
- /* @__PURE__ */ jsx("span", { className: `min-w-0 flex-1 truncate ${rc("max-md:hidden")}`, children: item.label }),
2868
- /* @__PURE__ */ jsx(NavRowBadge, { value: item.badge }),
2869
- /* @__PURE__ */ jsx(
2870
- ChevronDown,
2871
- {
2872
- className: [
2873
- "shrink-0 opacity-80 transition-transform duration-200",
2874
- open ? "rotate-180" : "",
2875
- rc("max-md:hidden")
2876
- ].join(" ")
2877
- }
2878
- )
2879
- ] })
2880
- ]
2881
- }
2882
- ),
2883
- open ? /* @__PURE__ */ jsx("div", { className: `overflow-hidden rounded-b-md bg-[color:var(--nav-submenu-bg)] p-1 ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: item.children.map((child, i) => {
2884
- if (child.kind === "section") {
2885
- return /* @__PURE__ */ jsx(
2886
- NavSectionRow,
2887
- {
2888
- label: child.label,
2889
- first: i === 0,
2890
- variant: "sub"
2891
- },
2892
- `sub-section-${i}-${child.label}`
2893
- );
2894
- }
2895
- const childActive = child.href ? activeFn(pathname, child.href) : false;
2896
- if (child.children && child.children.length > 0) {
2897
- return /* @__PURE__ */ jsx(
2898
- NavSubGroup,
2899
- {
2900
- item: child,
2901
- pathname,
2902
- activeFn,
2903
- Link
2904
- },
2905
- child.href ?? `subgrp-${i}-${child.label}`
2906
- );
2907
- }
2908
- return /* @__PURE__ */ jsx(
2909
- NavRow,
2910
- {
2911
- item: child,
2912
- active: childActive,
2913
- Link,
2914
- variant: "sub"
2915
- },
2916
- child.href ?? `sub-${i}-${child.label}`
2917
- );
2918
- }) }) }) : null
2919
- ] });
2920
- }
2921
- function NavSubGroup({
2922
- item,
2923
- pathname,
2924
- activeFn,
2925
- Link
2926
- }) {
2927
- const ownsActive = (item.href ? activeFn(pathname, item.href) : false) || (item.children ?? []).some((c) => c.href ? activeFn(pathname, c.href) : false);
2928
- const [open, setOpen] = useState(ownsActive);
2929
- useEffect(() => {
2930
- if (ownsActive) setOpen(true);
2931
- }, [ownsActive]);
2932
- const Icon = item.icon;
2933
- return /* @__PURE__ */ jsxs("div", { children: [
2934
- /* @__PURE__ */ jsxs(
2935
- "button",
2936
- {
2937
- type: "button",
2938
- onClick: () => setOpen((v) => !v),
2939
- "aria-expanded": open,
2940
- className: [
2941
- "flex w-full items-center gap-2.5 rounded px-3 py-1.5 text-left text-[13px] font-medium transition",
2942
- ownsActive ? "text-[color:var(--color-accent)]" : "text-[color:var(--sidebar-text,var(--muted))] hover:bg-[color:var(--nav-row-hover)] hover:text-[color:var(--foreground)]"
2943
- ].join(" "),
2944
- children: [
2945
- Icon ? /* @__PURE__ */ jsx(Icon, { size: 15, className: "shrink-0 text-current" }) : null,
2946
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
2947
- /* @__PURE__ */ jsx(
2948
- ChevronDown,
2949
- {
2950
- className: [
2951
- "shrink-0 opacity-70 transition-transform duration-200",
2952
- open ? "rotate-180" : ""
2953
- ].join(" ")
2954
- }
2955
- )
2956
- ]
2957
- }
2958
- ),
2959
- open ? /* @__PURE__ */ jsx("div", { className: "ml-4 flex flex-col gap-0.5 border-l border-[color:var(--line)] pl-2", children: item.children.map((leaf, i) => /* @__PURE__ */ jsx(
2960
- NavRow,
2961
- {
2962
- item: leaf,
2963
- active: leaf.href ? activeFn(pathname, leaf.href) : false,
2964
- Link,
2965
- variant: "sub"
2966
- },
2967
- leaf.href ?? `subsub-${i}-${leaf.label}`
2968
- )) }) : null
2969
- ] });
2970
- }
2971
2887
  function OrgIdCopyButton({ id }) {
2972
2888
  const [copied, setCopied] = useState(false);
2973
2889
  return /* @__PURE__ */ jsx(
@@ -3267,8 +3183,8 @@ function NavSidebarUserCard({
3267
3183
  }) {
3268
3184
  const rawName = user.name?.trim() || "";
3269
3185
  const hasRealName = rawName.length > 0 && !rawName.includes("@");
3270
- const displayName = hasRealName ? rawName : user.email ?? "Signed in";
3271
- const initials = (hasRealName ? rawName : user.email ?? "P").slice(0, 2).toUpperCase();
3186
+ const displayName = hasRealName ? shortUserName(rawName) : user.email ?? "Signed in";
3187
+ const initials = hasRealName ? rawName.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join("").toUpperCase() : (user.email ?? "P").slice(0, 2).toUpperCase();
3272
3188
  const secondary = hasRealName ? user.email || [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member" : [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member";
3273
3189
  const rc = useRailCollapse();
3274
3190
  return /* @__PURE__ */ jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
@@ -3668,7 +3584,7 @@ function NavAppShell({
3668
3584
  return /* @__PURE__ */ jsxs(
3669
3585
  "div",
3670
3586
  {
3671
- "data-politogy-mode": modeId,
3587
+ "data-politogy-mode": modeId ?? modeIdFromLabel(sidebar.mode?.label),
3672
3588
  className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
3673
3589
  children: [
3674
3590
  /* @__PURE__ */ jsx(
@@ -3715,6 +3631,6 @@ function NavAppShell({
3715
3631
  );
3716
3632
  }
3717
3633
 
3718
- 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, shortEnvLabel, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
3719
- //# sourceMappingURL=chunk-JBPJOPLW.js.map
3720
- //# sourceMappingURL=chunk-JBPJOPLW.js.map
3634
+ 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, modeIdFromLabel, resolveOrgLogoUrl, shortEnvLabel, shortUserName, standardNavIcons, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
3635
+ //# sourceMappingURL=chunk-6OM62ZTK.js.map
3636
+ //# sourceMappingURL=chunk-6OM62ZTK.js.map