@orangecheck/design 0.15.0 → 0.17.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.
@@ -1,13 +1,14 @@
1
1
  import * as Popover from '@radix-ui/react-popover';
2
- import { HelpCircle, Boxes, ChevronDown, Check, CornerDownLeft, Plus, Loader2, Copy } from 'lucide-react';
2
+ import { HelpCircle, Boxes, ChevronDown, Check, CornerDownLeft, Plus, Loader2, Copy, X, Menu, Sun, Moon, Monitor } from 'lucide-react';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import { jsxs, jsx, Fragment as Fragment$1 } from 'react/jsx-runtime';
6
6
  import Link6 from 'next/link';
7
7
  import * as React from 'react';
8
- import { Fragment, useState, useRef, useEffect, useId } from 'react';
8
+ import { createContext, Fragment, useState, useRef, useEffect, useId, useContext } from 'react';
9
9
  import { useRouter } from 'next/router';
10
10
  import { useOcSession, fetchOcLinkedIdentities } from '@orangecheck/auth-client';
11
+ import { useTheme } from 'next-themes';
11
12
 
12
13
  // src/composites/help-hint.tsx
13
14
  function cn(...inputs) {
@@ -1000,6 +1001,74 @@ function OcLogoDropdown({
1000
1001
  }
1001
1002
  );
1002
1003
  }
1004
+ var OcSkinContext = createContext(null);
1005
+ function useOcSkin() {
1006
+ const ctx = useContext(OcSkinContext);
1007
+ if (!ctx) {
1008
+ throw new Error("useOcSkin must be used within <OcThemeProvider>");
1009
+ }
1010
+ return ctx;
1011
+ }
1012
+ var MODES = [
1013
+ { id: "light", label: "light", Icon: Sun },
1014
+ { id: "dark", label: "dark", Icon: Moon },
1015
+ { id: "system", label: "system", Icon: Monitor }
1016
+ ];
1017
+ function AppearanceControls({ className }) {
1018
+ const { skin, setSkin, themes } = useOcSkin();
1019
+ const { theme, setTheme } = useTheme();
1020
+ const [mounted, setMounted] = useState(false);
1021
+ useEffect(() => setMounted(true), []);
1022
+ const activeMode = mounted ? theme ?? "system" : null;
1023
+ return /* @__PURE__ */ jsxs("div", { className, children: [
1024
+ /* @__PURE__ */ jsx("div", { className: "label-mono text-muted-foreground px-3 pt-3 pb-2", children: "mode" }),
1025
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 px-2 pb-2", children: MODES.map(({ id, label, Icon }) => {
1026
+ const active = activeMode === id;
1027
+ return /* @__PURE__ */ jsxs(
1028
+ "button",
1029
+ {
1030
+ type: "button",
1031
+ role: "menuitemradio",
1032
+ "aria-checked": active,
1033
+ onClick: () => setTheme(id),
1034
+ className: cn(
1035
+ "flex flex-col items-center gap-1 rounded-md border py-2 text-[11px] transition-colors",
1036
+ active ? "border-primary text-foreground bg-accent" : "border-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"
1037
+ ),
1038
+ children: [
1039
+ /* @__PURE__ */ jsx(Icon, { className: "size-4", "aria-hidden": true }),
1040
+ label
1041
+ ]
1042
+ },
1043
+ id
1044
+ );
1045
+ }) }),
1046
+ /* @__PURE__ */ jsx("div", { className: "label-mono text-muted-foreground border-t px-3 pt-3 pb-1", children: "theme" }),
1047
+ /* @__PURE__ */ jsx("ul", { className: "pb-1", children: themes.map((t) => {
1048
+ const active = t.id === skin;
1049
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
1050
+ "button",
1051
+ {
1052
+ type: "button",
1053
+ role: "menuitemradio",
1054
+ "aria-checked": active,
1055
+ onClick: () => setSkin(t.id),
1056
+ className: cn(
1057
+ "hover:bg-accent hover:text-accent-foreground flex w-full items-start gap-2 px-3 py-2 text-left transition-colors",
1058
+ active && "text-foreground"
1059
+ ),
1060
+ children: [
1061
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 size-4 shrink-0", children: active && /* @__PURE__ */ jsx(Check, { className: "text-primary size-4", "aria-hidden": true }) }),
1062
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
1063
+ /* @__PURE__ */ jsx("span", { className: "block text-sm font-medium", children: t.label }),
1064
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground block text-xs leading-snug", children: t.description })
1065
+ ] })
1066
+ ]
1067
+ }
1068
+ ) }, t.id);
1069
+ }) })
1070
+ ] });
1071
+ }
1003
1072
  function obscureIdentity(value) {
1004
1073
  if (value.length <= 12) {
1005
1074
  return `${value.slice(0, 4)}\u2026${value.slice(-3)}`;
@@ -1250,6 +1319,92 @@ function OcAccountMenu(props) {
1250
1319
  }
1251
1320
  );
1252
1321
  }
