@orangecheck/design 0.16.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.
package/dist/chrome.mjs CHANGED
@@ -1,13 +1,14 @@
1
- import { Boxes, ChevronDown, Check, CornerDownLeft, Plus, Loader2, X, Menu, Copy } from 'lucide-react';
1
+ import { Boxes, ChevronDown, Check, CornerDownLeft, Plus, Loader2, Copy, X, Menu, Sun, Moon, Monitor } from 'lucide-react';
2
2
  import Link5 from 'next/link';
3
3
  import * as React from 'react';
4
- import { useState, useRef, useEffect, useId } from 'react';
4
+ import { createContext, useState, useRef, useEffect, useId, useContext } from 'react';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
  import { useRouter } from 'next/router';
7
7
  import * as Popover from '@radix-ui/react-popover';
8
8
  import { clsx } from 'clsx';
9
9
  import { twMerge } from 'tailwind-merge';
10
10
  import { useOcSession, fetchOcLinkedIdentities } from '@orangecheck/auth-client';
11
+ import { useTheme } from 'next-themes';
11
12
 
12
13
  // src/chrome/ecosystem-switcher.tsx
13
14
  var ENTRIES = [
@@ -751,6 +752,74 @@ function OcLogoDropdown({
751
752
  }
752
753
  );
753
754
  }
755
+ var OcSkinContext = createContext(null);
756
+ function useOcSkin() {
757
+ const ctx = useContext(OcSkinContext);
758
+ if (!ctx) {
759
+ throw new Error("useOcSkin must be used within <OcThemeProvider>");
760
+ }
761
+ return ctx;
762
+ }
763
+ var MODES = [
764
+ { id: "light", label: "light", Icon: Sun },
765
+ { id: "dark", label: "dark", Icon: Moon },
766
+ { id: "system", label: "system", Icon: Monitor }
767
+ ];
768
+ function AppearanceControls({ className }) {
769
+ const { skin, setSkin, themes } = useOcSkin();
770
+ const { theme, setTheme } = useTheme();
771
+ const [mounted, setMounted] = useState(false);
772
+ useEffect(() => setMounted(true), []);
773
+ const activeMode = mounted ? theme ?? "system" : null;
774
+ return /* @__PURE__ */ jsxs("div", { className, children: [
775
+ /* @__PURE__ */ jsx("div", { className: "label-mono text-muted-foreground px-3 pt-3 pb-2", children: "mode" }),
776
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 px-2 pb-2", children: MODES.map(({ id, label, Icon }) => {
777
+ const active = activeMode === id;
778
+ return /* @__PURE__ */ jsxs(
779
+ "button",
780
+ {
781
+ type: "button",
782
+ role: "menuitemradio",
783
+ "aria-checked": active,
784
+ onClick: () => setTheme(id),
785
+ className: cn(
786
+ "flex flex-col items-center gap-1 rounded-md border py-2 text-[11px] transition-colors",
787
+ active ? "border-primary text-foreground bg-accent" : "border-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"
788
+ ),
789
+ children: [
790
+ /* @__PURE__ */ jsx(Icon, { className: "size-4", "aria-hidden": true }),
791
+ label
792
+ ]
793
+ },
794
+ id
795
+ );
796
+ }) }),
797
+ /* @__PURE__ */ jsx("div", { className: "label-mono text-muted-foreground border-t px-3 pt-3 pb-1", children: "theme" }),
798
+ /* @__PURE__ */ jsx("ul", { className: "pb-1", children: themes.map((t) => {
799
+ const active = t.id === skin;
800
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
801
+ "button",
802
+ {
803
+ type: "button",
804
+ role: "menuitemradio",
805
+ "aria-checked": active,
806
+ onClick: () => setSkin(t.id),
807
+ className: cn(
808
+ "hover:bg-accent hover:text-accent-foreground flex w-full items-start gap-2 px-3 py-2 text-left transition-colors",
809
+ active && "text-foreground"
810
+ ),
811
+ children: [
812
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 size-4 shrink-0", children: active && /* @__PURE__ */ jsx(Check, { className: "text-primary size-4", "aria-hidden": true }) }),
813
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
814
+ /* @__PURE__ */ jsx("span", { className: "block text-sm font-medium", children: t.label }),
815
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground block text-xs leading-snug", children: t.description })
816
+ ] })
817
+ ]
818
+ }
819
+ ) }, t.id);
820
+ }) })
821
+ ] });
822
+ }
754
823
  function obscureIdentity(value) {
755
824
  if (value.length <= 12) {
756
825
  return `${value.slice(0, 4)}\u2026${value.slice(-3)}`;
@@ -1001,6 +1070,92 @@ function OcAccountMenu(props) {
1001
1070
  }
1002
1071
  );
1003
1072
  }
