@the-portland-company/shell 0.2.0 → 0.3.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/index.cjs CHANGED
@@ -5,6 +5,8 @@ var jsxRuntime = require('react/jsx-runtime');
5
5
  var clsx2 = require('clsx');
6
6
  var reactRouterDom = require('react-router-dom');
7
7
  var react$1 = require('react');
8
+ var fi = require('react-icons/fi');
9
+ var react$2 = require('@emotion/react');
8
10
 
9
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
12
 
@@ -1124,6 +1126,11 @@ var ShellMetaContext = react$1.createContext(null);
1124
1126
  var ShellOrgContext = react$1.createContext(null);
1125
1127
  var ShellLinkedAccountsContext = react$1.createContext(null);
1126
1128
  var ShellSupportProviderContext = react$1.createContext(null);
1129
+ var ShellModeContext = react$1.createContext(null);
1130
+ var ShellNavItemsContext = react$1.createContext(null);
1131
+ var ShellNavigationPreferenceContext = react$1.createContext(null);
1132
+ var ShellRoleContext = react$1.createContext(null);
1133
+ var ShellFooterContext = react$1.createContext(null);
1127
1134
  var ShellChromeContext = react$1.createContext(null);
1128
1135
  function toShellUser(session) {
1129
1136
  if (!session?.user) return null;
@@ -1192,7 +1199,7 @@ function ShellProvider({
1192
1199
  }),
1193
1200
  [devNotesMenu, myProfileHref]
1194
1201
  );
1195
- return /* @__PURE__ */ jsxRuntime.jsx(ShellAuthContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(ShellMetaContext.Provider, { value: meta, children: /* @__PURE__ */ jsxRuntime.jsx(ShellOrgContext.Provider, { value: organization ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellLinkedAccountsContext.Provider, { value: linkedAccounts ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellSupportProviderContext.Provider, { value: support ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellChromeContext.Provider, { value: chrome, children: /* @__PURE__ */ jsxRuntime.jsx(react.ChakraProvider, { theme: politogyTheme, children }) }) }) }) }) }) });
1202
+ return /* @__PURE__ */ jsxRuntime.jsx(ShellAuthContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(ShellMetaContext.Provider, { value: meta, children: /* @__PURE__ */ jsxRuntime.jsx(ShellOrgContext.Provider, { value: organization ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellLinkedAccountsContext.Provider, { value: linkedAccounts ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellSupportProviderContext.Provider, { value: support ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellModeContext.Provider, { value: null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellNavItemsContext.Provider, { value: null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellNavigationPreferenceContext.Provider, { value: null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellRoleContext.Provider, { value: null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellFooterContext.Provider, { value: null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellChromeContext.Provider, { value: chrome, children: /* @__PURE__ */ jsxRuntime.jsx(react.ChakraProvider, { theme: politogyTheme, children }) }) }) }) }) }) }) }) }) }) }) });
1196
1203
  }
1197
1204
  function useShellAuth() {
1198
1205
  const ctx = react$1.useContext(ShellAuthContext);
@@ -1231,6 +1238,614 @@ function useShellChrome() {
1231
1238
  }
1232
1239
  return ctx;
1233
1240
  }
