@the-portland-company/shell 0.71.0 → 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/native.cjs CHANGED
@@ -6,6 +6,7 @@ var clsx = require('clsx');
6
6
  var fi = require('react-icons/fi');
7
7
  var reactDom = require('react-dom');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
+ var lu = require('react-icons/lu');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
12
 
@@ -1917,6 +1918,45 @@ function useThemePreference() {
1917
1918
  function FormColumn({ children, className }) {
1918
1919
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-shell-form-column": "", className: clsx__default.default("w-full max-w-[960px]", className), children });
1919
1920
  }
1921
+ var standardNavIcons = {
1922
+ home: lu.LuHouse,
1923
+ users: lu.LuUsers,
1924
+ mail: lu.LuMail,
1925
+ messageSquare: lu.LuMessageSquare,
1926
+ layout: lu.LuLayoutDashboard,
1927
+ activity: lu.LuActivity,
1928
+ lifeBuoy: lu.LuLifeBuoy,
1929
+ grid: lu.LuLayoutGrid,
1930
+ list: lu.LuList,
1931
+ upload: lu.LuUpload,
1932
+ edit: lu.LuPencil,
1933
+ fileText: lu.LuFileText,
1934
+ send: lu.LuSend,
1935
+ clock: lu.LuClock,
1936
+ user: lu.LuUser,
1937
+ barChart: lu.LuChartColumn,
1938
+ briefcase: lu.LuBriefcase,
1939
+ settings: lu.LuSettings,
1940
+ creditCard: lu.LuCreditCard,
1941
+ dollarSign: lu.LuDollarSign,
1942
+ share: lu.LuShare2,
1943
+ // Campaign / Petition mode slots.
1944
+ phone: lu.LuPhone,
1945
+ map: lu.LuMap,
1946
+ mapPin: lu.LuMapPin,
1947
+ target: lu.LuTarget,
1948
+ flag: lu.LuFlag,
1949
+ layoutDashboard: lu.LuLayoutDashboard,
1950
+ usersRound: lu.LuUsersRound,
1951
+ mousePointerClick: lu.LuMousePointerClick,
1952
+ clipboardList: lu.LuClipboardList,
1953
+ circleUser: lu.LuCircleUser,
1954
+ crosshair: lu.LuCrosshair,
1955
+ landmark: lu.LuLandmark,
1956
+ chartNoAxes: lu.LuChartNoAxesColumn,
1957
+ doorOpen: lu.LuDoorOpen,
1958
+ signpost: lu.LuSignpost
1959
+ };
1920
1960
 
1921
1961
  // src/native/standardNav.ts
1922
1962
  var CAMPAIGN_FEATURE_AVAILABILITY = {
@@ -2030,7 +2070,7 @@ var APP_SIGNS_CHILDREN = [
2030
2070
  function standardPolitogyNav(opts) {
2031
2071
  const base = opts.coreBaseUrl.replace(/\/+$/, "");
2032
2072
  const abs = (path) => `${base}${path.startsWith("/") ? path : `/${path}`}`;
2033
- const icon = (key) => opts.icons?.[key];
2073
+ const icon = (key) => opts.icons?.[key] ?? standardNavIcons[key];
2034
2074
  const orgParam = opts.activeOrgId ? `org=${opts.activeOrgId}` : "";
2035
2075
  const withOrg = (url) => orgParam ? `${url}${url.includes("?") ? "&" : "?"}${orgParam}` : url;
2036
2076
  const leaves = (children) => children.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(abs(c.path)) }));
@@ -2242,6 +2282,30 @@ function hasActiveChild(item, pathname, activeFn) {
2242
2282
  )
2243
2283
  );
2244
2284
  }