1073
+ function MobileMenu({
1074
+ primary,
1075
+ secondary
1076
+ }) {
1077
+ const [open, setOpen] = useState(false);
1078
+ const ref = useRef(null);
1079
+ useEffect(() => {
1080
+ if (!open) return;
1081
+ const onClick = (e) => {
1082
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
1083
+ };
1084
+ const onKey = (e) => {
1085
+ if (e.key === "Escape") setOpen(false);
1086
+ };
1087
+ document.addEventListener("mousedown", onClick);
1088
+ document.addEventListener("keydown", onKey);
1089
+ return () => {
1090
+ document.removeEventListener("mousedown", onClick);
1091
+ document.removeEventListener("keydown", onKey);
1092
+ };
1093
+ }, [open]);
1094
+ const links = [...primary ?? [], ...secondary ?? []];
1095
+ 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";
1096
+ return /* @__PURE__ */ jsxs("div", { ref, className: "relative md:hidden", "data-oc-account-mobile-menu": "", children: [
1097
+ /* @__PURE__ */ jsx(
1098
+ "button",
1099
+ {
1100
+ type: "button",
1101
+ onClick: () => setOpen((v) => !v),
1102
+ "aria-haspopup": "menu",
1103
+ "aria-expanded": open,
1104
+ "aria-label": "menu",
1105
+ className: "border-input bg-background hover:bg-accent text-muted-foreground inline-flex size-8 items-center justify-center rounded-md border transition-colors",
1106
+ "data-oc-account-mobile-toggle": "",
1107
+ children: open ? /* @__PURE__ */ jsx(X, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(Menu, { className: "size-4", "aria-hidden": true })
1108
+ }
1109
+ ),
1110
+ open && /* @__PURE__ */ jsxs(
1111
+ "div",
1112
+ {
1113
+ role: "menu",
1114
+ "aria-label": "menu",
1115
+ 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",
1116
+ "data-oc-account-mobile-popover": "",
1117
+ children: [
1118
+ links.length > 0 && /* @__PURE__ */ jsxs("div", { className: "border-b p-1", children: [
1119
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 navigate" }),
1120
+ links.map(
1121
+ (l) => l.external ? /* @__PURE__ */ jsxs(
1122
+ "a",
1123
+ {
1124
+ href: l.href,
1125
+ target: "_blank",
1126
+ rel: "noreferrer",
1127
+ role: "menuitem",
1128
+ onClick: () => setOpen(false),
1129
+ className: rowCls,
1130
+ children: [
1131
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1132
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: l.label }),
1133
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 text-[10px]", "aria-hidden": true, children: "\u2197" })
1134
+ ]
1135
+ },
1136
+ l.href
1137
+ ) : /* @__PURE__ */ jsxs(
1138
+ Link5,
1139
+ {
1140
+ href: l.href,
1141
+ role: "menuitem",
1142
+ onClick: () => setOpen(false),
1143
+ className: rowCls,
1144
+ children: [
1145
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1146
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: l.label })
1147
+ ]
1148
+ },
1149
+ l.href
1150
+ )
1151
+ )
1152
+ ] }),
1153
+ /* @__PURE__ */ jsx(AppearanceControls, {})
1154
+ ]
1155
+ }
1156
+ )
1157
+ ] });
1158
+ }
1004
1159
  function OcAccountMenuView({
1005
1160
  current,
1006
1161
  signInUrl = "/signin",
@@ -1073,220 +1228,220 @@ function OcAccountMenuView({
1073
1228
  children: signInLabel
1074
1229
  }
1075
1230
  );
1231
+ const hasNav = (primaryNavLinks?.length ?? 0) + (secondaryNavLinks?.length ?? 0) > 0;
1232
+ const wrap = (identity) => /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-1", className), "data-oc-account-menu": "", children: [
1233
+ hasNav ? /* @__PURE__ */ jsx(MobileMenu, { primary: primaryNavLinks, secondary: secondaryNavLinks }) : null,
1234
+ identity
1235
+ ] });
1076
1236
  if (!hydrated || status === "loading") {
1077
- return signInTrigger;
1237
+ return wrap(signInTrigger);
1078
1238
  }