1241
+ function useShellMode() {
1242
+ return react$1.useContext(ShellModeContext);
1243
+ }
1244
+ function useShellNavItems() {
1245
+ return react$1.useContext(ShellNavItemsContext);
1246
+ }
1247
+ function useShellNavigationPreference() {
1248
+ return react$1.useContext(ShellNavigationPreferenceContext);
1249
+ }
1250
+ function useShellRole() {
1251
+ return react$1.useContext(ShellRoleContext);
1252
+ }
1253
+ function useShellFooter() {
1254
+ return react$1.useContext(ShellFooterContext);
1255
+ }
1256
+ function BrandLogo({ src, alt = "Brand", className, style }) {
1257
+ if (!src) return null;
1258
+ return /* @__PURE__ */ jsxRuntime.jsx(
1259
+ "img",
1260
+ {
1261
+ src,
1262
+ alt,
1263
+ className,
1264
+ style,
1265
+ draggable: false
1266
+ }
1267
+ );
1268
+ }
1269
+ var BrandLogo_default = BrandLogo;
1270
+
1271
+ // src/lib/userDisplay.ts
1272
+ function getUserDisplayName(user) {
1273
+ if (!user) return "User";
1274
+ return user.profile?.full_name || user.profile?.name || user.user_metadata?.full_name || user.user_metadata?.name || (typeof user.email === "string" ? user.email.split("@")[0] : "") || user.email || "User";
1275
+ }
1276
+ function avatarUrlFromUser(user) {
1277
+ if (!user) return void 0;
1278
+ const meta = user.raw.user_metadata;
1279
+ return meta?.avatar_url ?? void 0;
1280
+ }
1281
+ function UserMenu() {
1282
+ const { user, status, signOut } = useShellAuth();
1283
+ const {
1284
+ myProfileHref,
1285
+ organizationSettingsHref,
1286
+ showContinueOnboarding,
1287
+ onContinueOnboarding
1288
+ } = useShellChrome();
1289
+ const linked = useShellLinkedAccounts();
1290
+ const mode = useShellMode();
1291
+ const org = useShellOrganization();
1292
+ const role = useShellRole();
1293
+ const navigate = reactRouterDom.useNavigate();
1294
+ const menuListBg = react.useColorModeValue("white", "gray.900");
1295
+ const menuListBorderColor = react.useColorModeValue("gray.200", "gray.700");
1296
+ if (status !== "authenticated" || !user) return null;
1297
+ const displayName = getUserDisplayName(user.raw);
1298
+ const avatarUrl = avatarUrlFromUser(user);
1299
+ const modeConfig = mode?.getModeConfig() ?? null;
1300
+ const currentOrg = org?.currentOrg ?? null;
1301
+ const linkedAccounts = linked?.linkedAccounts ?? [];
1302
+ const activeRoleConfig = role?.activeRoleConfig ?? null;
1303
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Flex, { alignItems: "center", children: /* @__PURE__ */ jsxRuntime.jsxs(react.Menu, { children: [
1304
+ /* @__PURE__ */ jsxRuntime.jsx(react.MenuButton, { py: 2, transition: "all 0.3s", _focus: { boxShadow: "none" }, children: /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { children: [
1305
+ /* @__PURE__ */ jsxRuntime.jsx(
1306
+ react.Avatar,
1307
+ {
1308
+ size: "sm",
1309
+ src: avatarUrl,
1310
+ name: displayName,
1311
+ bg: modeConfig?.primaryColor || "brand.500"
1312
+ }
1313
+ ),
1314
+ /* @__PURE__ */ jsxRuntime.jsxs(
1315
+ react.VStack,
1316
+ {
1317
+ display: { base: "none", md: "flex" },
1318
+ alignItems: "flex-start",
1319
+ spacing: "1px",
1320
+ ml: "2",
1321
+ children: [
1322
+ /* @__PURE__ */ jsxRuntime.jsx(react.HStack, { spacing: 2, children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", children: displayName }) }),
1323
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "gray.500", children: user.email })
1324
+ ]
1325
+ }
1326
+ ),
1327
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: { base: "none", md: "flex" }, children: /* @__PURE__ */ jsxRuntime.jsx(fi.FiChevronDown, {}) })
1328
+ ] }) }),
1329
+ /* @__PURE__ */ jsxRuntime.jsx(react.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.MenuList, { bg: menuListBg, borderColor: menuListBorderColor, zIndex: 1500, children: [
1330
+ /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiUser, {}), onClick: () => navigate(myProfileHref), children: "My Profile" }),
1331
+ showContinueOnboarding && /* @__PURE__ */ jsxRuntime.jsx(
1332
+ react.MenuItem,
1333
+ {
1334
+ icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiRotateCcw, {}),
1335
+ onClick: () => {
1336
+ if (onContinueOnboarding) onContinueOnboarding();
1337
+ else window.dispatchEvent(new CustomEvent("app:continue-onboarding"));
1338
+ },
1339
+ children: "Continue Onboarding"
1340
+ }
1341
+ ),
1342
+ organizationSettingsHref && /* @__PURE__ */ jsxRuntime.jsx(
1343
+ react.MenuItem,
1344
+ {
1345
+ icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiBriefcase, {}),
1346
+ onClick: () => navigate(organizationSettingsHref),
1347
+ children: "Organization Settings"
1348
+ }
1349
+ ),
1350
+ /* @__PURE__ */ jsxRuntime.jsx(react.MenuDivider, {}),
1351
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "gray.500", px: 3, py: 1, fontWeight: "semibold", children: "ROLES & ORGANIZATIONS" }),
1352
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { px: 3, py: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(react.VStack, { align: "stretch", spacing: 1, children: [
1353
+ currentOrg && currentOrg.role && /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { children: [
1354
+ /* @__PURE__ */ jsxRuntime.jsx(
1355
+ react.Badge,
1356
+ {
1357
+ size: "sm",
1358
+ colorScheme: currentOrg.role === "owner" ? "purple" : currentOrg.role === "admin" ? "blue" : "gray",
1359
+ children: currentOrg.role.charAt(0).toUpperCase() + currentOrg.role.slice(1)
1360
+ }
1361
+ ),
1362
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontSize: "xs", color: "gray.500", children: [
1363
+ "in ",
1364
+ currentOrg.name
1365
+ ] })
1366
+ ] }),
1367
+ activeRoleConfig && !currentOrg?.role && /* @__PURE__ */ jsxRuntime.jsx(react.Badge, { colorScheme: activeRoleConfig.color, size: "sm", children: activeRoleConfig.name })
1368
+ ] }) }),
1369
+ linked && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1370
+ /* @__PURE__ */ jsxRuntime.jsx(react.MenuDivider, {}),
1371
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "gray.500", px: 3, py: 1, fontWeight: "semibold", children: "ACCOUNTS" }),
1372
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { px: 3, py: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 2, children: [
1373
+ /* @__PURE__ */ jsxRuntime.jsx(react.Avatar, { size: "xs", src: avatarUrl, name: displayName }),
1374
+ /* @__PURE__ */ jsxRuntime.jsxs(react.VStack, { align: "start", spacing: 0, flex: 1, children: [
1375
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", fontWeight: "medium", color: "brand.600", children: displayName }),
1376
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "gray.400", children: "Active" })
1377
+ ] })
1378
+ ] }) }),
1379
+ linkedAccounts.map((account) => /* @__PURE__ */ jsxRuntime.jsx(
1380
+ react.MenuItem,
1381
+ {
1382
+ onClick: () => {
1383
+ void linked.switchToAccount(account.id);
1384
+ },
1385
+ _hover: { bg: "gray.50" },
1386
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 2, flex: 1, justify: "space-between", children: [
1387
+ /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 2, children: [
1388
+ /* @__PURE__ */ jsxRuntime.jsx(
1389
+ react.Avatar,
1390
+ {
1391
+ size: "xs",
1392
+ src: account.avatarUrl ?? void 0,
1393
+ name: account.displayName ?? account.email
1394
+ }
1395
+ ),
1396
+ /* @__PURE__ */ jsxRuntime.jsxs(react.VStack, { align: "start", spacing: 0, children: [
1397
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", fontWeight: "medium", noOfLines: 1, children: account.displayName ?? account.email.split("@")[0] }),
1398
+ /* @__PURE__ */ jsxRuntime.jsx(react.Tooltip, { label: account.email, placement: "top", hasArrow: true, children: /* @__PURE__ */ jsxRuntime.jsx(
1399
+ react.Text,
1400
+ {
1401
+ fontSize: "xs",
1402
+ color: "gray.500",
1403
+ maxW: "120px",
1404
+ noOfLines: 1,
1405
+ textOverflow: "ellipsis",
1406
+ children: account.email
1407
+ }
1408
+ ) })
1409
+ ] })
1410
+ ] }),
1411
+ /* @__PURE__ */ jsxRuntime.jsx(
1412
+ react.IconButton,
1413
+ {
1414
+ as: "span",
1415
+ role: "button",
1416
+ tabIndex: 0,
1417
+ "aria-label": "Remove account",
1418
+ icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiTrash2, {}),
1419
+ size: "xs",
1420
+ variant: "ghost",
1421
+ colorScheme: "red",
1422
+ onClick: (e) => {
1423
+ e.stopPropagation();
1424
+ linked.onRemoveAccount(account.id);
1425
+ }
1426
+ }
1427
+ )
1428
+ ] })
1429
+ },
1430
+ account.id
1431
+ )),
1432
+ /* @__PURE__ */ jsxRuntime.jsx(
1433
+ react.MenuItem,
1434
+ {
1435
+ icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiUserPlus, {}),
1436
+ onClick: linked.onAddAccount,
1437
+ color: "brand.500",
1438
+ children: "Add Account"
1439
+ }
1440
+ )
1441
+ ] }),
1442
+ /* @__PURE__ */ jsxRuntime.jsx(react.MenuDivider, {}),
1443
+ /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiLogOut, {}), onClick: () => void signOut(), children: "Sign out" })
1444
+ ] }) })
1445
+ ] }) });
1446
+ }
1447
+ function Header({ onOpen, id }) {
1448
+ const {
1449
+ pageTitle,
1450
+ breadcrumbs,
1451
+ headerActions,
1452
+ headerIconsSlot,
1453
+ brandLogoSrc,
1454
+ devNotesMenu
1455
+ } = useShellChrome();
1456
+ const mobileNavBg = react.useColorModeValue("white", "gray.900");
1457
+ const mobileNavBorderColor = react.useColorModeValue("gray.200", "gray.700");
1458
+ return /* @__PURE__ */ jsxRuntime.jsx(
1459
+ react.Flex,
1460
+ {
1461
+ id: id || "mobile-nav-container",
1462
+ ml: { base: 0, md: 60 },
1463
+ px: { base: 4, md: 4 },
1464
+ height: "20",
1465
+ alignItems: "center",
1466
+ bg: mobileNavBg,
1467
+ borderBottomWidth: "1px",
1468
+ borderBottomColor: mobileNavBorderColor,
1469
+ justifyContent: { base: "space-between", md: "space-between" },
1470
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { w: "full", mx: "auto", align: "center", justify: "space-between", children: [
1471
+ /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 4, minW: "0", children: [
1472
+ onOpen ? /* @__PURE__ */ jsxRuntime.jsx(
1473
+ react.IconButton,
1474
+ {
1475
+ display: { base: "flex", md: "none" },
1476
+ onClick: onOpen,
1477
+ variant: "outline",
1478
+ "aria-label": "open menu",
1479
+ icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiMenu, {})
1480
+ }
1481
+ ) : null,
1482
+ brandLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: { base: "flex", md: "none" }, h: "32px", children: /* @__PURE__ */ jsxRuntime.jsx(BrandLogo_default, { src: brandLogoSrc, className: "h-full w-auto object-contain" }) }) : null,
1483
+ /* @__PURE__ */ jsxRuntime.jsxs(
1484
+ react.VStack,
1485
+ {
1486
+ align: "flex-start",
1487
+ spacing: 0,
1488
+ minW: "0",
1489
+ display: { base: "none", md: "flex" },
1490
+ children: [
1491
+ pageTitle ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "lg", fontWeight: "bold", noOfLines: 1, children: pageTitle }) : null,
1492
+ breadcrumbs && breadcrumbs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(react.HStack, { spacing: 2, color: "gray.500", fontSize: "sm", mt: "1px", minW: "0", children: breadcrumbs.map((b, idx) => /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "inline-flex", alignItems: "center", minW: "0", children: [
1493
+ idx > 0 ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { color: "gray.400", mr: 2, children: " > " }) : null,
1494
+ b.href ? /* @__PURE__ */ jsxRuntime.jsx(
1495
+ react.Link,
1496
+ {
1497
+ as: reactRouterDom.NavLink,
1498
+ to: b.href,
1499
+ _hover: { textDecoration: "underline" },
1500
+ noOfLines: 1,
1501
+ children: b.label
1502
+ }
1503
+ ) : /* @__PURE__ */ jsxRuntime.jsx(react.Text, { noOfLines: 1, children: b.label })
1504
+ ] }, `${b.label}-${idx}`)) }) : null
1505
+ ]
1506
+ }
1507
+ )
1508
+ ] }),
1509
+ /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 0, align: "center", children: [
1510
+ /* @__PURE__ */ jsxRuntime.jsxs(
1511
+ react.HStack,
1512
+ {
1513
+ spacing: 2,
1514
+ mr: "15px",
1515
+ color: "gray.600",
1516
+ sx: {
1517
+ '& button:not([role="menuitem"]):not([data-menu-item])': {
1518
+ width: "32px",
1519
+ height: "32px",
1520
+ minWidth: "32px",
1521
+ padding: 0
1522
+ },
1523
+ '& button:not([role="menuitem"]):not([data-menu-item]) svg': {
1524
+ width: "20px",
1525
+ height: "20px"
1526
+ }
1527
+ },
1528
+ children: [
1529
+ headerActions,
1530
+ headerIconsSlot,
1531
+ devNotesMenu
1532
+ ]
1533
+ }
1534
+ ),
1535
+ /* @__PURE__ */ jsxRuntime.jsx(UserMenu, {})
1536
+ ] })
1537
+ ] })
1538
+ }
1539
+ );
1540
+ }
1541
+ function BrandIcon({
1542
+ name,
1543
+ size,
1544
+ className,
1545
+ style,
1546
+ alt,
1547
+ basePath = "/brand/icons/"
1548
+ }) {
1549
+ const a11yLabel = alt ?? "";
1550
+ const isDecorative = a11yLabel === "";
1551
+ const inlineSize = size ? { width: size, height: size, ...style } : style;
1552
+ return /* @__PURE__ */ jsxRuntime.jsx(
1553
+ "img",
1554
+ {
1555
+ src: `${basePath}${name}.svg`,
1556
+ alt: a11yLabel,
1557
+ role: isDecorative ? "presentation" : void 0,
1558
+ "aria-hidden": isDecorative ? true : void 0,
1559
+ className,
1560
+ style: inlineSize,
1561
+ draggable: false
1562
+ }
1563
+ );
1564
+ }
1565
+ var BrandIcon_default = BrandIcon;
1566
+ var MODE_CAMPAIGN = "campaign";
1567
+ var MODE_PETITION = "petition";
1568
+ function NavItem({
1569
+ icon,
1570
+ brandIcon,
1571
+ children,
1572
+ href,
1573
+ action,
1574
+ subItems,
1575
+ badge,
1576
+ subLabel,
1577
+ isSubItem = false,
1578
+ isExpanded,
1579
+ onToggle,
1580
+ menuKey,
1581
+ isDisabled: navIsDisabled,
1582
+ disabled,
1583
+ ...rest
1584
+ }) {
1585
+ const location = reactRouterDom.useLocation();
1586
+ const navigate = reactRouterDom.useNavigate();
1587
+ const mode = useShellMode();
1588
+ const currentMode = mode?.currentMode ?? null;
1589
+ const modeConfig = mode?.getModeConfig() ?? null;
1590
+ const navPref = useShellNavigationPreference();
1591
+ const showSubMenu = navPref?.showSubMenu ?? true;
1592
+ const navHoverGradient = currentMode === MODE_CAMPAIGN ? "linear-gradient(90deg, #F2C94C 0%, #E63946 100%)" : currentMode === MODE_PETITION ? "linear-gradient(90deg, #F2C94C 0%, #007BFF 100%)" : "linear-gradient(90deg, #007BFF 0%, #E63946 100%)";
1593
+ const gradientSweepBefore = {
1594
+ content: '""',
1595
+ position: "absolute",
1596
+ top: 0,
1597
+ left: 0,
1598
+ bottom: 0,
1599
+ width: "0%",
1600
+ background: navHoverGradient,
1601
+ transition: "width 300ms ease",
1602
+ pointerEvents: "none",
1603
+ zIndex: 0
1604
+ };
1605
+ const isDisabled = Boolean(navIsDisabled || disabled);
1606
+ const effectiveHref = href || (Array.isArray(subItems) && subItems.length > 0 ? subItems[0].href : void 0);
1607
+ const effectivePathname = effectiveHref?.split("?")[0];
1608
+ const currentFullPath = location.pathname + location.search;
1609
+ const currentSearchParams = react$1.useMemo(
1610
+ () => new URLSearchParams(location.search),
1611
+ [location.search]
1612
+ );
1613
+ const matchesSubItem = (itemHref) => {
1614
+ if (itemHref === currentFullPath) return true;
1615
+ const itemPath = itemHref.split("?")[0];
1616
+ const itemSearch = itemHref.includes("?") ? itemHref.split("?")[1] : "";
1617
+ if (itemPath === location.pathname && !itemSearch) {
1618
+ return true;
1619
+ }
1620
+ if (location.pathname.startsWith(`${itemPath}/`)) {
1621
+ const itemSegments = itemPath.split("/").filter(Boolean);
1622
+ const locationSegments = location.pathname.split("/").filter(Boolean);
1623
+ const itemLastSegment = itemSegments[itemSegments.length - 1];
1624
+ const locationLastSegment = locationSegments[locationSegments.length - 1];
1625
+ if (itemLastSegment && itemLastSegment === locationLastSegment) {
1626
+ return true;
1627
+ }
1628
+ }
1629
+ if (itemPath === location.pathname && itemSearch) {
1630
+ const itemSearchParams = new URLSearchParams(itemSearch);
1631
+ const itemTab = itemSearchParams.get("tab") || itemSearchParams.get("view");
1632
+ if (!itemTab) return true;
1633
+ return itemTab === currentSearchParams.get("tab");
1634
+ }
1635
+ if (itemPath && !itemHref.includes("?") && itemPath !== effectivePathname) {
1636
+ const segment = itemPath.split("/").pop();
1637
+ if (segment && location.pathname.endsWith("/" + segment) && location.pathname.startsWith(itemPath.split("/").slice(0, -1).join("/"))) {
1638
+ return true;
1639
+ }
1640
+ }
1641
+ return false;
1642
+ };
1643
+ const isActive = isSubItem ? matchesSubItem(effectiveHref || "") : (() => {
1644
+ if (!effectivePathname) return false;
1645
+ if (location.pathname === effectivePathname) return true;
1646
+ if (location.pathname.startsWith(`${effectivePathname}/`)) return true;
1647
+ const dashboardOverviewMatch = effectivePathname.match(
1648
+ /^\/[^/]+\/[^/]*\/dashboard\/overview$/
1649
+ );
1650
+ if (dashboardOverviewMatch) {
1651
+ const dashboardRoot = effectivePathname.replace(/\/overview$/, "");
1652
+ return location.pathname === dashboardRoot || location.pathname.startsWith(`${dashboardRoot}/`) || location.pathname.startsWith(`${dashboardRoot}&`);
1653
+ }
1654
+ return effectivePathname !== `/${location.pathname.split("/")[1]}/dashboard` && location.pathname.startsWith(effectivePathname + "/");
1655
+ })();
1656
+ const hasSubItems = showSubMenu && Array.isArray(subItems) && subItems.length > 0;
1657
+ const hasActiveChild = hasSubItems && subItems.some((item) => matchesSubItem(item.href || ""));
1658
+ const isParentActive = isActive || hasActiveChild;
1659
+ const isSubMenuOpen = isExpanded !== void 0 ? isExpanded : hasSubItems && subItems.some((item) => matchesSubItem(item.href || ""));
1660
+ const expandedRowBg = isParentActive ? modeConfig?.primaryColor || "brand.500" : isSubMenuOpen ? "gray.100" : "transparent";
1661
+ const expandedRowTextColor = isParentActive ? "white" : isSubMenuOpen ? "gray.900" : "gray.600";
1662
+ const disabledRowBg = isSubItem ? "gray.50" : "transparent";
1663
+ const disabledRowTextColor = "gray.400";
1664
+ if (hasSubItems) {
1665
+ const headerProps = {
1666
+ align: "center",
1667
+ px: "4",
1668
+ py: "2.5",
1669
+ mx: "4",
1670
+ w: "auto",
1671
+ borderTopRadius: "lg",
1672
+ borderBottomRadius: isSubMenuOpen ? 0 : "lg",
1673
+ role: "group",
1674
+ cursor: isDisabled ? "not-allowed" : "pointer",
1675
+ opacity: 1,
1676
+ pointerEvents: isDisabled ? "none" : "auto",
1677
+ "data-nav-item-active": String(isParentActive),
1678
+ position: "relative",
1679
+ overflow: "hidden",
1680
+ bg: isDisabled ? disabledRowBg : expandedRowBg,
1681
+ color: isDisabled ? disabledRowTextColor : expandedRowTextColor,
1682
+ _before: isDisabled ? void 0 : gradientSweepBefore,
1683
+ _hover: {
1684
+ color: isDisabled ? disabledRowTextColor : "white",
1685
+ _before: isDisabled ? void 0 : { width: "100%" }
1686
+ },
1687
+ "aria-disabled": isDisabled ? "true" : "false",
1688
+ onClick: (e) => {
1689
+ if (isDisabled) return;
1690
+ if (effectiveHref) e.preventDefault();
1691
+ e.stopPropagation();
1692
+ onToggle?.(menuKey || null);
1693
+ }
1694
+ };
1695
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { children: [
1696
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { ...headerProps, ...rest, children: [
1697
+ brandIcon ? /* @__PURE__ */ jsxRuntime.jsx(
1698
+ react.Box,
1699
+ {
1700
+ mr: "4",
1701
+ display: "inline-flex",
1702
+ alignItems: "center",
1703
+ position: "relative",
1704
+ zIndex: 1,
1705
+ filter: isParentActive ? "brightness(0) invert(1)" : void 0,
1706
+ _groupHover: isDisabled ? void 0 : { filter: "brightness(0) invert(1)" },
1707
+ children: /* @__PURE__ */ jsxRuntime.jsx(BrandIcon_default, { name: brandIcon, size: 18 })
1708
+ }
1709
+ ) : icon ? /* @__PURE__ */ jsxRuntime.jsx(
1710
+ react.Box,
1711
+ {
1712
+ mr: "4",
1713
+ fontSize: "16",
1714
+ position: "relative",
1715
+ zIndex: 1,
1716
+ _groupHover: {
1717
+ color: isDisabled ? disabledRowTextColor : "white"
1718
+ },
1719
+ as: icon
1720
+ }
1721
+ ) : null,
1722
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { flex: "1", position: "relative", zIndex: 1, children }),
1723
+ /* @__PURE__ */ jsxRuntime.jsx(
1724
+ react.Box,
1725
+ {
1726
+ as: fi.FiChevronDown,
1727
+ position: "relative",
1728
+ zIndex: 1,
1729
+ transform: isSubMenuOpen ? "rotate(180deg)" : void 0,
1730
+ transition: "transform 0.2s"
1731
+ }
1732
+ )
1733
+ ] }),
1734
+ /* @__PURE__ */ jsxRuntime.jsx(react.Collapse, { in: isSubMenuOpen, animateOpacity: true, children: /* @__PURE__ */ jsxRuntime.jsx(
1735
+ react.Box,
1736
+ {
1737
+ px: "0",
1738
+ mx: "4",
1739
+ w: "auto",
1740
+ mb: "2",
1741
+ py: "1",
1742
+ borderTopRadius: 0,
1743
+ borderBottomRadius: "md",
1744
+ bg: isDisabled ? "gray.100" : "gray.200",
1745
+ children: subItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1746
+ NavItem,
1747
+ {
1748
+ icon: item.icon,
1749
+ brandIcon: item.brandIcon,
1750
+ href: item.href,
1751
+ isSubItem: true,
1752
+ isDisabled: item.disabled,
1753
+ subLabel: item.subLabel,
1754
+ children: item.name
1755
+ },
1756
+ item.name
1757
+ ))
1758
+ }
1759
+ ) })
1760
+ ] });
1761
+ }
1762
+ const handleClick = (e) => {
1763
+ if (isDisabled) {
1764
+ e.preventDefault();
1765
+ return;
1766
+ }
1767
+ if (action) {
1768
+ e.preventDefault();
1769
+ action();
1770
+ return;
1771
+ }
1772
+ if (effectiveHref) {
1773
+ e.preventDefault();
1774
+ navigate(effectiveHref);
1775
+ }
1776
+ };
1777
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "a", href: effectiveHref || "#", onClick: handleClick, style: { textDecoration: "none" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1778
+ react.Flex,
1779
+ {
1780
+ align: "center",
1781
+ px: "4",
1782
+ py: "2.5",
1783
+ mx: isSubItem ? "0" : "4",
1784
+ w: isSubItem ? "full" : "auto",
1785
+ borderRadius: isSubItem ? "0" : "lg",
1786
+ role: "group",
1787
+ cursor: isDisabled ? "not-allowed" : "pointer",
1788
+ opacity: 1,
1789
+ pointerEvents: isDisabled ? "none" : "auto",
1790
+ "data-nav-item-active": String(isActive),
1791
+ position: "relative",
1792
+ overflow: "hidden",
1793
+ bg: isDisabled ? disabledRowBg : isActive ? isSubItem ? "gray.100" : modeConfig?.primaryColor || "brand.500" : "transparent",
1794
+ color: isDisabled ? disabledRowTextColor : isActive ? isSubItem ? modeConfig?.primaryColor || "brand.500" : "white" : "gray.600",
1795
+ _before: isDisabled ? void 0 : gradientSweepBefore,
1796
+ _hover: {
1797
+ color: isDisabled ? disabledRowTextColor : "white",
1798
+ _before: isDisabled ? void 0 : { width: "100%" }
1799
+ },
1800
+ "aria-disabled": isDisabled ? "true" : "false",
1801
+ onClick: handleClick,
1802
+ children: [
1803
+ brandIcon ? /* @__PURE__ */ jsxRuntime.jsx(
1804
+ react.Box,
1805
+ {
1806
+ mr: "4",
1807
+ display: "inline-flex",
1808
+ alignItems: "center",
1809
+ position: "relative",
1810
+ zIndex: 1,
1811
+ filter: isActive && !isSubItem ? "brightness(0) invert(1)" : void 0,
1812
+ _groupHover: isDisabled ? void 0 : { filter: "brightness(0) invert(1)" },
1813
+ children: /* @__PURE__ */ jsxRuntime.jsx(BrandIcon_default, { name: brandIcon, size: 18 })
1814
+ }
1815
+ ) : icon ? /* @__PURE__ */ jsxRuntime.jsx(
1816
+ react.Box,
1817
+ {
1818
+ mr: "4",
1819
+ fontSize: "16",
1820
+ position: "relative",
1821
+ zIndex: 1,
1822
+ _groupHover: {
1823
+ color: isDisabled ? disabledRowTextColor : "white"
1824
+ },
1825
+ as: icon
1826
+ }
1827
+ ) : null,
1828
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { flex: "1", position: "relative", zIndex: 1, children: [
1829
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { children }),
1830
+ subLabel ? /* @__PURE__ */ jsxRuntime.jsx(
1831
+ react.Text,
1832
+ {
1833
+ mt: 0.5,
1834
+ fontSize: "10px",
1835
+ lineHeight: "1.3",
1836
+ color: isDisabled ? "gray.400" : "gray.400",
1837
+ children: subLabel
1838
+ }
1839
+ ) : null,
1840
+ badge && /* @__PURE__ */ jsxRuntime.jsx(react.Badge, { colorScheme: "orange", size: "xs", mt: 1, fontSize: "xs", display: "block", children: badge })
1841
+ ] })
1842
+ ]
1843
+ }
1844
+ ) });
1845
+ }
1846
+ var NavItem_default = NavItem;
1847
+
1848
+ // src/lib/orgColors.ts
1234
1849
  var HEX_COLOR_PATTERN = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