2285
+ function firstLeafHref(item) {
2286
+ for (const c of item.children ?? []) {
2287
+ if (c.kind === "section") continue;
2288
+ if (c.href) return c.href;
2289
+ const deep = firstLeafHref(c);
2290
+ if (deep) return deep;
2291
+ }
2292
+ return void 0;
2293
+ }
2294
+ function modeIdFromLabel(label) {
2295
+ const l = label?.trim().toLowerCase();
2296
+ return l ? l.replace(/\s+mode$/, "") : void 0;
2297
+ }
2298
+ function shortUserName(name) {
2299
+ const parts = name.trim().split(/\s+/).filter(Boolean);
2300
+ if (parts.length < 2) return parts[0] ?? "";
2301
+ return `${parts[0]} ${parts[parts.length - 1][0].toUpperCase()}.`;
2302
+ }
2303
+ function shortEnvLabel(label) {
2304
+ const l = label.trim().toLowerCase();
2305
+ if (l === "production") return "prod";
2306
+ if (l === "development") return "dev";
2307
+ return l;
2308
+ }
2245
2309
  function envChipClasses(label) {
2246
2310
  const l = label.toLowerCase();
2247
2311
  if (l === "production" || l === "prod")
@@ -2352,7 +2416,6 @@ function NavSidebar({
2352
2416
  react.useEffect(() => {
2353
2417
  setOpenGroup(activeGroupKey);
2354
2418
  }, [activeGroupKey]);
2355
- const toggleGroup = (key) => setOpenGroup((prev) => prev === key ? null : key);
2356
2419
  return /* @__PURE__ */ jsxRuntime.jsxs(RailCollapsibleContext.Provider, { value: collapsible, children: [
2357
2420
  open ? /* @__PURE__ */ jsxRuntime.jsx(
2358
2421
  "div",
@@ -2692,21 +2755,16 @@ function NavSidebar({
2692
2755
  });
2693
2756
  }
2694
2757
  if (item.children && item.children.length > 0) {
2695
- const key = groupKeyOf(item, idx);
2696
2758
  const selfActive = item.href ? activeFn(pathname, item.href) : false;
2697
2759
  const parentActive = selfActive || hasActiveChild(item, pathname, activeFn);
2698
2760
  return /* @__PURE__ */ jsxRuntime.jsx(
2699
- NavGroup,
2761
+ NavRow,
2700
2762
  {
2701
- item,
2763
+ item: { ...item, href: item.href ?? firstLeafHref(item), children: void 0 },
2702
2764
  active: parentActive,
2703
- open: openGroup === key,
2704
- onToggle: () => toggleGroup(key),
2705
- pathname,
2706
- activeFn,
2707
2765
  Link
2708
2766
  },
2709
- key
2767
+ item.href ?? groupKeyOf(item, idx)
2710
2768
  );
2711
2769
  }
2712
2770
  const active = item.href ? activeFn(pathname, item.href) : false;
@@ -2741,41 +2799,26 @@ function NavSidebar({
2741
2799
  }
2742
2800
  )
2743
2801
  ] }, l.label)) }) : null,
2744
- footer.envLabel && footer.envLabel.trim().toLowerCase() !== "production" ? /* @__PURE__ */ jsxRuntime.jsxs(
2802
+ footer.envLabel || footer.commit || footer.version ? /* @__PURE__ */ jsxRuntime.jsxs(
2745
2803
  "div",
2746
2804
  {
2747
2805
  "data-shell-meta": true,
2748
- className: `mt-1.5 flex flex-col items-start gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--sidebar-meta-text,var(--sidebar-text))] ${rc("max-md:hidden")}`,
2806
+ className: `mt-1.5 flex flex-col items-center gap-0.5 font-[family-name:var(--font-plex-mono)] text-[11px] text-[color:var(--sidebar-meta-text,rgba(255,255,255,0.4))] ${rc("max-md:hidden")}`,
2749
2807
  children: [
2750
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
2751
- /* @__PURE__ */ jsxRuntime.jsx(
2752
- "span",
2753
- {
2754
- className: [
2755
- "rounded-md px-1.5 py-0.5 text-[10px] font-semibold",
2756
- envChipClasses(footer.envLabel)
2757
- ].join(" "),
2758
- children: footer.envLabel
2759
- }
2760
- ),
2761
- footer.commit ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2762
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }),
2763
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: footer.commit.slice(-4) })
2764
- ] }) : null,
2765
- footer.version ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2766
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }),
2767
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2768
- "v",
2769
- footer.version
2770
- ] })
2771
- ] }) : null
2772
- ] }),
2808
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: [
2809
+ footer.envLabel ? shortEnvLabel(footer.envLabel) : null,
2810
+ footer.commit ? footer.commit.slice(-4) : null,
2811
+ footer.version ? `v${footer.version.replace(/^v/, "")}` : null
2812
+ ].filter((v) => Boolean(v)).map((v, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
2813
+ i > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "|" }) : null,
2814
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: v })
2815
+ ] }, i)) }),
2773
2816
  footer.commitDate || footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