1079
1239
  if (status !== "authenticated" || !account) {
1080
- return signInTrigger;
1240
+ return wrap(signInTrigger);
1081
1241
  }
1082
1242
  const displayName = account.displayName ?? null;
1083
1243
  const label = displayName ?? obscureIdentity(account.displayIdentity.value);
1084
- return /* @__PURE__ */ jsxs(
1085
- "div",
1086
- {
1087
- ref: wrapRef,
1088
- className: "relative inline-block " + (className ?? ""),
1089
- "data-oc-account-menu": "",
1090
- children: [
1091
- /* @__PURE__ */ jsxs(
1092
- "button",
1093
- {
1094
- type: "button",
1095
- onClick: () => setOpen((v) => !v),
1096
- "aria-haspopup": "menu",
1097
- "aria-expanded": open,
1098
- "aria-label": `Signed in as ${account.didOc}. Open account menu.`,
1099
- 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",
1100
- "data-oc-account-menu-trigger": "",
1101
- children: [
1102
- /* @__PURE__ */ jsx("span", { className: "bg-primary inline-block size-1.5 shrink-0 rounded-full", "aria-hidden": true }),
1103
- /* @__PURE__ */ jsx("span", { className: "text-foreground hidden max-w-[16ch] truncate sm:inline", children: label }),
1104
- /* @__PURE__ */ jsx(
1105
- "svg",
1106
- {
1107
- width: "9",
1108
- height: "9",
1109
- viewBox: "0 0 10 10",
1110
- "aria-hidden": true,
1111
- className: "opacity-60 transition-transform " + (open ? "rotate-180" : "rotate-0"),
1112
- children: /* @__PURE__ */ jsx(
1113
- "path",
1114
- {
1115
- d: "M2 4 L5 7 L8 4",
1116
- stroke: "currentColor",
1117
- strokeWidth: "1.5",
1118
- fill: "none",
1119
- strokeLinecap: "round"
1120
- }
1121
- )
1122
- }
1123
- )
1124
- ]
1125
- }
1126
- ),
1127
- open && /* @__PURE__ */ jsxs(
1128
- "div",
1129
- {
1130
- role: "menu",
1131
- "aria-label": "Account menu",
1132
- 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",
1133
- "data-oc-account-menu-popover": "",
1134
- children: [
1135
- /* @__PURE__ */ jsxs("div", { className: "border-border border-b p-3", children: [
1136
- /* @__PURE__ */ jsxs("div", { className: "text-primary mb-1 font-mono text-[10px] tracking-widest uppercase", children: [
1137
- "\xA7 signed in \xB7 ",
1138
- hostname,
1139
- tabPinned ? /* @__PURE__ */ jsxs(
1244
+ return wrap(
1245
+ /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative inline-block", children: [
1246
+ /* @__PURE__ */ jsxs(
1247
+ "button",
1248
+ {
1249
+ type: "button",
1250
+ onClick: () => setOpen((v) => !v),
1251
+ "aria-haspopup": "menu",
1252
+ "aria-expanded": open,
1253
+ "aria-label": `Signed in as ${account.didOc}. Open account menu.`,
1254
+ 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",
1255
+ "data-oc-account-menu-trigger": "",
1256
+ children: [
1257
+ /* @__PURE__ */ jsx("span", { className: "bg-primary inline-block size-1.5 shrink-0 rounded-full", "aria-hidden": true }),
1258
+ /* @__PURE__ */ jsx("span", { className: "text-foreground hidden max-w-[16ch] truncate sm:inline", children: label }),
1259
+ /* @__PURE__ */ jsx(
1260
+ "svg",
1261
+ {
1262
+ width: "9",
1263
+ height: "9",
1264
+ viewBox: "0 0 10 10",
1265
+ "aria-hidden": true,
1266
+ className: "opacity-60 transition-transform " + (open ? "rotate-180" : "rotate-0"),
1267
+ children: /* @__PURE__ */ jsx(
1268
+ "path",
1269
+ {
1270
+ d: "M2 4 L5 7 L8 4",
1271
+ stroke: "currentColor",
1272
+ strokeWidth: "1.5",
1273
+ fill: "none",
1274
+ strokeLinecap: "round"
1275
+ }
1276
+ )
1277
+ }
1278
+ )
1279
+ ]
1280
+ }
1281
+ ),
1282
+ open && /* @__PURE__ */ jsxs(
1283
+ "div",
1284
+ {
1285
+ role: "menu",
1286
+ "aria-label": "Account menu",
1287
+ 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",
1288
+ "data-oc-account-menu-popover": "",
1289
+ children: [
1290
+ /* @__PURE__ */ jsxs("div", { className: "border-border border-b p-3", children: [
1291
+ /* @__PURE__ */ jsxs("div", { className: "text-primary mb-1 font-mono text-[10px] tracking-widest uppercase", children: [
1292
+ "\xA7 signed in \xB7 ",
1293
+ hostname,
1294
+ tabPinned ? /* @__PURE__ */ jsxs(
1295
+ "span",
1296
+ {
1297
+ className: "text-muted-foreground/70 normal-case",
1298
+ "data-oc-account-menu-tab-pin": "",
1299
+ title: "This tab keeps this account even if you switch accounts in another tab",
1300
+ children: [
1301
+ " ",
1302
+ "\xB7 this tab"
1303
+ ]
1304
+ }
1305
+ ) : null
1306
+ ] }),
1307
+ /* @__PURE__ */ jsx(CopyableDid, { did: account.didOc }),
1308
+ displayName ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/80 mt-1 font-mono text-[10px] tracking-wide", children: displayName }) : null
1309
+ ] }),
1310
+ /* @__PURE__ */ jsx(
1311
+ IdentityPromoteSection,
1312
+ {
1313
+ didOc: account.didOc,
1314
+ nostrNpub: account.nostrNpub ?? null,
1315
+ current: account.displayIdentity,
1316
+ open,
1317
+ setDisplayIdentity
1318
+ }
1319
+ ),
1320
+ /* @__PURE__ */ jsx(
1321
+ AccountsSection,
1322
+ {
1323
+ roster: roster ?? [],
1324
+ switchAccount,
1325
+ addAccountUrl,
1326
+ signOut,
1327
+ onActionStart: () => setOpen(false)
1328
+ }
1329
+ ),
1330
+ primaryNavLinks && primaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1331
+ PopoverSection,
1332
+ {
1333
+ label: "navigate",
1334
+ items: primaryNavLinks,
1335
+ onItemClick: () => setOpen(false),
1336
+ className: "hidden md:block"
1337
+ }
1338
+ ) : null,
1339
+ /* @__PURE__ */ jsxs("div", { className: "p-1", "data-oc-account-menu-section": "account", children: [
1340
+ menuItems?.map((item) => {
1341
+ const onClick = () => setOpen(false);
1342
+ const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
1343
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
1344
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1345
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1346
+ item.external ? /* @__PURE__ */ jsx(
1140
1347
  "span",
1141
1348
  {
1142
- className: "text-muted-foreground/70 normal-case",
1143
- "data-oc-account-menu-tab-pin": "",
1144
- title: "This tab keeps this account even if you switch accounts in another tab",
1145
- children: [
1146
- " ",
1147
- "\xB7 this tab"
1148
- ]
1349
+ className: "text-muted-foreground/70 text-[10px]",
1350
+ "aria-hidden": true,
1351
+ children: "\u2197"
1149
1352
  }
1150
1353
  ) : null
1151
- ] }),
1152
- /* @__PURE__ */ jsx(CopyableDid, { did: account.didOc }),
1153
- displayName ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/80 mt-1 font-mono text-[10px] tracking-wide", children: displayName }) : null
1154
- ] }),
1155
- /* @__PURE__ */ jsx(
1156
- IdentityPromoteSection,
1157
- {
1158
- didOc: account.didOc,
1159
- nostrNpub: account.nostrNpub ?? null,
1160
- current: account.displayIdentity,
1161
- open,
1162
- setDisplayIdentity
1163
- }
1164
- ),
1165
- /* @__PURE__ */ jsx(
1166
- AccountsSection,
1167
- {
1168
- roster: roster ?? [],
1169
- switchAccount,
1170
- addAccountUrl,
1171
- signOut,
1172
- onActionStart: () => setOpen(false)
1173
- }
1174
- ),
1175
- primaryNavLinks && primaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1176
- PopoverSection,
1177
- {
1178
- label: "navigate",
1179
- items: primaryNavLinks,
1180
- onItemClick: () => setOpen(false)
1181
- }
1182
- ) : null,
1183
- /* @__PURE__ */ jsxs("div", { className: "p-1", "data-oc-account-menu-section": "account", children: [
1184
- 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,
1185
- menuItems?.map((item) => {
1186
- const onClick = () => setOpen(false);
1187
- const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
1188
- const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
1189
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1190
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1191
- item.external ? /* @__PURE__ */ jsx(
1192
- "span",
1193
- {
1194
- className: "text-muted-foreground/70 text-[10px]",
1195
- "aria-hidden": true,
1196
- children: "\u2197"
1197
- }
1198
- ) : null
1199
- ] });
1200
- return item.external ? /* @__PURE__ */ jsx(
1201
- "a",
1202
- {
1203
- href: item.href,
1204
- target: "_blank",
1205
- rel: "noreferrer",
1206
- onClick,
1207
- role: "menuitem",
1208
- className: cls,
1209
- "data-oc-account-menu-item": "",
1210
- children: inner
1211
- },
1212
- item.href
1213
- ) : /* @__PURE__ */ jsx(
1214
- Link5,
1215
- {
1216
- href: item.href,
1217
- onClick,
1218
- role: "menuitem",
1219
- className: cls,
1220
- "data-oc-account-menu-item": "",
1221
- children: inner
1222
- },
1223
- item.href
1224
- );
1225
- }),
1226
- familyDashboardEnabled ? /* @__PURE__ */ jsxs(
1354
+ ] });
1355
+ return item.external ? /* @__PURE__ */ jsx(
1227
1356
  "a",
1228
1357
  {
1229
- href: "https://ochk.io/dashboard",
1358
+ href: item.href,
1230
1359
  target: "_blank",
1231
1360
  rel: "noreferrer",
1232
- onClick: () => setOpen(false),
1361
+ onClick,
1233
1362
  role: "menuitem",
1234
- className: "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors",
1363
+ className: cls,
1235
1364
  "data-oc-account-menu-item": "",
1236
- "data-oc-account-menu-family-dashboard": "",
1237
- children: [
1238
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1239
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: "family dashboard" }),
1240
- /* @__PURE__ */ jsx(
1241
- "span",
1242
- {
1243
- className: "text-muted-foreground/70 text-[10px]",
1244
- "aria-hidden": true,
1245
- children: "\u2197"
1246
- }
1247
- )
1248
- ]
1249
- }
1250
- ) : null,
1251
- /* @__PURE__ */ jsxs(
1252
- "button",
1365
+ children: inner
1366
+ },
1367
+ item.href
1368
+ ) : /* @__PURE__ */ jsx(
1369
+ Link5,
1253
1370
  {
1254
- type: "button",
1371
+ href: item.href,
1372
+ onClick,
1255
1373
  role: "menuitem",
1256
- onClick: () => {
1257
- setOpen(false);
1258
- void (async () => {
1259
- await signOut();
1260
- if (typeof window !== "undefined") {
1261
- window.location.assign(signOutRedirect);
1262
- }
1263
- })();
1264
- },
1265
- 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",
1374
+ className: cls,
1266
1375
  "data-oc-account-menu-item": "",
1267
- "data-oc-account-menu-signout": "",
1268
- children: [
1269
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1270
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: "sign out" })
1271
- ]
1272
- }
1273
- )
1274
- ] }),
1275
- secondaryNavLinks && secondaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1276
- PopoverSection,
1376
+ children: inner
1377
+ },
1378
+ item.href
1379
+ );
1380
+ }),
1381
+ familyDashboardEnabled ? /* @__PURE__ */ jsxs(
1382
+ "a",
1277
1383
  {
1278
- label: "more",
1279
- items: secondaryNavLinks,
1280
- onItemClick: () => setOpen(false),
1281
- bordered: true
1384
+ href: "https://ochk.io/dashboard",
1385
+ target: "_blank",
1386
+ rel: "noreferrer",
1387
+ onClick: () => setOpen(false),
1388
+ role: "menuitem",
1389
+ className: "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors",
1390
+ "data-oc-account-menu-item": "",
1391
+ "data-oc-account-menu-family-dashboard": "",
1392
+ children: [
1393
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1394
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "family dashboard" }),
1395
+ /* @__PURE__ */ jsx(
1396
+ "span",
1397
+ {
1398
+ className: "text-muted-foreground/70 text-[10px]",
1399
+ "aria-hidden": true,
1400
+ children: "\u2197"
1401
+ }
1402
+ )
1403
+ ]
1282
1404
  }