1235
1850
  function normalizeHexColor(value) {
1236
1851
  const trimmed = value?.trim();
@@ -1239,6 +1854,34 @@ function normalizeHexColor(value) {
1239
1854
  const [r, g, b] = trimmed.slice(1).split("");
1240
1855
  return `#${r}${r}${g}${g}${b}${b}`;
1241
1856
  }
1857
+ function hexToRgba(hex, alpha) {
1858
+ const normalized = normalizeHexColor(hex);
1859
+ if (!normalized) return null;
1860
+ const red = parseInt(normalized.slice(1, 3), 16);
1861
+ const green = parseInt(normalized.slice(3, 5), 16);
1862
+ const blue = parseInt(normalized.slice(5, 7), 16);
1863
+ return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
1864
+ }
1865
+ function lightenHexColor(hex, amount) {
1866
+ const normalized = normalizeHexColor(hex);
1867
+ if (!normalized) return null;
1868
+ const clamp = (value) => Math.max(0, Math.min(255, Math.round(value)));
1869
+ const blend = (channel) => clamp(channel + (255 - channel) * amount);
1870
+ const red = parseInt(normalized.slice(1, 3), 16);
1871
+ const green = parseInt(normalized.slice(3, 5), 16);
1872
+ const blue = parseInt(normalized.slice(5, 7), 16);
1873
+ return `#${blend(red).toString(16).padStart(2, "0")}${blend(green).toString(16).padStart(2, "0")}${blend(blue).toString(16).padStart(2, "0")}`;
1874
+ }
1875
+ function getOrganizationBrandColor(organization) {
1876
+ if (!organization) return null;
1877
+ const direct = normalizeHexColor(organization.brandColor);
1878
+ if (direct) return direct;
1879
+ const brandColors = Array.isArray(organization.settings?.brand_colors) ? organization.settings?.brand_colors : [];
1880
+ const firstBrandColor = brandColors?.find(
1881
+ (entry) => typeof entry?.value === "string" && normalizeHexColor(entry.value)
1882
+ );
1883
+ return normalizeHexColor(firstBrandColor?.value ?? null);
1884
+ }
1242
1885
  function getOrganizationBadgeLetters(name) {
1243
1886
  const normalizedName = String(name || "").trim().replace(/[^a-zA-Z0-9\s]+/g, " ");
1244
1887
  const parts = normalizedName.split(/\s+/).filter(Boolean);
@@ -1273,60 +1916,465 @@ function OrgBadge({ name, logoUrl, brandColor, size }) {
1273
1916
  }
1274
1917
  );
1275
1918
  }