1322
+ function MobileMenu({
1323
+ primary,
1324
+ secondary
1325
+ }) {
1326
+ const [open, setOpen] = useState(false);
1327
+ const ref = useRef(null);
1328
+ useEffect(() => {
1329
+ if (!open) return;
1330
+ const onClick = (e) => {
1331
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
1332
+ };
1333
+ const onKey = (e) => {
1334
+ if (e.key === "Escape") setOpen(false);
1335
+ };
1336
+ document.addEventListener("mousedown", onClick);
1337
+ document.addEventListener("keydown", onKey);
1338
+ return () => {
1339
+ document.removeEventListener("mousedown", onClick);
1340
+ document.removeEventListener("keydown", onKey);
1341
+ };
1342
+ }, [open]);
1343
+ const links = [...primary ?? [], ...secondary ?? []];
1344
+ const rowCls = "font-display flex items-center gap-2 px-3 py-2 text-[12px] font-semibold tracking-wider uppercase text-muted-foreground hover:text-foreground hover:bg-accent transition-colors";
1345
+ return /* @__PURE__ */ jsxs("div", { ref, className: "relative md:hidden", "data-oc-account-mobile-menu": "", children: [
1346
+ /* @__PURE__ */ jsx(
1347
+ "button",
1348
+ {
1349
+ type: "button",
1350
+ onClick: () => setOpen((v) => !v),
1351
+ "aria-haspopup": "menu",
1352
+ "aria-expanded": open,
1353
+ "aria-label": "menu",
1354
+ className: "border-input bg-background hover:bg-accent text-muted-foreground inline-flex size-8 items-center justify-center rounded-md border transition-colors",
1355
+ "data-oc-account-mobile-toggle": "",
1356
+ children: open ? /* @__PURE__ */ jsx(X, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(Menu, { className: "size-4", "aria-hidden": true })
1357
+ }
1358
+ ),
1359
+ open && /* @__PURE__ */ jsxs(
1360
+ "div",
1361
+ {
1362
+ role: "menu",
1363
+ "aria-label": "menu",
1364
+ className: "border-border bg-popover text-popover-foreground absolute top-[calc(100%+6px)] right-0 z-50 w-[min(16rem,calc(100vw-1rem))] overflow-hidden border shadow-xl",
1365
+ "data-oc-account-mobile-popover": "",
1366
+ children: [
1367
+ links.length > 0 && /* @__PURE__ */ jsxs("div", { className: "border-b p-1", children: [
1368
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 navigate" }),
1369
+ links.map(
1370
+ (l) => l.external ? /* @__PURE__ */ jsxs(
1371
+ "a",
1372
+ {
1373
+ href: l.href,
1374
+ target: "_blank",
1375
+ rel: "noreferrer",
1376
+ role: "menuitem",
1377
+ onClick: () => setOpen(false),
1378
+ className: rowCls,
1379
+ children: [
1380
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1381
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: l.label }),
1382
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 text-[10px]", "aria-hidden": true, children: "\u2197" })
1383
+ ]
1384
+ },
1385
+ l.href
1386
+ ) : /* @__PURE__ */ jsxs(
1387
+ Link6,
1388
+ {
1389
+ href: l.href,
1390
+ role: "menuitem",
1391
+ onClick: () => setOpen(false),
1392
+ className: rowCls,
1393
+ children: [
1394
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1395
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: l.label })
1396
+ ]
1397
+ },
1398
+ l.href
1399
+ )
1400
+ )
1401
+ ] }),
1402
+ /* @__PURE__ */ jsx(AppearanceControls, {})
1403
+ ]
1404
+ }
1405
+ )
1406
+ ] });
1407
+ }
1253
1408
  function OcAccountMenuView({
1254
1409
  current,
1255
1410
  signInUrl = "/signin",
@@ -1322,220 +1477,220 @@ function OcAccountMenuView({
1322
1477
  children: signInLabel
1323
1478
  }
1324
1479
  );
1480
+ const hasNav = (primaryNavLinks?.length ?? 0) + (secondaryNavLinks?.length ?? 0) > 0;
1481
+ const wrap = (identity) => /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-1", className), "data-oc-account-menu": "", children: [
1482
+ hasNav ? /* @__PURE__ */ jsx(MobileMenu, { primary: primaryNavLinks, secondary: secondaryNavLinks }) : null,
1483
+ identity
1484
+ ] });
1325
1485
  if (!hydrated || status === "loading") {
1326
- return signInTrigger;
1486
+ return wrap(signInTrigger);
1327
1487
  }