1283
1405
  ) : null,
1284
- build ? /* @__PURE__ */ jsx(BuildFooter, { hostname, build, state: siteState }) : null
1285
- ]
1286
- }
1287
- )
1288
- ]
1289
- }
1406
+ /* @__PURE__ */ jsxs(
1407
+ "button",
1408
+ {
1409
+ type: "button",
1410
+ role: "menuitem",
1411
+ onClick: () => {
1412
+ setOpen(false);
1413
+ void (async () => {
1414
+ await signOut();
1415
+ if (typeof window !== "undefined") {
1416
+ window.location.assign(signOutRedirect);
1417
+ }
1418
+ })();
1419
+ },
1420
+ 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",
1421
+ "data-oc-account-menu-item": "",
1422
+ "data-oc-account-menu-signout": "",
1423
+ children: [
1424
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1425
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "sign out" })
1426
+ ]
1427
+ }
1428
+ )
1429
+ ] }),
1430
+ secondaryNavLinks && secondaryNavLinks.length > 0 ? /* @__PURE__ */ jsx(
1431
+ PopoverSection,
1432
+ {
1433
+ label: "more",
1434
+ items: secondaryNavLinks,
1435
+ onItemClick: () => setOpen(false),
1436
+ bordered: true,
1437
+ className: "hidden md:block"
1438
+ }
1439
+ ) : null,
1440
+ build ? /* @__PURE__ */ jsx(BuildFooter, { hostname, build, state: siteState }) : null
1441
+ ]
1442
+ }
1443
+ )
1444
+ ] })
1290
1445
  );