1276
- function OrgSelector() {
1919
+ function OrganizationIdCopy({ orgId }) {
1920
+ const { hasCopied, onCopy } = react.useClipboard(orgId);
1921
+ const copiedAnimation = react$2.keyframes`
1922
+ 0% { opacity: 0; transform: translateY(6px); }
1923
+ 20% { opacity: 1; transform: translateY(0); }
1924
+ 100% { opacity: 0; transform: translateY(-8px); }
1925
+ `;
1926
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Tooltip, { label: orgId, placement: "top", hasArrow: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
1927
+ react.Flex,
1928
+ {
1929
+ align: "center",
1930
+ cursor: "pointer",
1931
+ onClick: onCopy,
1932
+ _hover: { bg: "gray.100" },
1933
+ borderRadius: "md",
1934
+ px: 2,
1935
+ py: 1,
1936
+ position: "relative",
1937
+ transition: "all 0.2s",
1938
+ children: [
1939
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontSize: "xs", color: hasCopied ? "green.500" : "gray.600", fontWeight: "normal", children: [
1940
+ "...",
1941
+ orgId.slice(-8)
1942
+ ] }),
1943
+ hasCopied && /* @__PURE__ */ jsxRuntime.jsx(
1944
+ react.Box,
1945
+ {
1946
+ position: "absolute",
1947
+ bottom: "100%",
1948
+ mb: "6px",
1949
+ px: "2",
1950
+ py: "1",
1951
+ fontSize: "xs",
1952
+ bg: "gray.700",
1953
+ color: "white",
1954
+ borderRadius: "md",
1955
+ animation: `${copiedAnimation} 0.9s ease-out`,
1956
+ pointerEvents: "none",
1957
+ children: "Copied!"
1958
+ }
1959
+ )
1960
+ ]
1961
+ }
1962
+ ) });
1963
+ }
1964
+ function OrgPill() {
1277
1965
  const org = useShellOrganization();
1966
+ const { user } = useShellAuth();
1967
+ const currentOrg = org?.currentOrg ?? null;
1968
+ const organizations = org?.organizations ?? [];
1969
+ const switchOrganization = org?.switchOrganization;
1970
+ const loadingOrgs = org?.loadingOrgs ?? false;
1971
+ const unselectedOrganizations = react$1.useMemo(
1972
+ () => organizations.filter((o) => o.id !== currentOrg?.id),
1973
+ [organizations, currentOrg?.id]
1974
+ );
1975
+ const selectedOrgBrandColor = react$1.useMemo(
1976
+ () => currentOrg ? getOrganizationBrandColor(currentOrg) : null,
1977
+ [currentOrg]
1978
+ );
1979
+ const selectedOrgColor = selectedOrgBrandColor || "var(--mode-primary-color, #ea6a3a)";
1980
+ const selectedOrgMenuBg = selectedOrgBrandColor && lightenHexColor(selectedOrgBrandColor, 0.12) || "#4a4a4a";
1278
1981
  if (!org) return null;
1279
- const { currentOrg, organizations, switchOrganization, createOrgHref } = org;
1280
- const others = organizations.filter((o) => o.id !== currentOrg?.id);
1281
- return /* @__PURE__ */ jsxRuntime.jsxs(react.Menu, { placement: "bottom-start", children: [
1282
- /* @__PURE__ */ jsxRuntime.jsx(
1283
- react.MenuButton,
1284
- {
1285
- as: react.Box,
1286
- cursor: "pointer",
1287
- px: 2,
1288
- py: 1,
1289
- borderRadius: "md",
1290
- _hover: { bg: "gray.100" },
1291
- _active: { bg: "gray.200" },
1292
- "aria-label": "Switch organization",
1293
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 2, align: "center", children: [
1294
- currentOrg ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1982
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { mx: "4", mb: "3", children: [
1983
+ /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { justify: "space-between", align: "center", mb: "2", children: [
1984
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "gray.500", fontWeight: "semibold", children: "ORGANIZATION" }),
1985
+ currentOrg?.id && currentOrg.id !== user?.id && /* @__PURE__ */ jsxRuntime.jsx(OrganizationIdCopy, { orgId: currentOrg.id })
1986
+ ] }),
1987
+ loadingOrgs && !currentOrg ? /* @__PURE__ */ jsxRuntime.jsx(react.Skeleton, { height: "32px", width: "full", borderRadius: "md" }) : /* @__PURE__ */ jsxRuntime.jsxs(react.Menu, { gutter: 0, children: [
1988
+ /* @__PURE__ */ jsxRuntime.jsx(
1989
+ react.MenuButton,
1990
+ {
1991
+ as: react.Button,
1992
+ rightIcon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiChevronDown, {}),
1993
+ size: "sm",
1994
+ width: "full",
1995
+ bg: currentOrg?.id ? selectedOrgColor : "gray.100",
1996
+ borderColor: currentOrg?.id ? selectedOrgColor : "gray.300",
1997
+ color: currentOrg?.id ? "white" : "gray.700",
1998
+ _hover: {
1999
+ bg: currentOrg?.id ? selectedOrgColor : "gray.200",
2000
+ color: currentOrg?.id ? "white" : "gray.900"
2001
+ },
2002
+ _active: {
2003
+ bg: currentOrg?.id ? selectedOrgColor : "gray.200",
2004
+ color: currentOrg?.id ? "white" : "gray.900"
2005
+ },
2006
+ _expanded: {
2007
+ bg: currentOrg?.id ? selectedOrgColor : "gray.200",
2008
+ color: currentOrg?.id ? "white" : "gray.900"
2009
+ },
2010
+ textAlign: "left",
2011
+ justifyContent: "flex-start",
2012
+ isDisabled: loadingOrgs && organizations.length === 0,
2013
+ sx: currentOrg?.id ? {
2014
+ color: "white",
2015
+ ".chakra-button__icon": { color: "white" }
2016
+ } : void 0,
2017
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: "2.5", minW: 0, align: "center", children: [
1295
2018
  /* @__PURE__ */ jsxRuntime.jsx(
1296
2019
  OrgBadge,
1297
2020
  {
1298
- name: currentOrg.name,
1299
- logoUrl: currentOrg.logoUrl,
1300
- brandColor: currentOrg.brandColor,
1301
- size: "24px"
2021
+ name: currentOrg?.name,
2022
+ logoUrl: currentOrg?.logoUrl,
2023
+ brandColor: selectedOrgBrandColor,
2024
+ size: "28px"
1302
2025
  }
1303
2026
  ),
1304
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "600", color: "gray.800", noOfLines: 1, children: currentOrg.name })
1305
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", color: "gray.500", children: "Select organization" }),
1306
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontSize: "xs", color: "gray.500", "aria-hidden": "true", children: "\u25BE" })
1307
- ] })
1308
- }
1309
- ),
1310
- /* @__PURE__ */ jsxRuntime.jsx(react.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.MenuList, { zIndex: 1500, children: [
1311
- others.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { isDisabled: true, children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", color: "gray.500", children: "No other organizations" }) }),
1312
- others.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
1313
- react.MenuItem,
1314
- {
1315
- onClick: () => {
1316
- void switchOrganization(o.id);
1317
- },
1318
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 2, align: "center", children: [
1319
- /* @__PURE__ */ jsxRuntime.jsx(OrgBadge, { name: o.name, logoUrl: o.logoUrl, brandColor: o.brandColor, size: "20px" }),
1320
- /* @__PURE__ */ jsxRuntime.jsx(react.Flex, { direction: "column", children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "600", children: o.name }) })
2027
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: currentOrg?.name || "No organizations" })
1321
2028
  ] })
2029
+ }
2030
+ ),
2031
+ /* @__PURE__ */ jsxRuntime.jsx(react.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
2032
+ react.MenuList,
2033
+ {
2034
+ bg: currentOrg?.id ? selectedOrgMenuBg : "gray.100",
2035
+ borderColor: currentOrg?.id ? selectedOrgColor : "gray.300",
2036
+ color: currentOrg?.id ? "white" : "gray.800",
2037
+ mt: "1",
2038
+ minW: "13rem",
2039
+ maxH: "60vh",
2040
+ overflowY: "auto",
2041
+ zIndex: "modal",
2042
+ boxShadow: "2xl",
2043
+ children: [
2044
+ unselectedOrganizations.map((o) => {
2045
+ const orgBrandColor = getOrganizationBrandColor(o);
2046
+ return /* @__PURE__ */ jsxRuntime.jsx(
2047
+ react.MenuItem,
2048
+ {
2049
+ onClick: () => switchOrganization?.(o.id),
2050
+ bg: "transparent",
2051
+ color: currentOrg?.id ? "white" : "inherit",
2052
+ _hover: {
2053
+ bg: currentOrg?.id ? lightenHexColor(selectedOrgBrandColor || "#ea6a3a", 0.2) || "#555555" : "gray.100",
2054
+ color: currentOrg?.id ? "white" : "gray.900"
2055
+ },
2056
+ _focus: {
2057
+ bg: currentOrg?.id ? lightenHexColor(selectedOrgBrandColor || "#ea6a3a", 0.2) || "#555555" : "gray.100",
2058
+ color: currentOrg?.id ? "white" : "gray.900"
2059
+ },
2060
+ _active: {
2061
+ bg: currentOrg?.id ? lightenHexColor(selectedOrgBrandColor || "#ea6a3a", 0.24) || "#5d5d5d" : "gray.200",
2062
+ color: currentOrg?.id ? "white" : "gray.900"
2063
+ },
2064
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { justify: "space-between", align: "center", width: "100%", overflow: "hidden", children: [
2065
+ /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { minW: 0, flex: "1", spacing: "2.5", children: [
2066
+ /* @__PURE__ */ jsxRuntime.jsx(
2067
+ OrgBadge,
2068
+ {
2069
+ name: o.name,
2070
+ logoUrl: o.logoUrl,
2071
+ brandColor: orgBrandColor,
2072
+ size: "24px"
2073
+ }
2074
+ ),
2075
+ /* @__PURE__ */ jsxRuntime.jsx(
2076
+ react.Text,
2077
+ {
2078
+ overflow: "hidden",
2079
+ textOverflow: "ellipsis",
2080
+ whiteSpace: "nowrap",
2081
+ flex: "1",
2082
+ children: o.name
2083
+ }
2084
+ )
2085
+ ] }),
2086
+ /* @__PURE__ */ jsxRuntime.jsx(
2087
+ react.Text,
2088
+ {
2089
+ fontSize: "xs",
2090
+ color: currentOrg?.id ? "whiteAlpha.700" : "gray.500",
2091
+ ml: 2,
2092
+ flexShrink: 0,
2093
+ children: o.id.slice(-8)
2094
+ }
2095
+ )
2096
+ ] })
2097
+ },
2098
+ o.id
2099
+ );
2100
+ }),
2101
+ /* @__PURE__ */ jsxRuntime.jsx(react.MenuDivider, { my: 0, borderColor: currentOrg?.id ? "whiteAlpha.300" : void 0 }),
2102
+ /* @__PURE__ */ jsxRuntime.jsx(
2103
+ react.MenuItem,
2104
+ {
2105
+ onClick: () => window.dispatchEvent(new CustomEvent("open-create-org")),
2106
+ fontWeight: "bold",
2107
+ bg: "transparent",
2108
+ color: currentOrg?.id ? "white" : "inherit",
2109
+ my: 0,
2110
+ _hover: {
2111
+ bg: currentOrg?.id ? lightenHexColor(selectedOrgBrandColor || "#ea6a3a", 0.2) || "#555555" : "gray.100",
2112
+ color: currentOrg?.id ? "white" : "gray.900"
2113
+ },
2114
+ _focus: {
2115
+ bg: currentOrg?.id ? lightenHexColor(selectedOrgBrandColor || "#ea6a3a", 0.2) || "#555555" : "gray.100",
2116
+ color: currentOrg?.id ? "white" : "gray.900"
2117
+ },
2118
+ _active: {
2119
+ bg: currentOrg?.id ? lightenHexColor(selectedOrgBrandColor || "#ea6a3a", 0.24) || "#5d5d5d" : "gray.200",
2120
+ color: currentOrg?.id ? "white" : "gray.900"
2121
+ },
2122
+ fontSize: "sm",
2123
+ children: "+ New Organization"
2124
+ }
2125
+ )
2126
+ ]
2127
+ }
2128
+ ) })
2129
+ ] })
2130
+ ] });
2131
+ }
2132
+ var OrgPill_default = OrgPill;
2133
+ function ModePill() {
2134
+ const mode = useShellMode();
2135
+ if (!mode) return null;
2136
+ const { currentMode, modes, switchMode, getModeConfig } = mode;
2137
+ const modeConfig = getModeConfig();
2138
+ if (!modeConfig) return null;
2139
+ const hasMultipleModes = modes.length > 1;
2140
+ const isDisabled = !hasMultipleModes;
2141
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { mx: "4", mb: "4", children: /* @__PURE__ */ jsxRuntime.jsxs(react.Menu, { gutter: 0, children: [
2142
+ /* @__PURE__ */ jsxRuntime.jsx(
2143
+ react.MenuButton,
2144
+ {
2145
+ as: react.Button,
2146
+ leftIcon: modeConfig.icon,
2147
+ rightIcon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiChevronDown, {}),
2148
+ size: "sm",
2149
+ width: "full",
2150
+ bg: modeConfig.primaryColor,
2151
+ borderColor: modeConfig.primaryColor,
2152
+ color: modeConfig.white,
2153
+ _disabled: {
2154
+ bg: modeConfig.primaryColor,
2155
+ borderColor: modeConfig.primaryColor,
2156
+ color: modeConfig.white,
2157
+ cursor: "not-allowed",
2158
+ opacity: 1
1322
2159
  },
1323
- o.id
1324
- )),
1325
- createOrgHref && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1326
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuDivider, {}),
1327
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { as: "a", href: createOrgHref, children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", color: "brand.500", fontWeight: "600", children: "Create organization" }) })
2160
+ isDisabled,
2161
+ _hover: {
2162
+ bg: modeConfig.primaryColor,
2163
+ color: modeConfig.white
2164
+ },
2165
+ _active: {
2166
+ bg: modeConfig.primaryColor,
2167
+ color: modeConfig.white
2168
+ },
2169
+ children: modeConfig.name
2170
+ }
2171
+ ),
2172
+ hasMultipleModes && /* @__PURE__ */ jsxRuntime.jsx(react.MenuList, { children: modes.map((m) => /* @__PURE__ */ jsxRuntime.jsx(
2173
+ react.MenuItem,
2174
+ {
2175
+ onClick: () => switchMode(m.id),
2176
+ bg: "transparent",
2177
+ color: currentMode === m.id ? m.primaryColor : "inherit",
2178
+ _hover: { bg: m.bgColor, color: m.primaryColor },
2179
+ icon: m.icon,
2180
+ children: m.name
2181
+ },
2182
+ m.id
2183
+ )) })
2184
+ ] }) });
2185
+ }
2186
+ var ModePill_default = ModePill;
2187
+ function Sidebar({ onClose, id }) {
2188
+ const { brandLogoSrc } = useShellChrome();
2189
+ const navItems = useShellNavItems()?.items ?? [];
2190
+ const footer = useShellFooter();
2191
+ const org = useShellOrganization();
2192
+ const currentOrg = org?.currentOrg ?? null;
2193
+ const location = reactRouterDom.useLocation();
2194
+ const sidebarBg = react.useColorModeValue("white", "gray.900");
2195
+ const sidebarBorderColor = react.useColorModeValue("gray.200", "gray.700");
2196
+ const [expandedMenu, setExpandedMenu] = react$1.useState(null);
2197
+ react$1.useEffect(() => {
2198
+ const activeMenu = navItems.find(
2199
+ (item) => item.children && item.children.some((child) => {
2200
+ if (!child.href) return false;
2201
+ const childPath = child.href.split("?")[0];
2202
+ if (!childPath) return false;
2203
+ return location.pathname === childPath || location.pathname.startsWith(`${childPath}/`);
2204
+ })
2205
+ )?.name || null;
2206
+ setExpandedMenu(activeMenu);
2207
+ }, [location.pathname, navItems]);
2208
+ const handleMenuToggle = (menuKey) => {
2209
+ if (!menuKey) {
2210
+ setExpandedMenu(null);
2211
+ return;
2212
+ }
2213
+ setExpandedMenu((prev) => prev === menuKey ? null : menuKey);
2214
+ };
2215
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2216
+ react.Flex,
2217
+ {
2218
+ id: id || "sidebar-container",
2219
+ transition: "3s ease",
2220
+ bg: sidebarBg,
2221
+ borderRight: "1px",
2222
+ borderRightColor: sidebarBorderColor,
2223
+ w: { base: "full", md: 60 },
2224
+ pos: "fixed",
2225
+ h: "100vh",
2226
+ direction: "column",
2227
+ overflow: "hidden",
2228
+ children: [
2229
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { alignItems: "center", mx: "8", mt: "3", mb: "2", justifyContent: "space-between", flexShrink: 0, children: [
2230
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { h: "40px", children: brandLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx(BrandLogo_default, { src: brandLogoSrc, className: "h-full w-auto object-contain" }) : null }),
2231
+ onClose ? /* @__PURE__ */ jsxRuntime.jsx(
2232
+ react.IconButton,
2233
+ {
2234
+ display: { base: "flex", md: "none" },
2235
+ onClick: onClose,
2236
+ variant: "outline",
2237
+ "aria-label": "close menu",
2238
+ icon: /* @__PURE__ */ jsxRuntime.jsx(fi.FiX, {})
2239
+ }
2240
+ ) : null
2241
+ ] }),
2242
+ /* @__PURE__ */ jsxRuntime.jsxs(
2243
+ react.Box,
2244
+ {
2245
+ flex: "1",
2246
+ overflowY: "auto",
2247
+ css: {
2248
+ "&::-webkit-scrollbar": { width: "8px" },
2249
+ "&::-webkit-scrollbar-track": { background: "transparent" },
2250
+ "&::-webkit-scrollbar-thumb": { background: "#CBD5E0", borderRadius: "4px" },
2251
+ "&::-webkit-scrollbar-thumb:hover": { background: "#A0AEC0" }
2252
+ },
2253
+ children: [
2254
+ currentOrg?.logoUrl && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { mx: "4", mb: "3", children: /* @__PURE__ */ jsxRuntime.jsx(
2255
+ react.Image,
2256
+ {
2257
+ src: currentOrg.logoUrl,
2258
+ alt: `${currentOrg.name} logo`,
2259
+ maxH: "70px",
2260
+ w: "full",
2261
+ objectFit: "contain",
2262
+ borderRadius: "md"
2263
+ }
2264
+ ) }),
2265
+ /* @__PURE__ */ jsxRuntime.jsx(OrgPill_default, {}),
2266
+ /* @__PURE__ */ jsxRuntime.jsx(ModePill_default, {}),
2267
+ navItems.map((link) => /* @__PURE__ */ jsxRuntime.jsx(
2268
+ NavItem_default,
2269
+ {
2270
+ icon: link.icon,
2271
+ brandIcon: link.brandIcon,
2272
+ href: link.href,
2273
+ subItems: link.children,
2274
+ badge: link.badge,
2275
+ subLabel: link.subLabel,
2276
+ action: link.action,
2277
+ menuKey: String(link.name),
2278
+ isExpanded: expandedMenu === link.name,
2279
+ onToggle: handleMenuToggle,
2280
+ isDisabled: Boolean(link.disabled),
2281
+ children: link.name
2282
+ },
2283
+ link.name
2284
+ ))
2285
+ ]
2286
+ }
2287
+ ),
2288
+ footer && /* @__PURE__ */ jsxRuntime.jsx(
2289
+ react.Box,
2290
+ {
2291
+ px: "1",
2292
+ py: "1",
2293
+ borderTop: "1px",
2294
+ borderColor: "gray.200",
2295
+ flexShrink: 0,
2296
+ bg: sidebarBg,
2297
+ zIndex: 1,
2298
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.VStack, { align: "stretch", spacing: 2, px: "3", py: "2", children: [
2299
+ /* @__PURE__ */ jsxRuntime.jsx(react.HStack, { spacing: 1, fontSize: "xs", color: "gray.600", wrap: "wrap", children: footer.links.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "inline-flex", alignItems: "center", children: [
2300
+ idx > 0 ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { color: "gray.400", mx: 1, children: "|" }) : null,
2301
+ l.external ? /* @__PURE__ */ jsxRuntime.jsx(
2302
+ react.Link,
2303
+ {
2304
+ href: l.href,
2305
+ isExternal: true,
2306
+ _hover: { textDecoration: "underline", opacity: 1 },
2307
+ children: l.label
2308
+ }
2309
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2310
+ react.Link,
2311
+ {
2312
+ as: reactRouterDom.NavLink,
2313
+ to: l.href,
2314
+ _hover: { textDecoration: "underline", opacity: 1 },
2315
+ children: l.label
2316
+ }
2317
+ )
2318
+ ] }, `${l.label}-${idx}`)) }),
2319
+ (footer.version || footer.commit || footer.environmentLabel) && /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 2, fontSize: "xs", color: "gray.500", wrap: "wrap", children: [
2320
+ footer.environmentLabel ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontWeight: "semibold", children: footer.environmentLabel }) : null,
2321
+ footer.version ? /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { children: [
2322
+ "v",
2323
+ footer.version
2324
+ ] }) : null,
2325
+ footer.commit ? /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontFamily: "mono", children: [
2326
+ "#",
2327
+ footer.commit.slice(-7)
2328
+ ] }) : null
2329
+ ] })
2330
+ ] })
2331
+ }
2332
+ )
2333
+ ]
2334
+ }
2335
+ );
2336
+ }
2337
+ function Footer({ buildInfo }) {
2338
+ return /* @__PURE__ */ jsxRuntime.jsx(
2339
+ react.Box,
2340
+ {
2341
+ as: "footer",
2342
+ px: 4,
2343
+ py: 2,
2344
+ borderTop: "1px solid",
2345
+ borderColor: "gray.200",
2346
+ fontSize: "xs",
2347
+ color: "gray.500",
2348
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { children: [
2349
+ "politogy ",
2350
+ buildInfo ? `\xB7 ${buildInfo}` : ""
1328
2351
  ] })
1329
- ] }) })
2352
+ }
2353
+ );
2354
+ }
2355
+ function AppLayout({
2356
+ children,
2357
+ buildInfo,
2358
+ modalsSlot,
2359
+ notificationsSlot,
2360
+ overlaySlot
2361
+ }) {
2362
+ const [mobileOpen, setMobileOpen] = react$1.useState(false);
2363
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { direction: "column", minH: "100vh", children: [
2364
+ /* @__PURE__ */ jsxRuntime.jsx(
2365
+ Sidebar,
2366
+ {
2367
+ onClose: mobileOpen ? () => setMobileOpen(false) : void 0
2368
+ }
2369
+ ),
2370
+ /* @__PURE__ */ jsxRuntime.jsx(Header, { onOpen: () => setMobileOpen(true) }),
2371
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "main", flex: "1", ml: { base: 0, md: 60 }, position: "relative", overflow: "auto", children: [
2372
+ children,
2373
+ notificationsSlot
2374
+ ] }),
2375
+ buildInfo ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { buildInfo }) : null,
2376
+ modalsSlot,
2377
+ overlaySlot
1330
2378
  ] });