2774
2817
  footer.commitDate ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(footer.commitDate).toLocaleDateString(void 0, {
2775
2818
  month: "short",
2776
2819
  day: "numeric"
2777
2820
  }) }) : null,
2778
- footer.commitDate && footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }) : null,
2821
+ footer.commitDate && footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "|" }) : null,
2779
2822
  footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: footer.commitAuthor.split(/\s+/)[0] }) : null
2780
2823
  ] }) : null
2781
2824
  ]
@@ -3009,142 +3052,6 @@ function NavRow({
3009
3052
  }
3010
3053
  );
3011
3054
  }
3012
- function NavGroup({
3013
- item,
3014
- active,
3015
- open,
3016
- onToggle,
3017
- pathname,
3018
- activeFn,
3019
- Link
3020
- }) {
3021
- const rc = useRailCollapse();
3022
- const Icon = item.icon;
3023
- const headerClasses = [
3024
- "group relative block w-full overflow-hidden text-left transition",
3025
- open ? "rounded-t-[5px]" : "rounded-[5px]",
3026
- 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
3027
- ].join(" ");
3028
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3029
- /* @__PURE__ */ jsxRuntime.jsxs(
3030
- "button",
3031
- {
3032
- type: "button",
3033
- onClick: () => {
3034
- onToggle();
3035
- item.onClick?.();
3036
- },
3037
- "aria-expanded": open,
3038
- title: item.label,
3039
- className: headerClasses,
3040
- children: [
3041
- active ? /* @__PURE__ */ jsxRuntime.jsx(NavActiveRail, {}) : null,
3042
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${NAV_TOP_ROW_CLASS(active)} ${rc("max-md:justify-center max-md:px-0")}`, children: [
3043
- Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: NAV_TOP_ICON_SIZE, className: "shrink-0 text-current" }) : null,
3044
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `min-w-0 flex-1 truncate ${rc("max-md:hidden")}`, children: item.label }),
3045
- /* @__PURE__ */ jsxRuntime.jsx(NavRowBadge, { value: item.badge }),
3046
- /* @__PURE__ */ jsxRuntime.jsx(
3047
- ChevronDown,
3048
- {
3049
- className: [
3050
- "shrink-0 opacity-80 transition-transform duration-200",
3051
- open ? "rotate-180" : "",
3052
- rc("max-md:hidden")
3053
- ].join(" ")
3054
- }
3055
- )
3056
- ] })
3057
- ]
3058
- }
3059
- ),
3060
- open ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `overflow-hidden rounded-b-md bg-[color:var(--nav-submenu-bg)] p-1 ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: item.children.map((child, i) => {
3061
- if (child.kind === "section") {
3062
- return /* @__PURE__ */ jsxRuntime.jsx(
3063
- NavSectionRow,
3064
- {
3065
- label: child.label,
3066
- first: i === 0,
3067
- variant: "sub"
3068
- },
3069
- `sub-section-${i}-${child.label}`
3070
- );
3071
- }
3072
- const childActive = child.href ? activeFn(pathname, child.href) : false;
3073
- if (child.children && child.children.length > 0) {
3074
- return /* @__PURE__ */ jsxRuntime.jsx(
3075
- NavSubGroup,
3076
- {
3077
- item: child,
3078
- pathname,
3079
- activeFn,
3080
- Link
3081
- },
3082
- child.href ?? `subgrp-${i}-${child.label}`
3083
- );
3084
- }
3085
- return /* @__PURE__ */ jsxRuntime.jsx(
3086
- NavRow,
3087
- {
3088
- item: child,
3089
- active: childActive,
3090
- Link,
3091
- variant: "sub"
3092
- },
3093
- child.href ?? `sub-${i}-${child.label}`
3094
- );
3095
- }) }) }) : null
3096
- ] });
3097
- }
3098
- function NavSubGroup({
3099
- item,
3100
- pathname,
3101
- activeFn,
3102
- Link
3103
- }) {
3104
- const ownsActive = (item.href ? activeFn(pathname, item.href) : false) || (item.children ?? []).some((c) => c.href ? activeFn(pathname, c.href) : false);
3105
- const [open, setOpen] = react.useState(ownsActive);
3106
- react.useEffect(() => {
3107
- if (ownsActive) setOpen(true);
3108
- }, [ownsActive]);
3109
- const Icon = item.icon;
3110
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3111
- /* @__PURE__ */ jsxRuntime.jsxs(
3112
- "button",
3113
- {
3114
- type: "button",
3115
- onClick: () => setOpen((v) => !v),
3116
- "aria-expanded": open,
3117
- className: [
3118
- "flex w-full items-center gap-2.5 rounded px-3 py-1.5 text-left text-[13px] font-medium transition",
3119
- 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)]"
3120
- ].join(" "),
3121
- children: [
3122
- Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 15, className: "shrink-0 text-current" }) : null,
3123
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
3124
- /* @__PURE__ */ jsxRuntime.jsx(
3125
- ChevronDown,
3126
- {
3127
- className: [
3128
- "shrink-0 opacity-70 transition-transform duration-200",
3129
- open ? "rotate-180" : ""
3130
- ].join(" ")
3131
- }
3132
- )
3133
- ]
3134
- }
3135
- ),
3136
- open ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
3137
- NavRow,
3138
- {
3139
- item: leaf,
3140
- active: leaf.href ? activeFn(pathname, leaf.href) : false,
3141
- Link,
3142
- variant: "sub"
3143
- },
3144
- leaf.href ?? `subsub-${i}-${leaf.label}`
3145
- )) }) : null
3146
- ] });
3147
- }
3148
3055
  function OrgIdCopyButton({ id }) {
3149
3056
  const [copied, setCopied] = react.useState(false);
3150
3057
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -3444,8 +3351,8 @@ function NavSidebarUserCard({
3444
3351
  }) {
3445
3352
  const rawName = user.name?.trim() || "";
3446
3353
  const hasRealName = rawName.length > 0 && !rawName.includes("@");
3447
- const displayName = hasRealName ? rawName : user.email ?? "Signed in";
3448
- const initials = (hasRealName ? rawName : user.email ?? "P").slice(0, 2).toUpperCase();
3354
+ const displayName = hasRealName ? shortUserName(rawName) : user.email ?? "Signed in";
3355
+ const initials = hasRealName ? rawName.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join("").toUpperCase() : (user.email ?? "P").slice(0, 2).toUpperCase();
3449
3356
  const secondary = hasRealName ? user.email || [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member" : [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member";
3450
3357
  const rc = useRailCollapse();
3451
3358
  return /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
@@ -3845,7 +3752,7 @@ function NavAppShell({
3845
3752
  return /* @__PURE__ */ jsxRuntime.jsxs(
3846
3753
  "div",
3847
3754
  {
3848
- "data-politogy-mode": modeId,
3755
+ "data-politogy-mode": modeId ?? modeIdFromLabel(sidebar.mode?.label),
3849
3756
  className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
3850
3757
  children: [
3851
3758
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -3918,7 +3825,10 @@ exports.TopBarWidgetSlot = TopBarWidgetSlot;
3918
3825
  exports.clearBetaBannerDismissal = clearBetaBannerDismissal;
3919
3826
  exports.envChipClasses = envChipClasses;
3920
3827
  exports.isNavItemActive = isNavItemActive;
3828
+ exports.modeIdFromLabel = modeIdFromLabel;
3921
3829
  exports.resolveOrgLogoUrl = resolveOrgLogoUrl;
3830
+ exports.shortEnvLabel = shortEnvLabel;
3831
+ exports.shortUserName = shortUserName;
3922
3832
  exports.standardPolitogyNav = standardPolitogyNav;
3923
3833
  exports.topBarIconButtonClass = topBarIconButtonClass;
3924
3834
  exports.useChromeMe = useChromeMe;