1291
1446
  }
1292
1447
  function AccountsSection({
@@ -1399,33 +1554,22 @@ function PopoverSection({
1399
1554
  label,
1400
1555
  items,
1401
1556
  onItemClick,
1402
- bordered
1557
+ bordered,
1558
+ className
1403
1559
  }) {
1404
1560
  const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
1405
1561
  return /* @__PURE__ */ jsxs(
1406
1562
  "div",
1407
1563
  {
1408
- className: "p-1 " + (bordered ? "border-border border-t" : ""),
1564
+ className: cn("p-1", bordered && "border-border border-t", className),
1409
1565
  "data-oc-account-menu-section": label,
1410
1566
  children: [
1411
1567
  /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: [
1412
1568
  "\xA7 ",
1413
1569
  label
1414
1570
  ] }),
1415
- items.map((item) => {
1416
- const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
1417
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1418
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1419
- item.external ? /* @__PURE__ */ jsx(
1420
- "span",
1421
- {
1422
- className: "text-muted-foreground/70 text-[10px]",
1423
- "aria-hidden": true,
1424
- children: "\u2197"
1425
- }
1426
- ) : null
1427
- ] });
1428
- return item.external ? /* @__PURE__ */ jsx(
1571
+ items.map(
1572
+ (item) => item.external ? /* @__PURE__ */ jsxs(
1429
1573
  "a",
1430
1574
  {
1431
1575
  href: item.href,
@@ -1435,10 +1579,14 @@ function PopoverSection({
1435
1579
  role: "menuitem",
1436
1580
  className: cls,
1437
1581
  "data-oc-account-menu-item": "",
1438
- children: inner
1582
+ children: [
1583
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1584
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
1585
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 text-[10px]", "aria-hidden": true, children: "\u2197" })
1586
+ ]
1439
1587
  },
1440
1588
  item.href
1441
- ) : /* @__PURE__ */ jsx(
1589
+ ) : /* @__PURE__ */ jsxs(
1442
1590
  Link5,
1443
1591
  {
1444
1592
  href: item.href,
@@ -1446,11 +1594,14 @@ function PopoverSection({
1446
1594
  role: "menuitem",
1447
1595
  className: cls,
1448
1596
  "data-oc-account-menu-item": "",
1449
- children: inner
1597
+ children: [
1598
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1599
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label })
1600
+ ]
1450
1601
  },
1451
1602
  item.href
1452
- );
1453
- })
1603
+ )
1604
+ )
1454
1605
  ]
1455
1606
  }
1456
1607
  );