1331
2379
  }
1332
2380
  var SUPPORT_REQUEST_SUCCESS_MESSAGE = "Your support request was sent to Politogy leadership.";
@@ -1613,174 +2661,58 @@ function LifebuoyIcon() {
1613
2661
  }
1614
2662
  );
1615
2663
  }
1616
- function avatarUrlFromUser(user) {
1617
- if (!user) return void 0;
1618
- const meta = user.raw.user_metadata;
1619
- return meta?.avatar_url ?? void 0;
1620
- }
1621
- function UserMenu() {
1622
- const { user, status, signOut } = useShellAuth();
1623
- const { myProfileHref } = useShellChrome();
1624
- const linked = useShellLinkedAccounts();
1625
- const { colorMode, toggleColorMode } = react.useColorMode();
1626
- if (status !== "authenticated" || !user) return null;
1627
- const displayName = user.displayName ?? user.email ?? "User";
1628
- const avatarUrl = avatarUrlFromUser(user);
1629
- return /* @__PURE__ */ jsxRuntime.jsxs(react.Menu, { placement: "bottom-end", children: [
1630
- /* @__PURE__ */ jsxRuntime.jsx(
1631
- react.MenuButton,
1632
- {
1633
- "aria-label": "Open account menu",
1634
- as: react.Box,
1635
- cursor: "pointer",
1636
- borderRadius: "full",
1637
- _hover: { opacity: 0.85 },
1638
- children: /* @__PURE__ */ jsxRuntime.jsx(react.Avatar, { size: "sm", name: displayName, src: avatarUrl })
1639
- }
1640
- ),
1641
- /* @__PURE__ */ jsxRuntime.jsx(react.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(react.MenuList, { zIndex: 1500, children: [
1642
- /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { px: 3, py: 2, children: [
1643
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "600", noOfLines: 1, children: displayName }),
1644
- user.email && /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "gray.500", noOfLines: 1, children: user.email })
1645
- ] }),
1646
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuDivider, {}),
1647
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { as: "a", href: myProfileHref, children: "My Profile" }),
1648
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { onClick: toggleColorMode, children: colorMode === "light" ? "Switch to dark mode" : "Switch to light mode" }),
1649
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { onClick: () => void signOut(), children: "Sign out" }),
1650
- linked && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1651
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuDivider, {}),
1652
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { px: 3, pt: 1, pb: 1, children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", textTransform: "uppercase", letterSpacing: "0.08em", color: "gray.500", children: "Switch account" }) }),
1653
- linked.linkedAccounts.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { isDisabled: true, children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", color: "gray.500", children: "No linked accounts" }) }),
1654
- linked.linkedAccounts.map((acct) => /* @__PURE__ */ jsxRuntime.jsx(
1655
- react.MenuItem,
1656
- {
1657
- onClick: () => {
1658
- void linked.switchToAccount(acct.id);
1659
- },
1660
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { spacing: 2, align: "center", children: [
1661
- /* @__PURE__ */ jsxRuntime.jsx(
1662
- react.Avatar,
1663
- {
1664
- size: "xs",
1665
- name: acct.displayName ?? acct.email,
1666
- src: acct.avatarUrl ?? void 0
1667
- }
1668
- ),
1669
- /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { direction: "column", minW: 0, children: [
1670
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "600", noOfLines: 1, children: acct.displayName ?? acct.email }),
1671
- acct.displayName && /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "gray.500", noOfLines: 1, children: acct.email })
1672
- ] })
1673
- ] })
1674
- },
1675
- acct.id
1676
- )),
1677
- /* @__PURE__ */ jsxRuntime.jsx(react.MenuItem, { onClick: linked.onAddAccount, children: "Add account" })
1678
- ] })
1679
- ] }) })
1680
- ] });
1681
- }
1682
- function Header({ extrasSlot }) {
1683
- const { devNotesMenu } = useShellChrome();
1684
- return /* @__PURE__ */ jsxRuntime.jsxs(
1685
- react.Flex,
1686
- {
1687
- as: "header",
1688
- align: "center",
1689
- px: 4,
1690
- h: "56px",
1691
- bg: "white",
1692
- borderBottom: "1px solid",
1693
- borderColor: "gray.200",
1694
- gap: 3,
1695
- children: [
1696
- /* @__PURE__ */ jsxRuntime.jsx(react.Heading, { size: "md", color: "brand.500", children: "politogy" }),
1697
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(OrgSelector, {}) }),
1698
- /* @__PURE__ */ jsxRuntime.jsx(react.Spacer, {}),
1699
- extrasSlot && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { children: extrasSlot }),
1700
- /* @__PURE__ */ jsxRuntime.jsx(SupportRequestButton, {}),
1701
- devNotesMenu,
1702
- /* @__PURE__ */ jsxRuntime.jsx(UserMenu, {})
1703
- ]
1704
- }
1705
- );
1706
- }
1707
- function Sidebar({ entries, currentApp, footerSlot }) {
1708
- return /* @__PURE__ */ jsxRuntime.jsxs(
1709
- react.Box,
1710
- {
1711
- as: "nav",
1712
- w: "200px",
1713
- minH: "100%",
1714
- bg: "gray.50",
1715
- borderRight: "1px solid",
1716
- borderColor: "gray.200",
1717
- p: 3,
1718
- display: "flex",
1719
- flexDirection: "column",
1720
- children: [
1721
- /* @__PURE__ */ jsxRuntime.jsx(react.VStack, { align: "stretch", spacing: 1, children: entries.filter((e) => e.visible !== false).map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
1722
- react.Link,
1723
- {
1724
- href: entry.path,
1725
- "data-current": entry.id === currentApp,
1726
- px: 3,
1727
- py: 2,
1728
- borderRadius: "md",
1729
- fontWeight: entry.id === currentApp ? "bold" : "normal",
1730
- bg: entry.id === currentApp ? "brand.50" : "transparent",
1731
- _hover: { bg: "gray.100" },
1732
- children: /* @__PURE__ */ jsxRuntime.jsx(react.Text, { children: entry.label })
1733
- },
1734
- entry.id
1735
- )) }),
1736
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { flex: "1" }),
1737
- footerSlot && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { pt: 3, children: footerSlot })
1738
- ]
1739
- }
1740
- );
1741
- }
1742
- function Footer({ buildInfo }) {
1743
- return /* @__PURE__ */ jsxRuntime.jsx(
1744
- react.Box,
1745
- {
1746
- as: "footer",
1747
- px: 4,
1748
- py: 2,
1749
- borderTop: "1px solid",
1750
- borderColor: "gray.200",
1751
- fontSize: "xs",
1752
- color: "gray.500",
1753
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { children: [
1754
- "politogy ",
1755
- buildInfo ? `\xB7 ${buildInfo}` : ""
1756
- ] })
1757
- }
1758
- );
1759
- }
1760
- function AppLayout({
2664
+ function ShellChrome({
1761
2665
  children,
1762
- buildInfo,
1763
- headerExtrasSlot,
1764
- modalsSlot,
1765
- notificationsSlot,
1766
- sidebarFooterSlot,
1767
- overlaySlot
2666
+ organization,
2667
+ linkedAccounts,
2668
+ support,
2669
+ devNotesMenu,
2670
+ myProfileHref,
2671
+ mode,
2672
+ navItems,
2673
+ navigationPreference,
2674
+ role,
2675
+ footer,
2676
+ brandLogoSrc,
2677
+ headerIconsSlot,
2678
+ organizationSettingsHref,
2679
+ showContinueOnboarding,
2680
+ onContinueOnboarding,
2681
+ pageTitle,
2682
+ breadcrumbs,
2683
+ headerActions
1768
2684
  }) {
1769
- const currentApp = useCurrentApp();
1770
- const entries = useAppRegistry();
1771
- return /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { direction: "column", minH: "100vh", children: [
1772
- /* @__PURE__ */ jsxRuntime.jsx(Header, { extrasSlot: headerExtrasSlot }),
1773
- /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { flex: "1", minH: 0, children: [
1774
- /* @__PURE__ */ jsxRuntime.jsx(Sidebar, { entries, currentApp, footerSlot: sidebarFooterSlot }),
1775
- /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "main", flex: "1", overflow: "auto", position: "relative", children: [
1776
- children,
1777
- notificationsSlot
1778
- ] })
1779
- ] }),
1780
- /* @__PURE__ */ jsxRuntime.jsx(Footer, { buildInfo }),
1781
- modalsSlot,
1782
- overlaySlot
1783
- ] });
2685
+ const chrome = react$1.useMemo(
2686
+ () => ({
2687
+ devNotesMenu: devNotesMenu ?? null,
2688
+ myProfileHref: myProfileHref ?? "/my-profile",
2689
+ brandLogoSrc,
2690
+ headerIconsSlot,
2691
+ organizationSettingsHref,
2692
+ showContinueOnboarding,
2693
+ onContinueOnboarding,
2694
+ pageTitle,
2695
+ breadcrumbs,
2696
+ headerActions
2697
+ }),
2698
+ [
2699
+ devNotesMenu,
2700
+ myProfileHref,
2701
+ brandLogoSrc,
2702
+ headerIconsSlot,
2703
+ organizationSettingsHref,
2704
+ showContinueOnboarding,
2705
+ onContinueOnboarding,
2706
+ pageTitle,
2707
+ breadcrumbs,
2708
+ headerActions
2709
+ ]
2710
+ );
2711
+ const navItemsValue = react$1.useMemo(
2712
+ () => navItems ? { items: navItems } : null,
2713
+ [navItems]
2714
+ );
2715
+ return /* @__PURE__ */ jsxRuntime.jsx(ShellOrgContext.Provider, { value: organization ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellLinkedAccountsContext.Provider, { value: linkedAccounts ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellSupportProviderContext.Provider, { value: support ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellModeContext.Provider, { value: mode ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellNavItemsContext.Provider, { value: navItemsValue, children: /* @__PURE__ */ jsxRuntime.jsx(ShellNavigationPreferenceContext.Provider, { value: navigationPreference ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellRoleContext.Provider, { value: role ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellFooterContext.Provider, { value: footer ?? null, children: /* @__PURE__ */ jsxRuntime.jsx(ShellChromeContext.Provider, { value: chrome, children }) }) }) }) }) }) }) }) });
1784
2716
  }