1328
1488
  if (status !== "authenticated" || !account) {
1329
- return signInTrigger;
1489
+ return wrap(signInTrigger);
1330
1490
  }
1331
1491
  const displayName = account.displayName ?? null;
1332
1492
  const label = displayName ?? obscureIdentity(account.displayIdentity.value);
1333
- return /* @__PURE__ */ jsxs(
1334
- "div",
1335
- {
1336
- ref: wrapRef,
1337
- className: "relative inline-block " + (className ?? ""),
1338
- "data-oc-account-menu": "",
1339
- children: [
1340
- /* @__PURE__ */ jsxs(
1341
- "button",
1342
- {
1343
- type: "button",
1344
- onClick: () => setOpen((v) => !v),
1345
- "aria-haspopup": "menu",
1346
- "aria-expanded": open,
1347
- "aria-label": `Signed in as ${account.didOc}. Open account menu.`,
1348
- className: triggerClassName ?? "border-primary/40 bg-card hover:bg-accent inline-flex h-8 items-center gap-1.5 rounded-md border px-3 font-mono text-[11px] tracking-wide transition-colors",
1349
- "data-oc-account-menu-trigger": "",
1350
- children: [
1351
- /* @__PURE__ */ jsx("span", { className: "bg-primary inline-block size-1.5 rounded-full", "aria-hidden": true }),
1352
- /* @__PURE__ */ jsx("span", { className: "text-foreground", children: label }),
1353
- /* @__PURE__ */ jsx(
1354
- "svg",
1355
- {
1356
- width: "9",
1357
- height: "9",
1358
- viewBox: "0 0 10 10",
1359
- "aria-hidden": true,
1360
- className: "opacity-60 transition-transform " + (open ? "rotate-180" : "rotate-0"),
1361
- children: /* @__PURE__ */ jsx(
1362
- "path",
1363
- {
1364
- d: "M2 4 L5 7 L8 4",
1365
- stroke: "currentColor",
1366
- strokeWidth: "1.5",
1367
- fill: "none",
1368
- strokeLinecap: "round"
1369
- }
1370
- )
1371
- }
1372
- )
1373
- ]
1374
- }
1375
- ),
1376
- open && /* @__PURE__ */ jsxs(
1377
- "div",
1378
- {
1379
- role: "menu",
1380
- "aria-label": "Account menu",
1381
- className: popoverClassName ?? "border-border bg-popover text-popover-foreground absolute top-[calc(100%+6px)] right-0 z-50 w-[min(20rem,calc(100vw-1rem))] border shadow-xl",
1382
- "data-oc-account-menu-popover": "",
1383
- children: [
1384
- /* @__PURE__ */ jsxs("div", { className: "border-border border-b p-3", children: [
1385
- /* @__PURE__ */ jsxs("div", { className: "text-primary mb-1 font-mono text-[10px] tracking-widest uppercase", children: [
1386
- "\xA7 signed in \xB7 ",
1387
- hostname,
1388
- tabPinned ? /* @__PURE__ */ jsxs(
1493
+ return wrap(
1494
+ /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative inline-block", children: [
1495
+ /* @__PURE__ */ jsxs(
1496
+ "button",
1497
+ {
1498
+ type: "button",
1499
+ onClick: () => setOpen((v) => !v),
1500
+ "aria-haspopup": "menu",
1501
+ "aria-expanded": open,
1502
+ "aria-label": `Signed in as ${account.didOc}. Open account menu.`,
1503
+ className: triggerClassName ?? "border-primary/40 bg-card hover:bg-accent inline-flex h-8 items-center gap-1.5 rounded-md border px-2 font-mono text-[11px] tracking-wide transition-colors sm:px-3",
1504
+ "data-oc-account-menu-trigger": "",
1505
+ children: [
1506
+ /* @__PURE__ */ jsx("span", { className: "bg-primary inline-block size-1.5 shrink-0 rounded-full", "aria-hidden": true }),
1507
+ /* @__PURE__ */ jsx("span", { className: "text-foreground hidden max-w-[16ch] truncate sm:inline", children: label }),
1508
+ /* @__PURE__ */ jsx(
1509
+ "svg",
1510
+ {
1511
+ width: "9",
1512
+ height: "9",
1513
+ viewBox: "0 0 10 10",
1514
+ "aria-hidden": true,
1515
+ className: "opacity-60 transition-transform " + (open ? "rotate-180" : "rotate-0"),
1516
+ children: /* @__PURE__ */ jsx(
1517
+ "path",
1518
+ {
1519
+ d: "M2 4 L5 7 L8 4",
1520
+ stroke: "currentColor",
1521
+ strokeWidth: "1.5",
1522
+ fill: "none",
1523
+ strokeLinecap: "round"
1524
+ }
1525
+ )
1526
+ }
1527
+ )
1528
+ ]
1529
+ }
1530
+ ),
1531
+ open && /* @__PURE__ */ jsxs(
1532
+ "div",
1533
+ {
1534
+ role: "menu",
1535
+ "aria-label": "Account menu",
1536
+ className: popoverClassName ?? "border-border bg-popover text-popover-foreground absolute top-[calc(100%+6px)] right-0 z-50 w-[min(20rem,calc(100vw-1rem))] border shadow-xl",
1537
+ "data-oc-account-menu-popover": "",
1538
+ children: [
1539
+ /* @__PURE__ */ jsxs("div", { className: "border-border border-b p-3", children: [
1540
+ /* @__PURE__ */ jsxs("div", { className: "text-primary mb-1 font-mono text-[10px] tracking-widest uppercase", children: [
1541
+ "\xA7 signed in \xB7 ",
1542
+ hostname,
1543
+ tabPinned ? /* @__PURE__ */ jsxs(
1544
+ "span",
1545
+ {
1546
+ className: "text-muted-foreground/70 normal-case",
1547
+ "data-oc-account-menu-tab-pin": "",
1548
+ title: "This tab keeps this account even if you switch accounts in another tab",
1549
+ children: [
1550
+ " ",
1551
+ "\xB7 this tab"
1552
+ ]
1553
+ }
1554
+ ) : null
1555
+ ] }),
1556
+ /* @__PURE__ */ jsx(CopyableDid, { did: account.didOc }),
1557
+ displayName ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/80 mt-1 font-mono text-[10px] tracking-wide", children: displayName }) : null
1558
+ ] }),
1559
+ /* @__PURE__ */ jsx(
1560
+ IdentityPromoteSection,
1561
+ {
1562
+ didOc: account.didOc,
1563
+ nostrNpub: account.nostrNpub ?? null,
1564
+ current: account.displayIdentity,
1565
+ open,
1566
+ setDisplayIdentity
1567
+ }
1568
+ ),
1569
+ /* @__PURE__ */ jsx(
1570
+ AccountsSection,
1571
+ {
1572
+ roster: roster ?? [],
1573
+ switchAccount,
1574
+ addAccountUrl,
1575
+ signOut,
1576
+ onActionStart: () => setOpen(false)
1577
+ }
1578
+ ),
1579
+ primaryNavLinks && primaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1580
+ PopoverSection,
1581
+ {
1582
+ label: "navigate",
1583
+ items: primaryNavLinks,
1584
+ onItemClick: () => setOpen(false),
1585
+ className: "hidden md:block"
1586
+ }
1587
+ ) : null,
1588
+ /* @__PURE__ */ jsxs("div", { className: "p-1", "data-oc-account-menu-section": "account", children: [
1589
+ menuItems?.map((item) => {
1590
+ const onClick = () => setOpen(false);
1591
+ const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
1592
+ const inner = /* @__PURE__ */ jsxs(Fragment$1, { children: [
1593
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1594
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1595
+ item.external ? /* @__PURE__ */ jsx(
1389
1596
  "span",
1390
1597
  {
1391
- className: "text-muted-foreground/70 normal-case",
1392
- "data-oc-account-menu-tab-pin": "",
1393
- title: "This tab keeps this account even if you switch accounts in another tab",
1394
- children: [
1395
- " ",
1396
- "\xB7 this tab"
1397
- ]
1598
+ className: "text-muted-foreground/70 text-[10px]",
1599
+ "aria-hidden": true,
1600
+ children: "\u2197"
1398
1601
  }
1399
1602
  ) : null
1400
- ] }),
1401
- /* @__PURE__ */ jsx(CopyableDid, { did: account.didOc }),
1402
- displayName ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/80 mt-1 font-mono text-[10px] tracking-wide", children: displayName }) : null
1403
- ] }),
1404
- /* @__PURE__ */ jsx(
1405
- IdentityPromoteSection,
1406
- {
1407
- didOc: account.didOc,
1408
- nostrNpub: account.nostrNpub ?? null,
1409
- current: account.displayIdentity,
1410
- open,
1411
- setDisplayIdentity
1412
- }
1413
- ),
1414
- /* @__PURE__ */ jsx(
1415
- AccountsSection,
1416
- {
1417
- roster: roster ?? [],
1418
- switchAccount,
1419
- addAccountUrl,
1420
- signOut,
1421
- onActionStart: () => setOpen(false)
1422
- }
1423
- ),
1424
- primaryNavLinks && primaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1425
- PopoverSection,
1426
- {
1427
- label: "navigate",
1428
- items: primaryNavLinks,
1429
- onItemClick: () => setOpen(false)
1430
- }
1431
- ) : null,
1432
- /* @__PURE__ */ jsxs("div", { className: "p-1", "data-oc-account-menu-section": "account", children: [
1433
- primaryNavLinks && primaryNavLinks.length > 0 ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/60 px-3 pb-1 pt-2 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 account" }) : null,
1434
- menuItems?.map((item) => {
1435
- const onClick = () => setOpen(false);
1436
- const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
1437
- const inner = /* @__PURE__ */ jsxs(Fragment$1, { children: [
1438
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1439
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1440
- item.external ? /* @__PURE__ */ jsx(
1441
- "span",
1442
- {
1443
- className: "text-muted-foreground/70 text-[10px]",
1444
- "aria-hidden": true,
1445
- children: "\u2197"
1446
- }
1447
- ) : null
1448
- ] });
1449
- return item.external ? /* @__PURE__ */ jsx(
1450
- "a",
1451
- {
1452
- href: item.href,
1453
- target: "_blank",
1454
- rel: "noreferrer",
1455
- onClick,
1456
- role: "menuitem",
1457
- className: cls,
1458
- "data-oc-account-menu-item": "",
1459
- children: inner
1460
- },
1461
- item.href
1462
- ) : /* @__PURE__ */ jsx(
1463
- Link6,
1464
- {
1465
- href: item.href,
1466
- onClick,
1467
- role: "menuitem",
1468
- className: cls,
1469
- "data-oc-account-menu-item": "",
1470
- children: inner
1471
- },
1472
- item.href
1473
- );
1474
- }),
1475
- familyDashboardEnabled ? /* @__PURE__ */ jsxs(
1603
+ ] });
1604
+ return item.external ? /* @__PURE__ */ jsx(
1476
1605
  "a",
1477
1606
  {
1478
- href: "https://ochk.io/dashboard",
1607
+ href: item.href,
1479
1608
  target: "_blank",
1480
1609
  rel: "noreferrer",
1481
- onClick: () => setOpen(false),
1610
+ onClick,
1482
1611
  role: "menuitem",
1483
- className: "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors",
1612
+ className: cls,
1484
1613
  "data-oc-account-menu-item": "",
1485
- "data-oc-account-menu-family-dashboard": "",
1486
- children: [
1487
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1488
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: "family dashboard" }),
1489
- /* @__PURE__ */ jsx(
1490
- "span",
1491
- {
1492
- className: "text-muted-foreground/70 text-[10px]",
1493
- "aria-hidden": true,
1494
- children: "\u2197"
1495
- }
1496
- )
1497
- ]
1498
- }
1499
- ) : null,
1500
- /* @__PURE__ */ jsxs(
1501
- "button",
1614
+ children: inner
1615
+ },
1616
+ item.href
1617
+ ) : /* @__PURE__ */ jsx(
1618
+ Link6,
1502
1619
  {
1503
- type: "button",
1620
+ href: item.href,
1621
+ onClick,
1504
1622
  role: "menuitem",
1505
- onClick: () => {
1506
- setOpen(false);
1507
- void (async () => {
1508
- await signOut();
1509
- if (typeof window !== "undefined") {
1510
- window.location.assign(signOutRedirect);
1511
- }
1512
- })();
1513
- },
1514
- className: "hover:bg-accent flex w-full items-center gap-2 px-3 py-2 text-left font-mono text-[11px] tracking-wide transition-colors",
1623
+ className: cls,
1515
1624
  "data-oc-account-menu-item": "",
1516
- "data-oc-account-menu-signout": "",
1517
- children: [
1518
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1519
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: "sign out" })
1520
- ]
1521
- }
1522
- )
1523
- ] }),
1524
- secondaryNavLinks && secondaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1525
- PopoverSection,
1625
+ children: inner
1626
+ },
1627
+ item.href
1628
+ );
1629
+ }),
1630
+ familyDashboardEnabled ? /* @__PURE__ */ jsxs(
1631
+ "a",
1526
1632
  {
1527
- label: "more",
1528
- items: secondaryNavLinks,
1529
- onItemClick: () => setOpen(false),
1530
- bordered: true
1633
+ href: "https://ochk.io/dashboard",
1634
+ target: "_blank",
1635
+ rel: "noreferrer",
1636
+ onClick: () => setOpen(false),
1637
+ role: "menuitem",
1638
+ className: "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors",
1639
+ "data-oc-account-menu-item": "",
1640
+ "data-oc-account-menu-family-dashboard": "",
1641
+ children: [
1642
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1643
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "family dashboard" }),
1644
+ /* @__PURE__ */ jsx(
1645
+ "span",
1646
+ {
1647
+ className: "text-muted-foreground/70 text-[10px]",
1648
+ "aria-hidden": true,
1649
+ children: "\u2197"
1650
+ }
1651
+ )
1652
+ ]
1531
1653
  }
1532
1654
  ) : null,
1533
- build ? /* @__PURE__ */ jsx(BuildFooter, { hostname, build, state: siteState }) : null
1534
- ]
1535
- }
1536
- )
1537
- ]
1538
- }
1655
+ /* @__PURE__ */ jsxs(
1656
+ "button",
1657
+ {
1658
+ type: "button",
1659
+ role: "menuitem",
1660
+ onClick: () => {
1661
+ setOpen(false);
1662
+ void (async () => {
1663
+ await signOut();
1664
+ if (typeof window !== "undefined") {
1665
+ window.location.assign(signOutRedirect);
1666
+ }
1667
+ })();
1668
+ },
1669
+ className: "hover:bg-accent flex w-full items-center gap-2 px-3 py-2 text-left font-mono text-[11px] tracking-wide transition-colors",
1670
+ "data-oc-account-menu-item": "",
1671
+ "data-oc-account-menu-signout": "",
1672
+ children: [
1673
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1674
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "sign out" })
1675
+ ]
1676
+ }
1677
+ )
1678
+ ] }),
1679
+ secondaryNavLinks && secondaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1680
+ PopoverSection,
1681
+ {
1682
+ label: "more",
1683
+ items: secondaryNavLinks,
1684
+ onItemClick: () => setOpen(false),
1685
+ bordered: true,
1686
+ className: "hidden md:block"
1687
+ }
1688
+ ) : null,
1689
+ build ? /* @__PURE__ */ jsx(BuildFooter, { hostname, build, state: siteState }) : null
1690
+ ]
1691
+ }
1692
+ )
1693
+ ] })
1539
1694
  );