@@ -1502,146 +1653,54 @@ function isActive(pathname, link) {
1502
1653
  if (link.href === "/") return pathname === "/";
1503
1654
  return pathname === link.href || pathname.startsWith(link.href + "/");
1504
1655
  }
1505
- function ExternalGlyph() {
1506
- return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-muted-foreground/60 ml-1 text-[9px]", children: "\u2197" });
1507
- }
1508
1656
  function OcPrimaryNav({
1509
1657
  activePath,
1510
1658
  links,
1511
1659
  className
1512
1660
  }) {
1513
- const [open, setOpen] = useState(false);
1514
- const ref = useRef(null);
1515
- const menuId = useId();
1516
- useEffect(() => {
1517
- setOpen(false);
1518
- }, [activePath]);
1519
- useEffect(() => {
1520
- if (!open) return;
1521
- const onClick = (e) => {
1522
- if (ref.current && !ref.current.contains(e.target)) setOpen(false);
1523
- };
1524
- const onKey = (e) => {
1525
- if (e.key === "Escape") setOpen(false);
1526
- };
1527
- document.addEventListener("mousedown", onClick);
1528
- document.addEventListener("keydown", onKey);
1529
- return () => {
1530
- document.removeEventListener("mousedown", onClick);
1531
- document.removeEventListener("keydown", onKey);
1532
- };
1533
- }, [open]);
1534
- const inlineClass = (active) => "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");
1535
- const rowClass = (active) => "font-display flex items-center gap-2 px-3 py-2 text-[12px] font-semibold tracking-wider uppercase transition-colors " + (active ? "text-primary" : "text-muted-foreground hover:text-foreground hover:bg-accent");
1536
- function renderInline(link) {
1537
- const active = isActive(activePath, link);
1538
- const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
1539
- link.label,
1540
- link.external ? /* @__PURE__ */ jsx(ExternalGlyph, {}) : null
1541
- ] });
1542
- return link.external ? /* @__PURE__ */ jsx(
1543
- "a",
1544
- {
1545
- href: link.href,
1546
- target: "_blank",
1547
- rel: "noreferrer",
1548
- className: inlineClass(false),
1549
- "data-oc-primary-nav-item": "",
1550
- children: inner
1551
- },
1552
- link.href
1553
- ) : /* @__PURE__ */ jsx(
1554
- Link5,
1555
- {
1556
- href: link.href,
1557
- "aria-current": active ? "page" : void 0,
1558
- className: inlineClass(active),
1559
- "data-oc-primary-nav-item": active ? "active" : "sibling",
1560
- children: inner
1561
- },
1562
- link.href
1563
- );
1564
- }
1565
- function renderRow(link) {
1566
- const active = isActive(activePath, link);
1567
- const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
1568
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
1569
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: link.label }),
1570
- link.external ? /* @__PURE__ */ jsx(ExternalGlyph, {}) : null
1571
- ] });
1572
- return link.external ? /* @__PURE__ */ jsx(
1573
- "a",
1574
- {
1575
- href: link.href,
1576
- target: "_blank",
1577
- rel: "noreferrer",
1578
- role: "menuitem",
1579
- onClick: () => setOpen(false),
1580
- className: rowClass(false),
1581
- "data-oc-primary-nav-item": "",
1582
- children: inner
1583
- },
1584
- link.href
1585
- ) : /* @__PURE__ */ jsx(
1586
- Link5,
1587
- {
1588
- href: link.href,
1589
- role: "menuitem",
1590
- "aria-current": active ? "page" : void 0,
1591
- onClick: () => setOpen(false),
1592
- className: rowClass(active),
1593
- "data-oc-primary-nav-item": active ? "active" : "sibling",
1594
- children: inner
1595
- },
1596
- link.href
1597
- );
1598
- }
1599
- return /* @__PURE__ */ jsxs(
1600
- "div",
1661
+ return /* @__PURE__ */ jsx(
1662
+ "nav",
1601
1663
  {
1602
- ref,
1603
- className: "relative flex items-center justify-center " + (className ?? ""),
1664
+ "aria-label": "primary",
1665
+ className: "hidden items-center gap-0.5 sm:gap-1 md:flex " + (className ?? ""),
1604
1666
  "data-oc-primary-nav": "",
1605
- children: [
1606
- /* @__PURE__ */ jsx(
1607
- "nav",
1608
- {
1609
- "aria-label": "primary",
1610
- className: "hidden items-center gap-0.5 sm:gap-1 md:flex",
1611
- children: links.map(renderInline)
1612
- }
1613
- ),
1614
- /* @__PURE__ */ jsxs("div", { className: "md:hidden", children: [
1615
- /* @__PURE__ */ jsx(
1616
- "button",
1667
+ children: links.map((link) => {
1668
+ const active = isActive(activePath, link);
1669
+ 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");
1670
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1671
+ link.label,
1672
+ link.external ? /* @__PURE__ */ jsx(
1673
+ "span",
1617
1674
  {
1618
- type: "button",
1619
- onClick: () => setOpen((v) => !v),
1620
- "aria-haspopup": "menu",
1621
- "aria-expanded": open,
1622
- "aria-controls": menuId,
1623
- "aria-label": "site navigation",
1624
- className: "border-input bg-background hover:bg-accent text-muted-foreground inline-flex size-8 items-center justify-center rounded-md border transition-colors",
1625
- "data-oc-primary-nav-toggle": "",
1626
- children: open ? /* @__PURE__ */ jsx(X, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(Menu, { className: "size-4", "aria-hidden": true })
1675
+ "aria-hidden": true,
1676
+ className: "text-muted-foreground/60 ml-1 text-[9px]",
1677
+ children: "\u2197"
1627
1678
  }
1628
- ),
1629
- open && /* @__PURE__ */ jsxs(
1630
- "div",
1631
- {
1632
- id: menuId,
1633
- role: "menu",
1634
- "aria-label": "primary",
1635
- className: "border-border bg-popover text-popover-foreground absolute top-[calc(100%+8px)] left-1/2 z-50 w-[min(15rem,calc(100vw-1rem))] -translate-x-1/2 border p-1 shadow-xl",
1636
- "data-oc-primary-nav-popover": "",
1637
- children: [
1638
- /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 navigate" }),
1639
- links.map(renderRow)
1640
- ]
1641
- }
1642
- )
1643
- ] })
1644
- ]
1679
+ ) : null
1680
+ ] });
1681
+ return link.external ? /* @__PURE__ */ jsx(
1682
+ "a",
1683
+ {
1684
+ href: link.href,
1685
+ target: "_blank",
1686
+ rel: "noreferrer",
1687
+ className: cls,
1688
+ "data-oc-primary-nav-item": "",
1689
+ children: content
1690
+ },
1691
+ link.href
1692
+ ) : /* @__PURE__ */ jsx(
1693
+ Link5,
1694
+ {
1695
+ href: link.href,
1696
+ "aria-current": active ? "page" : void 0,
1697
+ className: cls,
1698
+ "data-oc-primary-nav-item": active ? "active" : "sibling",
1699
+ children: content
1700
+ },
1701
+ link.href
1702
+ );
1703
+ })
1645
1704
  }
1646
1705
  );
1647
1706
  }