1785
2717
 
1786
2718
  // src/sw/registerShellPrecache.ts
@@ -1814,28 +2746,54 @@ function buildSpeculationRules(currentApp, registry) {
1814
2746
  }
1815
2747
 
1816
2748
  exports.AppLayout = AppLayout;
2749
+ exports.BrandIcon = BrandIcon;
2750
+ exports.BrandLogo = BrandLogo;
1817
2751
  exports.BreadcrumbBar = BreadcrumbBar;
1818
2752
  exports.Card = Card;
1819
2753
  exports.Footer = Footer;
1820
2754
  exports.GlobalUiIdProvider = GlobalUiIdProvider;
1821
2755
  exports.Header = Header;
1822
2756
  exports.HeaderTabBar = HeaderTabBar;
1823
- exports.OrgSelector = OrgSelector;
2757
+ exports.ModePill = ModePill;
2758
+ exports.NavItem = NavItem;
2759
+ exports.OrgPill = OrgPill;
2760
+ exports.OrgSelector = OrgPill;
1824
2761
  exports.PageContainer = PageContainer;
1825
2762
  exports.PageHeader = PageHeader;
2763
+ exports.ShellChrome = ShellChrome;
2764
+ exports.ShellChromeContext = ShellChromeContext;
2765
+ exports.ShellFooterContext = ShellFooterContext;
2766
+ exports.ShellLinkedAccountsContext = ShellLinkedAccountsContext;
2767
+ exports.ShellModeContext = ShellModeContext;
2768
+ exports.ShellNavItemsContext = ShellNavItemsContext;
2769
+ exports.ShellNavigationPreferenceContext = ShellNavigationPreferenceContext;
2770
+ exports.ShellOrgContext = ShellOrgContext;
1826
2771
  exports.ShellProvider = ShellProvider;
