@the-portland-company/shell 0.2.1 → 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,191 +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({
1761
- children,
1762
- buildInfo,
1763
- headerExtrasSlot,
1764
- modalsSlot,
1765
- notificationsSlot,
1766
- sidebarFooterSlot,
1767
- overlaySlot
1768
- }) {
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
- ] });
1784
- }
1785
2664
  function ShellChrome({
1786
2665
  children,
1787
2666
  organization,
1788
2667
  linkedAccounts,
1789
2668
  support,
1790
2669
  devNotesMenu,
1791
- myProfileHref
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
1792
2684
  }) {
1793
2685
  const chrome = react$1.useMemo(
1794
2686
  () => ({
1795
2687
  devNotesMenu: devNotesMenu ?? null,
1796
- myProfileHref: myProfileHref ?? "/my-profile"
2688
+ myProfileHref: myProfileHref ?? "/my-profile",
2689
+ brandLogoSrc,
2690
+ headerIconsSlot,
2691
+ organizationSettingsHref,
2692
+ showContinueOnboarding,
2693
+ onContinueOnboarding,
2694
+ pageTitle,
2695
+ breadcrumbs,
2696
+ headerActions
1797
2697
  }),
1798
- [devNotesMenu, myProfileHref]
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]
1799
2714
  );
1800
- 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(ShellChromeContext.Provider, { value: chrome, children }) }) }) });
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 }) }) }) }) }) }) }) }) });
1801
2716
  }
1802
2717
 
1803
2718
  // src/sw/registerShellPrecache.ts
@@ -1831,33 +2746,54 @@ function buildSpeculationRules(currentApp, registry) {
1831
2746
  }
1832
2747
 
1833
2748
  exports.AppLayout = AppLayout;
2749
+ exports.BrandIcon = BrandIcon;
2750
+ exports.BrandLogo = BrandLogo;
1834
2751
  exports.BreadcrumbBar = BreadcrumbBar;
1835
2752
  exports.Card = Card;
1836
2753
  exports.Footer = Footer;
1837
2754
  exports.GlobalUiIdProvider = GlobalUiIdProvider;
1838
2755
  exports.Header = Header;
1839
2756
  exports.HeaderTabBar = HeaderTabBar;
1840
- exports.OrgSelector = OrgSelector;
2757
+ exports.ModePill = ModePill;
2758
+ exports.NavItem = NavItem;
2759
+ exports.OrgPill = OrgPill;
2760
+ exports.OrgSelector = OrgPill;
1841
2761
  exports.PageContainer = PageContainer;
1842
2762
  exports.PageHeader = PageHeader;
1843
2763
  exports.ShellChrome = ShellChrome;
1844
2764
  exports.ShellChromeContext = ShellChromeContext;
2765
+ exports.ShellFooterContext = ShellFooterContext;
1845
2766
  exports.ShellLinkedAccountsContext = ShellLinkedAccountsContext;
2767
+ exports.ShellModeContext = ShellModeContext;
2768
+ exports.ShellNavItemsContext = ShellNavItemsContext;
2769
+ exports.ShellNavigationPreferenceContext = ShellNavigationPreferenceContext;
1846
2770
  exports.ShellOrgContext = ShellOrgContext;
1847
2771
  exports.ShellProvider = ShellProvider;
2772
+ exports.ShellRoleContext = ShellRoleContext;
1848
2773
  exports.ShellSupportProviderContext = ShellSupportProviderContext;
1849
2774
  exports.Sidebar = Sidebar;
1850
2775
  exports.SupportRequestButton = SupportRequestButton;
1851
2776
  exports.UserMenu = UserMenu;
1852
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;
1853
2784
  exports.politogyTheme = politogyTheme;
1854
2785
  exports.registerShellPrecache = registerShellPrecache;
1855
2786
  exports.useAppRegistry = useAppRegistry;
1856
2787
  exports.useCurrentApp = useCurrentApp;
1857
2788
  exports.useShellAuth = useShellAuth;
1858
2789
  exports.useShellChrome = useShellChrome;
2790
+ exports.useShellFooter = useShellFooter;
1859
2791
  exports.useShellLinkedAccounts = useShellLinkedAccounts;
2792
+ exports.useShellMode = useShellMode;
2793
+ exports.useShellNavItems = useShellNavItems;
2794
+ exports.useShellNavigationPreference = useShellNavigationPreference;
1860
2795
  exports.useShellOrganization = useShellOrganization;
2796
+ exports.useShellRole = useShellRole;
1861
2797
  exports.useShellSupport = useShellSupport;
1862
2798
  //# sourceMappingURL=index.cjs.map
1863
2799
  //# sourceMappingURL=index.cjs.map