1540
1695
  }
1541
1696
  function AccountsSection({
@@ -1648,33 +1803,22 @@ function PopoverSection({
1648
1803
  label,
1649
1804
  items,
1650
1805
  onItemClick,
1651
- bordered
1806
+ bordered,
1807
+ className
1652
1808
  }) {
1653
1809
  const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
1654
1810
  return /* @__PURE__ */ jsxs(
1655
1811
  "div",
1656
1812
  {
1657
- className: "p-1 " + (bordered ? "border-border border-t" : ""),
1813
+ className: cn("p-1", bordered && "border-border border-t", className),
1658
1814
  "data-oc-account-menu-section": label,
1659
1815
  children: [
1660
1816
  /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: [
1661
1817
  "\xA7 ",
1662
1818
  label
1663
1819
  ] }),
1664
- items.map((item) => {
1665
- const inner = /* @__PURE__ */ jsxs(Fragment$1, { children: [
1666
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1667
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1668
- item.external ? /* @__PURE__ */ jsx(
1669
- "span",
1670
- {
1671
- className: "text-muted-foreground/70 text-[10px]",
1672
- "aria-hidden": true,
1673
- children: "\u2197"
1674
- }
1675
- ) : null
1676
- ] });
1677
- return item.external ? /* @__PURE__ */ jsx(
1820
+ items.map(
1821
+ (item) => item.external ? /* @__PURE__ */ jsxs(
1678
1822
  "a",
1679
1823
  {
1680
1824
  href: item.href,
@@ -1684,10 +1828,14 @@ function PopoverSection({
1684
1828
  role: "menuitem",
1685
1829
  className: cls,
1686
1830
  "data-oc-account-menu-item": "",
1687
- children: inner
1831
+ children: [
1832
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1833
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1834
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 text-[10px]", "aria-hidden": true, children: "\u2197" })
1835
+ ]
1688
1836
  },
1689
1837
  item.href
1690
- ) : /* @__PURE__ */ jsx(
1838
+ ) : /* @__PURE__ */ jsxs(
1691
1839
  Link6,
1692
1840
  {
1693
1841
  href: item.href,
@@ -1695,11 +1843,14 @@ function PopoverSection({
1695
1843
  role: "menuitem",
1696
1844
  className: cls,
1697
1845
  "data-oc-account-menu-item": "",
1698
- children: inner
1846
+ children: [
1847
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1848
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label })
1849
+ ]
1699
1850
  },
1700
1851
  item.href
1701
- );
1702
- })
1852
+ )
1853
+ )
1703
1854
  ]
1704
1855
  }
1705
1856
  );
@@ -1760,11 +1911,11 @@ function OcPrimaryNav({
1760
1911
  "nav",
1761
1912
  {
1762
1913
  "aria-label": "primary",
1763
- className: "flex min-w-0 items-center justify-start overflow-x-auto gap-0.5 sm:gap-1 whitespace-nowrap [scrollbar-width:none] [&::-webkit-scrollbar]:hidden " + (className ?? ""),
1914
+ className: "hidden items-center gap-0.5 sm:gap-1 md:flex " + (className ?? ""),
1764
1915
  "data-oc-primary-nav": "",
1765
1916
  children: links.map((link) => {
1766
1917
  const active = isActive(activePath, link);
1767
- const className2 = "font-display shrink-0 px-2 py-1 sm:px-3 text-[11px] sm:text-[12px] font-semibold tracking-wider uppercase transition-colors " + (active ? "text-primary" : "text-muted-foreground hover:text-foreground");
1918
+ const cls = "font-display shrink-0 px-2 py-1 sm:px-3 text-[11px] sm:text-[12px] font-semibold tracking-wider uppercase transition-colors " + (active ? "text-primary" : "text-muted-foreground hover:text-foreground");
1768
1919
  const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [
1769
1920
  link.label,
1770
1921
  link.external ? /* @__PURE__ */ jsx(
@@ -1782,7 +1933,7 @@ function OcPrimaryNav({
1782
1933
  href: link.href,
1783
1934
  target: "_blank",
1784
1935
  rel: "noreferrer",
1785
- className: className2,
1936
+ className: cls,
1786
1937
  "data-oc-primary-nav-item": "",
1787
1938
  children: content
1788
1939
  },
@@ -1792,7 +1943,7 @@ function OcPrimaryNav({
1792
1943
  {
1793
1944
  href: link.href,
1794
1945
  "aria-current": active ? "page" : void 0,
1795
- className: className2,
1946
+ className: cls,
1796
1947
  "data-oc-primary-nav-item": active ? "active" : "sibling",
1797
1948
  children: content
1798
1949
  },
@@ -2095,13 +2246,19 @@ function LayoutSubHeader({
2095
2246
  noHeartbeat = false,
2096
2247
  className
2097
2248
  }) {
2098
- return /* @__PURE__ */ jsx("div", { className: cn("border-b", className), children: /* @__PURE__ */ jsxs("div", { className: "container flex flex-wrap items-center justify-between gap-x-6 gap-y-1 py-2 font-mono text-[11px]", children: [
2099
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2100
- !noHeartbeat && /* @__PURE__ */ jsx("span", { className: "bg-primary inline-block h-1.5 w-1.5 animate-pulse rounded-full" }),
2101
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground tracking-widest uppercase", children: status }),
2102
- /* @__PURE__ */ jsx("span", { className: "text-foreground", children: product })
2249
+ return /* @__PURE__ */ jsx("div", { className: cn("oc-substrip border-b", className), children: /* @__PURE__ */ jsxs("div", { className: "container flex items-center justify-between gap-x-6 py-2 font-mono text-[11px]", children: [
2250
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
2251
+ !noHeartbeat && /* @__PURE__ */ jsx(
2252
+ "span",
2253
+ {
2254
+ className: "bg-primary inline-block size-1.5 shrink-0 animate-pulse rounded-full ring-2 ring-[color-mix(in_oklch,var(--primary),transparent_78%)]",
2255
+ "aria-hidden": true
2256
+ }
2257
+ ),
2258
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground hidden tracking-widest whitespace-nowrap uppercase sm:inline", children: status }),
2259
+ /* @__PURE__ */ jsx("span", { className: "text-foreground truncate", children: product })
2103
2260
  ] }),
2104
- tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex flex-wrap items-center gap-x-4 gap-y-1 tracking-widest uppercase", children: tags.map((tag, i) => /* @__PURE__ */ jsx("span", { className: tag.hideBelow ? HIDE[tag.hideBelow] : void 0, children: tag.label }, i)) })
2261
+ tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/55 hidden shrink-0 items-center gap-x-3 tracking-wider whitespace-nowrap uppercase sm:flex", children: tags.map((tag, i) => /* @__PURE__ */ jsx("span", { className: tag.hideBelow ? HIDE[tag.hideBelow] : void 0, children: tag.label }, i)) })
2105
2262
  ] }) });
2106
2263
  }
2107
2264
  function OcAppBar({