2772
+ exports.ShellRoleContext = ShellRoleContext;
2773
+ exports.ShellSupportProviderContext = ShellSupportProviderContext;
1827
2774
  exports.Sidebar = Sidebar;
1828
2775
  exports.SupportRequestButton = SupportRequestButton;
1829
2776
  exports.UserMenu = UserMenu;
1830
2777
  exports.buildSpeculationRules = buildSpeculationRules;
2778
+ exports.getOrganizationBadgeLetters = getOrganizationBadgeLetters;
2779
+ exports.getOrganizationBrandColor = getOrganizationBrandColor;
2780
+ exports.getUserDisplayName = getUserDisplayName;
2781
+ exports.hexToRgba = hexToRgba;
2782
+ exports.lightenHexColor = lightenHexColor;
2783
+ exports.normalizeHexColor = normalizeHexColor;
1831
2784
  exports.politogyTheme = politogyTheme;
1832
2785
  exports.registerShellPrecache = registerShellPrecache;
1833
2786
  exports.useAppRegistry = useAppRegistry;
1834
2787
  exports.useCurrentApp = useCurrentApp;
1835
2788
  exports.useShellAuth = useShellAuth;
1836
2789
  exports.useShellChrome = useShellChrome;
2790
+ exports.useShellFooter = useShellFooter;
1837
2791
  exports.useShellLinkedAccounts = useShellLinkedAccounts;
2792
+ exports.useShellMode = useShellMode;
2793
+ exports.useShellNavItems = useShellNavItems;
2794
+ exports.useShellNavigationPreference = useShellNavigationPreference;
1838
2795
  exports.useShellOrganization = useShellOrganization;
2796
+ exports.useShellRole = useShellRole;
1839
2797
  exports.useShellSupport = useShellSupport;
1840
2798
  //# sourceMappingURL=index.cjs.map
1841
2799
  //# sourceMappingURL=index.cjs.map