@orangecheck/design 0.6.1 → 0.7.1

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.js CHANGED
@@ -18,8 +18,11 @@ var PopoverPrimitive = require('@radix-ui/react-popover');
18
18
  var AccordionPrimitive = require('@radix-ui/react-accordion');
19
19
  var SelectPrimitive = require('@radix-ui/react-select');
20
20
  var sonner = require('sonner');
21
+ var TabsPrimitive = require('@radix-ui/react-tabs');
21
22
  var QRCode = require('qrcode');
22
- var ui_star = require('@orangecheck/ui');
23
+ var Link6 = require('next/link');
24
+ var router = require('next/router');
25
+ var authClient = require('@orangecheck/auth-client');
23
26
 
24
27
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
25
28
 
@@ -51,131 +54,11 @@ var SheetPrimitive__namespace = /*#__PURE__*/_interopNamespace(SheetPrimitive);
51
54
  var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
52
55
  var AccordionPrimitive__namespace = /*#__PURE__*/_interopNamespace(AccordionPrimitive);
53
56
  var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
57
+ var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
54
58
  var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
55
- var ui_star__namespace = /*#__PURE__*/_interopNamespace(ui_star);
59
+ var Link6__default = /*#__PURE__*/_interopDefault(Link6);
56
60
 
57
- var __defProp = Object.defineProperty;
58
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
59
- var __getOwnPropNames = Object.getOwnPropertyNames;
60
- var __hasOwnProp = Object.prototype.hasOwnProperty;
61
- var __export = (target, all) => {
62
- for (var name in all)
63
- __defProp(target, name, { get: all[name], enumerable: true });
64
- };
65
- var __copyProps = (to, from, except, desc) => {
66
- if (from && typeof from === "object" || typeof from === "function") {
67
- for (let key of __getOwnPropNames(from))
68
- if (!__hasOwnProp.call(to, key) && key !== except)
69
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
70
- }
71
- return to;
72
- };
73
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget);
74
-
75
- // src/index.ts
76
- var src_exports = {};
77
- __export(src_exports, {
78
- Accordion: () => Accordion,
79
- AccordionContent: () => AccordionContent,
80
- AccordionItem: () => AccordionItem,
81
- AccordionTrigger: () => AccordionTrigger,
82
- Alert: () => Alert,
83
- AlertDescription: () => AlertDescription,
84
- AlertTitle: () => AlertTitle,
85
- AlertWithAction: () => AlertWithAction,
86
- AlertWithCountdown: () => AlertWithCountdown,
87
- Badge: () => Badge,
88
- Bar: () => Bar,
89
- BitcoinAddress: () => BitcoinAddress,
90
- Button: () => Button,
91
- Card: () => Card,
92
- Checkbox: () => Checkbox,
93
- ConfirmHost: () => ConfirmHost,
94
- CopyButton: () => CopyButton,
95
- DEFAULT_OC_THEME: () => DEFAULT_OC_THEME,
96
- Dialog: () => Dialog,
97
- DialogClose: () => DialogClose,
98
- DialogContent: () => DialogContent,
99
- DialogDescription: () => DialogDescription,
100
- DialogFooter: () => DialogFooter,
101
- DialogHeader: () => DialogHeader,
102
- DialogOverlay: () => DialogOverlay,
103
- DialogPortal: () => DialogPortal,
104
- DialogTitle: () => DialogTitle,
105
- DialogTrigger: () => DialogTrigger,
106
- ErrorBoundary: () => ErrorBoundary,
107
- Input: () => Input,
108
- Label: () => Label,
109
- Modal: () => Modal,
110
- OC_DEFAULT_ACCENT: () => OC_DEFAULT_ACCENT,
111
- OC_SKIN_COOKIE: () => OC_SKIN_COOKIE,
112
- OC_THEMES: () => OC_THEMES,
113
- OcAppearanceMenu: () => OcAppearanceMenu,
114
- OcThemeBridge: () => OcThemeBridge,
115
- OcThemePicker: () => OcThemePicker,
116
- OcThemeProvider: () => OcThemeProvider,
117
- Pagination: () => Pagination,
118
- Popover: () => Popover,
119
- PopoverAnchor: () => PopoverAnchor,
120
- PopoverContent: () => PopoverContent,
121
- PopoverTrigger: () => PopoverTrigger,
122
- PromptHost: () => PromptHost,
123
- QrCode: () => QrCode,
124
- REFERENCE_BTC_USD: () => REFERENCE_BTC_USD,
125
- RadioGroup: () => RadioGroup,
126
- RadioGroupItem: () => RadioGroupItem,
127
- SatsAmount: () => SatsAmount,
128
- Select: () => Select,
129
- SelectContent: () => SelectContent,
130
- SelectGroup: () => SelectGroup,
131
- SelectItem: () => SelectItem,
132
- SelectLabel: () => SelectLabel,
133
- SelectScrollDownButton: () => SelectScrollDownButton,
134
- SelectScrollUpButton: () => SelectScrollUpButton,
135
- SelectSeparator: () => SelectSeparator,
136
- SelectTrigger: () => SelectTrigger,
137
- SelectValue: () => SelectValue,
138
- Separator: () => Separator,
139
- Sheet: () => Sheet,
140
- SheetClose: () => SheetClose,
141
- SheetContent: () => SheetContent,
142
- SheetDescription: () => SheetDescription,
143
- SheetFooter: () => SheetFooter,
144
- SheetHeader: () => SheetHeader,
145
- SheetOverlay: () => SheetOverlay,
146
- SheetPortal: () => SheetPortal,
147
- SheetTitle: () => SheetTitle,
148
- SheetTrigger: () => SheetTrigger,
149
- Skeleton: () => Skeleton,
150
- Sparkline: () => Sparkline,
151
- StatBlock: () => StatBlock,
152
- StatusPill: () => StatusPill,
153
- Switch: () => Switch,
154
- Textarea: () => Textarea,
155
- ThemeToggle: () => ThemeToggle,
156
- ThemeToggleLink: () => ThemeToggleLink,
157
- Toaster: () => Toaster,
158
- Working: () => Working,
159
- WorkingPanel: () => WorkingPanel,
160
- accentFor: () => accentFor,
161
- badgeVariants: () => badgeVariants,
162
- buttonVariants: () => buttonVariants,
163
- cn: () => cn,
164
- confirm: () => confirm,
165
- explorerUrl: () => explorerUrl,
166
- formatSats: () => formatSats,
167
- formatSatsCompact: () => formatSatsCompact,
168
- getOcThemeInitScript: () => getOcThemeInitScript,
169
- isKnownTheme: () => isKnownTheme,
170
- priceBoth: () => priceBoth,
171
- prompt: () => prompt,
172
- relativeTime: () => relativeTime,
173
- resolveTheme: () => resolveTheme,
174
- satsToUsd: () => satsToUsd,
175
- shortenAddress: () => shortenAddress,
176
- usdToSats: () => usdToSats,
177
- useOcSkin: () => useOcSkin
178
- });
61
+ // src/tokens/cn.ts
179
62
  function cn(...inputs) {
180
63
  return tailwindMerge.twMerge(clsx.clsx(inputs));
181
64
  }
@@ -978,6 +861,7 @@ var ErrorBoundary = class extends React2__namespace.Component {
978
861
  }
979
862
  componentDidCatch(error, info) {
980
863
  console.error("[ErrorBoundary]", error, info);
864
+ this.props.onError?.(error, info);
981
865
  }
982
866
  render() {
983
867
  if (this.state.error) {
@@ -985,7 +869,7 @@ var ErrorBoundary = class extends React2__namespace.Component {
985
869
  return this.props.fallback(this.state.error, this.reset);
986
870
  }
987
871
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "terminal", children: [
988
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "terminal-title", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive flex items-center gap-1.5", children: "! fatal" }) }),
872
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "terminal-title", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive flex items-center gap-1.5", children: this.props.title ?? "! fatal" }) }),
989
873
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 p-5 font-mono text-xs leading-relaxed", children: [
990
874
  /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
991
875
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-destructive", children: [
@@ -997,7 +881,7 @@ var ErrorBoundary = class extends React2__namespace.Component {
997
881
  ] }),
998
882
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground", children: [
999
883
  "> ",
1000
- "this page crashed. reload to recover."
884
+ this.props.message ?? "this page crashed. reload to recover."
1001
885
  ] }),
1002
886
  /* @__PURE__ */ jsxRuntime.jsx(
1003
887
  "button",
@@ -1934,7 +1818,37 @@ var TONE = {
1934
1818
  primary: "text-primary",
1935
1819
  info: "text-info"
1936
1820
  };
1937
- function StatusPill({ label, tone = "muted", icon, className }) {
1821
+ var BORDER_TONE = {
1822
+ success: "border-success/40 text-success",
1823
+ warning: "border-warning/40 text-warning",
1824
+ destructive: "border-destructive/40 text-destructive",
1825
+ muted: "border-muted-foreground/40 text-muted-foreground",
1826
+ primary: "border-primary/40 text-primary",
1827
+ info: "border-info/40 text-info"
1828
+ };
1829
+ function StatusPill({
1830
+ label,
1831
+ tone = "muted",
1832
+ variant = "plain",
1833
+ icon,
1834
+ className
1835
+ }) {
1836
+ if (variant === "bordered") {
1837
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1838
+ "span",
1839
+ {
1840
+ className: cn(
1841
+ "inline-flex items-center gap-1.5 border px-1.5 py-0.5 font-mono text-[9px] tracking-widest uppercase",
1842
+ BORDER_TONE[tone],
1843
+ className
1844
+ ),
1845
+ children: [
1846
+ icon,
1847
+ label
1848
+ ]
1849
+ }
1850
+ );
1851
+ }
1938
1852
  return /* @__PURE__ */ jsxRuntime.jsxs(
1939
1853
  "span",
1940
1854
  {
@@ -1950,6 +1864,60 @@ function StatusPill({ label, tone = "muted", icon, className }) {
1950
1864
  }
1951
1865
  );
1952
1866
  }
1867
+ function makeStatusPill(map, options) {
1868
+ const variant = options?.variant ?? "plain";
1869
+ const fallbackTone = options?.fallbackTone ?? "muted";
1870
+ function DomainStatusPill({ status, className }) {
1871
+ const spec = map[status];
1872
+ return /* @__PURE__ */ jsxRuntime.jsx(
1873
+ StatusPill,
1874
+ {
1875
+ tone: spec?.tone ?? fallbackTone,
1876
+ label: spec?.label ?? status,
1877
+ icon: spec?.icon,
1878
+ variant,
1879
+ className
1880
+ }
1881
+ );
1882
+ }
1883
+ return DomainStatusPill;
1884
+ }
1885
+ function Tabs({ ...props }) {
1886
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsPrimitive__namespace.Root, { "data-slot": "tabs", ...props });
1887
+ }
1888
+ function TabsList({ className, ...props }) {
1889
+ return /* @__PURE__ */ jsxRuntime.jsx(
1890
+ TabsPrimitive__namespace.List,
1891
+ {
1892
+ "data-slot": "tabs-list",
1893
+ className: cn("border-border -mb-px flex items-center gap-6 border-b", className),
1894
+ ...props
1895
+ }
1896
+ );
1897
+ }
1898
+ function TabsTrigger({ className, ...props }) {
1899
+ return /* @__PURE__ */ jsxRuntime.jsx(
1900
+ TabsPrimitive__namespace.Trigger,
1901
+ {
1902
+ "data-slot": "tabs-trigger",
1903
+ className: cn(
1904
+ "text-muted-foreground hover:text-foreground data-[state=active]:text-primary data-[state=active]:border-primary -mb-px border-b-2 border-transparent py-2 font-mono text-[11px] tracking-widest uppercase transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
1905
+ className
1906
+ ),
1907
+ ...props
1908
+ }
1909
+ );
1910
+ }
1911
+ function TabsContent({ className, ...props }) {
1912
+ return /* @__PURE__ */ jsxRuntime.jsx(
1913
+ TabsPrimitive__namespace.Content,
1914
+ {
1915
+ "data-slot": "tabs-content",
1916
+ className: cn("mt-4 outline-none", className),
1917
+ ...props
1918
+ }
1919
+ );
1920
+ }
1953
1921
 
1954
1922
  // src/format/index.ts
1955
1923
  var REFERENCE_BTC_USD = 95e3;
@@ -2119,13 +2087,1799 @@ function QrCode({ value, size = 200, label, className }) {
2119
2087
  }
2120
2088
  );
2121
2089
  }
2090
+ function HelpHint({
2091
+ title,
2092
+ children,
2093
+ side = "bottom",
2094
+ label = "more information",
2095
+ className
2096
+ }) {
2097
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
2098
+ /* @__PURE__ */ jsxRuntime.jsx(
2099
+ PopoverTrigger,
2100
+ {
2101
+ "aria-label": label,
2102
+ className: cn(
2103
+ "text-muted-foreground/60 hover:text-foreground inline-flex size-3.5 items-center justify-center align-middle transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring",
2104
+ className
2105
+ ),
2106
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircle, { className: "size-3.5", "aria-hidden": true })
2107
+ }
2108
+ ),
2109
+ /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { side, className: "w-72 space-y-1.5", children: [
2110
+ title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "label-mono text-foreground text-[10px]", children: title }),
2111
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground text-xs leading-relaxed", children })
2112
+ ] })
2113
+ ] });
2114
+ }
2115
+ var TONE_CLASS = {
2116
+ primary: "text-primary",
2117
+ muted: "text-muted-foreground",
2118
+ warning: "text-warning",
2119
+ success: "text-success",
2120
+ destructive: "text-destructive"
2121
+ };
2122
+ function SectionHeader({
2123
+ label,
2124
+ meta,
2125
+ hint,
2126
+ tone = "primary",
2127
+ className = ""
2128
+ }) {
2129
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mb-3 flex items-baseline justify-between gap-2 ${className}`, children: [
2130
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
2131
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `label-mono ${TONE_CLASS[tone]}`, children: [
2132
+ "\xA7 ",
2133
+ label
2134
+ ] }),
2135
+ hint && /* @__PURE__ */ jsxRuntime.jsx(HelpHint, { title: hint.title, side: hint.side ?? "bottom", children: hint.body })
2136
+ ] }),
2137
+ meta && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/70 font-mono text-[10px] tracking-widest uppercase", children: meta })
2138
+ ] });
2139
+ }
2140
+ var TONE_CLASS2 = {
2141
+ info: "border-primary/30 bg-primary/5",
2142
+ warning: "border-warning/40 bg-warning/5",
2143
+ muted: "border-border bg-muted/20"
2144
+ };
2145
+ var LABEL_TONE_CLASS = {
2146
+ info: "text-primary",
2147
+ warning: "text-warning",
2148
+ muted: "text-muted-foreground"
2149
+ };
2150
+ function EmptyState({
2151
+ label,
2152
+ children,
2153
+ cta,
2154
+ secondary,
2155
+ tone = "info",
2156
+ className = ""
2157
+ }) {
2158
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `border p-5 md:p-6 ${TONE_CLASS2[tone]} ${className}`, children: [
2159
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `label-mono mb-2 ${LABEL_TONE_CLASS[tone]}`, children: [
2160
+ "\xA7 ",
2161
+ label
2162
+ ] }),
2163
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-foreground/85 max-w-2xl text-sm leading-relaxed", children }),
2164
+ (cta || secondary) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex flex-wrap gap-3", children: [
2165
+ cta && /* @__PURE__ */ jsxRuntime.jsx(CtaLink, { ...cta, variant: "primary" }),
2166
+ secondary && /* @__PURE__ */ jsxRuntime.jsx(CtaLink, { ...secondary, variant: "secondary" })
2167
+ ] })
2168
+ ] });
2169
+ }
2170
+ function CtaLink({
2171
+ label,
2172
+ href,
2173
+ external,
2174
+ variant
2175
+ }) {
2176
+ const cls = variant === "primary" ? "bg-primary text-primary-foreground hover:bg-primary/90 inline-flex h-9 items-center justify-center rounded-md px-4 font-mono text-[11px] font-semibold tracking-widest uppercase" : "text-muted-foreground hover:text-foreground border-input hover:bg-accent inline-flex h-9 items-center justify-center rounded-md border px-4 font-mono text-[11px] tracking-widest uppercase";
2177
+ const text = external ? `${label} \u2197` : label;
2178
+ if (external) {
2179
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noreferrer", className: cls, children: text });
2180
+ }
2181
+ return /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href, className: cls, children: text });
2182
+ }
2183
+ var TONE_CLASS3 = {
2184
+ default: "",
2185
+ primary: "text-primary",
2186
+ success: "text-success",
2187
+ warning: "text-warning",
2188
+ destructive: "text-destructive",
2189
+ muted: "text-muted-foreground"
2190
+ };
2191
+ var COL_CLASS = {
2192
+ 1: "",
2193
+ 2: "md:grid-cols-2",
2194
+ 3: "md:grid-cols-3",
2195
+ 4: "md:grid-cols-2 lg:grid-cols-4"
2196
+ };
2197
+ function StatGrid({ items, columns = 3, className = "" }) {
2198
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `bg-border grid gap-px border ${COL_CLASS[columns]} ${className}`, children: items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsx(Tile, { item: it }, `${it.label}-${i}`)) });
2199
+ }
2200
+ function Tile({ item }) {
2201
+ const tone = item.tone ?? (item.accent ? "primary" : "default");
2202
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-background p-5", children: [
2203
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/80 font-mono text-[10px] tracking-widest uppercase", children: item.label }),
2204
+ /* @__PURE__ */ jsxRuntime.jsx(
2205
+ "div",
2206
+ {
2207
+ className: `font-display mt-1 text-2xl font-bold tabular-nums tracking-tight ${TONE_CLASS3[tone]}`,
2208
+ children: item.value
2209
+ }
2210
+ ),
2211
+ item.sub && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/70 mt-1 font-mono text-[10px] tracking-widest uppercase", children: item.sub })
2212
+ ] });
2213
+ }
2214
+ function StatTile({ children, ...item }) {
2215
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2216
+ /* @__PURE__ */ jsxRuntime.jsx(Tile, { item }),
2217
+ children
2218
+ ] });
2219
+ }
2220
+ var FRAME = {
2221
+ info: "border-primary/30 bg-primary/5",
2222
+ warning: "border-warning/40 bg-warning/5",
2223
+ destructive: "border-destructive/40 bg-destructive/5",
2224
+ success: "border-success/40 bg-success/5",
2225
+ muted: "border-border bg-muted/20"
2226
+ };
2227
+ var LABEL = {
2228
+ info: "text-primary",
2229
+ warning: "text-warning",
2230
+ destructive: "text-destructive",
2231
+ success: "text-success",
2232
+ muted: "text-muted-foreground"
2233
+ };
2234
+ function Callout({ tone = "info", label, icon, children, action, className }) {
2235
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("border p-4 md:p-5", FRAME[tone], className), children: [
2236
+ label && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("label-mono mb-2 flex items-center gap-1.5", LABEL[tone]), children: [
2237
+ icon,
2238
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2239
+ "\xA7 ",
2240
+ label
2241
+ ] })
2242
+ ] }),
2243
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-foreground/85 text-sm leading-relaxed", children: [
2244
+ !label && icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("mr-2 inline-flex align-middle", LABEL[tone]), children: icon }) : null,
2245
+ children
2246
+ ] }),
2247
+ action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-3", children: action })
2248
+ ] });
2249
+ }
2250
+ function DefinitionList({ items, className }) {
2251
+ return /* @__PURE__ */ jsxRuntime.jsx(
2252
+ "dl",
2253
+ {
2254
+ className: cn(
2255
+ "grid gap-x-5 gap-y-2 text-sm sm:grid-cols-[auto_1fr] sm:items-baseline",
2256
+ className
2257
+ ),
2258
+ children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(React2.Fragment, { children: [
2259
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "label-mono text-muted-foreground text-[10px]", children: item.label }),
2260
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "text-foreground font-mono text-xs break-all", children: item.value })
2261
+ ] }, i))
2262
+ }
2263
+ );
2264
+ }
2265
+ function DataRow({ children, meta, action, as, className }) {
2266
+ const Tag = as ?? "div";
2267
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2268
+ Tag,
2269
+ {
2270
+ className: cn(
2271
+ "flex flex-col gap-1 py-3 sm:flex-row sm:items-baseline sm:justify-between sm:gap-4",
2272
+ className
2273
+ ),
2274
+ children: [
2275
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children }),
2276
+ (meta || action) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-3 sm:justify-end", children: [
2277
+ meta && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground font-mono text-[11px] tracking-wide", children: meta }),
2278
+ action
2279
+ ] })
2280
+ ]
2281
+ }
2282
+ );
2283
+ }
2284
+ var ENTRIES = [
2285
+ {
2286
+ slug: "home",
2287
+ href: "https://ochk.io",
2288
+ label: "orangecheck",
2289
+ sub: "umbrella",
2290
+ docsHref: "https://docs.ochk.io"
2291
+ },
2292
+ {
2293
+ slug: "docs",
2294
+ href: "https://docs.ochk.io",
2295
+ label: "oc\xB7docs",
2296
+ sub: "unified docs",
2297
+ docsHref: "https://docs.ochk.io"
2298
+ },
2299
+ {
2300
+ slug: "fleet",
2301
+ href: "https://fleet.ochk.io",
2302
+ label: "oc\xB7fleet",
2303
+ sub: "managed \u2014 agent fleet",
2304
+ docsHref: "https://docs.ochk.io/fleet"
2305
+ },
2306
+ {
2307
+ slug: "me",
2308
+ href: "https://me.ochk.io",
2309
+ label: "oc\xB7me",
2310
+ sub: "earn \u2014 consumer identity",
2311
+ docsHref: "https://docs.ochk.io/me"
2312
+ },
2313
+ {
2314
+ slug: "vault",
2315
+ href: "https://vault.ochk.io",
2316
+ label: "oc\xB7vault",
2317
+ sub: "keep \u2014 encrypted secrets",
2318
+ docsHref: "https://docs.ochk.io/vault"
2319
+ },
2320
+ {
2321
+ slug: "attest",
2322
+ href: "https://attest.ochk.io",
2323
+ label: "oc\xB7attest",
2324
+ sub: "am \u2014 sybil resistance",
2325
+ docsHref: "https://docs.ochk.io/attest"
2326
+ },
2327
+ {
2328
+ slug: "lock",
2329
+ href: "https://lock.ochk.io",
2330
+ label: "oc\xB7lock",
2331
+ sub: "whisper \u2014 encryption",
2332
+ docsHref: "https://docs.ochk.io/lock"
2333
+ },
2334
+ {
2335
+ slug: "vote",
2336
+ href: "https://vote.ochk.io",
2337
+ label: "oc\xB7vote",
2338
+ sub: "decide \u2014 polls",
2339
+ docsHref: "https://docs.ochk.io/vote"
2340
+ },
2341
+ {
2342
+ slug: "stamp",
2343
+ href: "https://stamp.ochk.io",
2344
+ label: "oc\xB7stamp",
2345
+ sub: "declare \u2014 block-anchored",
2346
+ docsHref: "https://docs.ochk.io/stamp"
2347
+ },
2348
+ {
2349
+ slug: "agent",
2350
+ href: "https://agent.ochk.io",
2351
+ label: "oc\xB7agent",
2352
+ sub: "delegate \u2014 scoped auth",
2353
+ docsHref: "https://docs.ochk.io/agent"
2354
+ },
2355
+ {
2356
+ slug: "pledge",
2357
+ href: "https://pledge.ochk.io",
2358
+ label: "oc\xB7pledge",
2359
+ sub: "swear \u2014 bonded commitment",
2360
+ docsHref: "https://docs.ochk.io/pledge"
2361
+ }
2362
+ ];
2363
+ var OWNER_ENTRIES = [
2364
+ {
2365
+ slug: "analytics",
2366
+ href: "https://analytics.ochk.io",
2367
+ label: "oc\xB7analytics",
2368
+ sub: "owner cockpit",
2369
+ docsHref: "https://analytics.ochk.io"
2370
+ }
2371
+ ];
2372
+ function EcosystemSwitcher({
2373
+ current,
2374
+ className,
2375
+ showOwnerEntries = false
2376
+ }) {
2377
+ const [open, setOpen] = React2.useState(false);
2378
+ const containerRef = React2.useRef(null);
2379
+ React2.useEffect(() => {
2380
+ if (!open) return;
2381
+ function onDoc(e) {
2382
+ if (!containerRef.current) return;
2383
+ if (!containerRef.current.contains(e.target)) setOpen(false);
2384
+ }
2385
+ function onKey(e) {
2386
+ if (e.key === "Escape") setOpen(false);
2387
+ }
2388
+ document.addEventListener("mousedown", onDoc);
2389
+ document.addEventListener("keydown", onKey);
2390
+ return () => {
2391
+ document.removeEventListener("mousedown", onDoc);
2392
+ document.removeEventListener("keydown", onKey);
2393
+ };
2394
+ }, [open]);
2395
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: "relative " + (className ?? ""), children: [
2396
+ /* @__PURE__ */ jsxRuntime.jsxs(
2397
+ "button",
2398
+ {
2399
+ type: "button",
2400
+ "aria-haspopup": "menu",
2401
+ "aria-expanded": open,
2402
+ "aria-label": "Switch OrangeCheck product",
2403
+ title: "Switch product",
2404
+ onClick: () => setOpen((v) => !v),
2405
+ className: "inline-flex items-center gap-1 px-2 py-1 transition-colors " + (open ? "text-foreground" : "text-muted-foreground hover:text-foreground"),
2406
+ children: [
2407
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Boxes, { className: "h-4 w-4" }),
2408
+ /* @__PURE__ */ jsxRuntime.jsx(
2409
+ lucideReact.ChevronDown,
2410
+ {
2411
+ className: "h-3.5 w-3.5 transition-transform " + (open ? "rotate-180" : "")
2412
+ }
2413
+ )
2414
+ ]
2415
+ }
2416
+ ),
2417
+ open && /* @__PURE__ */ jsxRuntime.jsxs(
2418
+ "div",
2419
+ {
2420
+ role: "menu",
2421
+ "aria-label": "Switch OrangeCheck product",
2422
+ className: "bg-background absolute right-0 top-full z-[60] mt-2 w-72 border shadow-lg",
2423
+ children: [
2424
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-primary border-b px-4 py-2", children: "\xA7 the family" }),
2425
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "py-1", children: [...ENTRIES, ...showOwnerEntries ? OWNER_ENTRIES : []].map((e) => {
2426
+ const isActive2 = e.slug === current;
2427
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
2428
+ Link6__default.default,
2429
+ {
2430
+ href: e.href,
2431
+ onClick: () => setOpen(false),
2432
+ "aria-current": isActive2 ? "page" : void 0,
2433
+ className: "group flex items-baseline gap-3 px-4 py-2 transition-colors " + (isActive2 ? "bg-primary/5" : "hover:bg-muted"),
2434
+ children: [
2435
+ /* @__PURE__ */ jsxRuntime.jsx(
2436
+ "span",
2437
+ {
2438
+ className: "font-display flex-1 text-[12px] font-semibold tracking-tight " + (isActive2 ? "text-primary" : "text-foreground group-hover:text-primary transition-colors"),
2439
+ children: e.label
2440
+ }
2441
+ ),
2442
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground font-mono text-[10px] tracking-wider uppercase", children: e.sub }),
2443
+ isActive2 && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "text-primary h-3 w-3" })
2444
+ ]
2445
+ }
2446
+ ) }, e.slug);
2447
+ }) }),
2448
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t px-4 py-2 font-mono text-[10px] tracking-widest uppercase", children: /* @__PURE__ */ jsxRuntime.jsx(
2449
+ Link6__default.default,
2450
+ {
2451
+ href: "https://docs.ochk.io",
2452
+ onClick: () => setOpen(false),
2453
+ className: "text-muted-foreground hover:text-foreground inline-block transition-colors",
2454
+ children: "docs.ochk.io \u2192"
2455
+ }
2456
+ ) })
2457
+ ]
2458
+ }
2459
+ )
2460
+ ] });
2461
+ }
2122
2462
 
2123
- // src/components/index.ts
2124
- var components_exports = {};
2125
- __reExport(components_exports, ui_star__namespace);
2126
-
2127
- // src/index.ts
2128
- __reExport(src_exports, components_exports);
2463
+ // src/chrome/family-properties.ts
2464
+ var FAMILY_PROPERTIES = [
2465
+ {
2466
+ slug: "home",
2467
+ origin: "https://ochk.io",
2468
+ hostname: "ochk.io",
2469
+ label: "orangecheck",
2470
+ sub: "umbrella \xB7 sign-in",
2471
+ docsHref: "https://docs.ochk.io",
2472
+ category: "hub"
2473
+ },
2474
+ {
2475
+ slug: "docs",
2476
+ origin: "https://docs.ochk.io",
2477
+ hostname: "docs.ochk.io",
2478
+ label: "oc\xB7docs",
2479
+ sub: "unified reference",
2480
+ docsHref: "https://docs.ochk.io",
2481
+ category: "hub"
2482
+ },
2483
+ {
2484
+ slug: "me",
2485
+ origin: "https://me.ochk.io",
2486
+ hostname: "me.ochk.io",
2487
+ label: "oc\xB7me",
2488
+ sub: "earn \u2014 consumer identity",
2489
+ docsHref: "https://docs.ochk.io/me",
2490
+ category: "product"
2491
+ },
2492
+ {
2493
+ slug: "vault",
2494
+ origin: "https://vault.ochk.io",
2495
+ hostname: "vault.ochk.io",
2496
+ label: "oc\xB7vault",
2497
+ sub: "keep \u2014 encrypted secrets",
2498
+ docsHref: "https://docs.ochk.io/vault",
2499
+ category: "product"
2500
+ },
2501
+ {
2502
+ slug: "fleet",
2503
+ origin: "https://fleet.ochk.io",
2504
+ hostname: "fleet.ochk.io",
2505
+ label: "oc\xB7fleet",
2506
+ sub: "managed \u2014 agent fleet",
2507
+ docsHref: "https://docs.ochk.io/fleet",
2508
+ category: "product"
2509
+ },
2510
+ {
2511
+ slug: "attest",
2512
+ origin: "https://attest.ochk.io",
2513
+ hostname: "attest.ochk.io",
2514
+ label: "oc\xB7attest",
2515
+ sub: "am \u2014 sybil resistance",
2516
+ docsHref: "https://docs.ochk.io/attest",
2517
+ category: "protocol"
2518
+ },
2519
+ {
2520
+ slug: "lock",
2521
+ origin: "https://lock.ochk.io",
2522
+ hostname: "lock.ochk.io",
2523
+ label: "oc\xB7lock",
2524
+ sub: "whisper \u2014 encryption",
2525
+ docsHref: "https://docs.ochk.io/lock",
2526
+ category: "protocol"
2527
+ },
2528
+ {
2529
+ slug: "vote",
2530
+ origin: "https://vote.ochk.io",
2531
+ hostname: "vote.ochk.io",
2532
+ label: "oc\xB7vote",
2533
+ sub: "decide \u2014 polls",
2534
+ docsHref: "https://docs.ochk.io/vote",
2535
+ category: "protocol"
2536
+ },
2537
+ {
2538
+ slug: "stamp",
2539
+ origin: "https://stamp.ochk.io",
2540
+ hostname: "stamp.ochk.io",
2541
+ label: "oc\xB7stamp",
2542
+ sub: "declare \u2014 block-anchored",
2543
+ docsHref: "https://docs.ochk.io/stamp",
2544
+ category: "protocol"
2545
+ },
2546
+ {
2547
+ slug: "agent",
2548
+ origin: "https://agent.ochk.io",
2549
+ hostname: "agent.ochk.io",
2550
+ label: "oc\xB7agent",
2551
+ sub: "delegate \u2014 scoped auth",
2552
+ docsHref: "https://docs.ochk.io/agent",
2553
+ category: "protocol"
2554
+ },
2555
+ {
2556
+ slug: "pledge",
2557
+ origin: "https://pledge.ochk.io",
2558
+ hostname: "pledge.ochk.io",
2559
+ label: "oc\xB7pledge",
2560
+ sub: "swear \u2014 bonded commitment",
2561
+ docsHref: "https://docs.ochk.io/pledge",
2562
+ category: "protocol"
2563
+ },
2564
+ {
2565
+ slug: "analytics",
2566
+ origin: "https://analytics.ochk.io",
2567
+ hostname: "analytics.ochk.io",
2568
+ label: "oc\xB7analytics",
2569
+ sub: "owner cockpit",
2570
+ docsHref: "https://analytics.ochk.io",
2571
+ category: "owner"
2572
+ }
2573
+ ];
2574
+ var SITE_STATE_LABEL = {
2575
+ alpha: "alpha",
2576
+ beta: "beta"
2577
+ };
2578
+ function findFamilyProperty(slug) {
2579
+ return FAMILY_PROPERTIES.find((p) => p.slug === slug);
2580
+ }
2581
+ var SECTIONS = [
2582
+ { category: "hub", label: "hub" },
2583
+ { category: "product", label: "products" },
2584
+ { category: "protocol", label: "protocols" },
2585
+ { category: "owner", label: "owner" }
2586
+ ];
2587
+ function CategoryChip({ category }) {
2588
+ if (category === "hub") return null;
2589
+ const label = category === "product" ? "product" : category === "protocol" ? "protocol" : "owner";
2590
+ const tone = category === "product" ? "border-primary/25 bg-primary/10 text-primary" : category === "protocol" ? "border-muted-foreground/20 bg-muted/40 text-muted-foreground/85" : "border-warning/30 bg-warning/10 text-warning";
2591
+ return /* @__PURE__ */ jsxRuntime.jsx(
2592
+ "span",
2593
+ {
2594
+ "aria-label": category === "product" ? "commercial product" : category === "protocol" ? "protocol reference" : "owner-only surface",
2595
+ className: "ml-1 hidden rounded-sm border px-1.5 py-[1px] font-mono text-[9px] font-medium tracking-widest uppercase sm:inline-block " + tone,
2596
+ "data-oc-category": category,
2597
+ children: label
2598
+ }
2599
+ );
2600
+ }
2601
+ function SiteStateBadge({ state }) {
2602
+ if (state === "live") return null;
2603
+ return /* @__PURE__ */ jsxRuntime.jsx(
2604
+ "span",
2605
+ {
2606
+ "aria-label": `site lifecycle: ${state}`,
2607
+ className: "text-muted-foreground/70 ml-1 hidden font-mono text-[9px] font-medium tracking-widest uppercase sm:inline-block",
2608
+ "data-oc-site-state": state,
2609
+ children: SITE_STATE_LABEL[state]
2610
+ }
2611
+ );
2612
+ }
2613
+ function MenuCategoryChip({ category }) {
2614
+ if (category === "hub") return null;
2615
+ const label = category === "product" ? "pro" : category === "protocol" ? "spec" : "own";
2616
+ const tone = category === "product" ? "bg-primary/10 text-primary" : category === "protocol" ? "bg-muted/60 text-muted-foreground/80" : "bg-warning/15 text-warning";
2617
+ return /* @__PURE__ */ jsxRuntime.jsx(
2618
+ "span",
2619
+ {
2620
+ "aria-hidden": true,
2621
+ className: "inline-block shrink-0 rounded-sm px-1 py-[1px] font-mono text-[9px] font-medium tracking-widest uppercase " + tone,
2622
+ children: label
2623
+ }
2624
+ );
2625
+ }
2626
+ function OcLogoDropdown({
2627
+ current,
2628
+ homeHref = "/",
2629
+ siteState = "live",
2630
+ children,
2631
+ className,
2632
+ triggerClassName,
2633
+ popoverClassName,
2634
+ showOwnerEntries = false
2635
+ }) {
2636
+ const [open, setOpen] = React2.useState(false);
2637
+ const containerRef = React2.useRef(null);
2638
+ const menuId = React2.useId();
2639
+ const router$1 = router.useRouter();
2640
+ const currentCategory = findFamilyProperty(current)?.category ?? "hub";
2641
+ function handleTriggerClick(e) {
2642
+ if (e.detail >= 2) {
2643
+ e.preventDefault();
2644
+ setOpen(false);
2645
+ void router$1.push(homeHref);
2646
+ return;
2647
+ }
2648
+ setOpen((v) => !v);
2649
+ }
2650
+ React2.useEffect(() => {
2651
+ if (!open) return;
2652
+ function onDoc(e) {
2653
+ if (!containerRef.current) return;
2654
+ if (!containerRef.current.contains(e.target)) setOpen(false);
2655
+ }
2656
+ function onKey(e) {
2657
+ if (e.key === "Escape") setOpen(false);
2658
+ }
2659
+ document.addEventListener("mousedown", onDoc);
2660
+ document.addEventListener("keydown", onKey);
2661
+ return () => {
2662
+ document.removeEventListener("mousedown", onDoc);
2663
+ document.removeEventListener("keydown", onKey);
2664
+ };
2665
+ }, [open]);
2666
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2667
+ "div",
2668
+ {
2669
+ ref: containerRef,
2670
+ className: "relative inline-flex items-center " + (className ?? ""),
2671
+ "data-oc-logo-dropdown": "",
2672
+ "data-oc-current-category": currentCategory,
2673
+ "data-oc-site-state": siteState,
2674
+ children: [
2675
+ /* @__PURE__ */ jsxRuntime.jsxs(
2676
+ "button",
2677
+ {
2678
+ type: "button",
2679
+ "aria-haspopup": "menu",
2680
+ "aria-expanded": open,
2681
+ "aria-controls": menuId,
2682
+ "aria-label": "OrangeCheck family \xB7 click to open property menu, double-click to go home",
2683
+ title: "single-click \xB7 family menu \xB7 double-click \xB7 go home",
2684
+ onClick: handleTriggerClick,
2685
+ className: triggerClassName ?? "group hover:bg-accent/30 -mx-1.5 -my-1 flex min-h-[40px] items-center gap-2 rounded-sm px-1.5 py-1 transition-colors " + (open ? "bg-accent/20" : ""),
2686
+ "data-oc-logo-dropdown-trigger": "",
2687
+ "data-oc-logo-dropdown-open": open ? "true" : "false",
2688
+ children: [
2689
+ children,
2690
+ /* @__PURE__ */ jsxRuntime.jsx(CategoryChip, { category: currentCategory }),
2691
+ /* @__PURE__ */ jsxRuntime.jsx(SiteStateBadge, { state: siteState }),
2692
+ /* @__PURE__ */ jsxRuntime.jsx(
2693
+ lucideReact.ChevronDown,
2694
+ {
2695
+ "aria-hidden": true,
2696
+ className: "text-muted-foreground/70 group-hover:text-foreground/80 h-3.5 w-3.5 shrink-0 transition-transform duration-200 " + (open ? "rotate-180" : "")
2697
+ }
2698
+ )
2699
+ ]
2700
+ }
2701
+ ),
2702
+ /* @__PURE__ */ jsxRuntime.jsxs(
2703
+ Link6__default.default,
2704
+ {
2705
+ href: homeHref,
2706
+ "aria-label": "go to " + homeHref + " (this site's home)",
2707
+ onClick: () => setOpen(false),
2708
+ tabIndex: open ? 0 : -1,
2709
+ className: "hover:text-primary group/home -ml-1 hidden items-center gap-1 rounded-sm px-1.5 py-1 font-mono text-[9px] tracking-widest uppercase transition-all duration-200 sm:inline-flex " + (open ? "pointer-events-auto translate-x-0 text-muted-foreground/70 opacity-100 hover:bg-accent/30" : "pointer-events-none -translate-x-1 opacity-0"),
2710
+ "data-oc-logo-dropdown-home-hint": "",
2711
+ children: [
2712
+ /* @__PURE__ */ jsxRuntime.jsx(
2713
+ lucideReact.CornerDownLeft,
2714
+ {
2715
+ "aria-hidden": true,
2716
+ className: "h-3 w-3 group-hover/home:text-primary " + (open ? "motion-safe:animate-pulse" : "")
2717
+ }
2718
+ ),
2719
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary/70 group-hover/home:text-primary", children: "home" })
2720
+ ]
2721
+ }
2722
+ ),
2723
+ open && /* @__PURE__ */ jsxRuntime.jsxs(
2724
+ "div",
2725
+ {
2726
+ id: menuId,
2727
+ role: "menu",
2728
+ "aria-label": "OrangeCheck family",
2729
+ className: popoverClassName ?? "bg-background absolute top-full left-0 z-[60] mt-2 w-[min(20rem,calc(100vw-1rem))] border shadow-lg",
2730
+ "data-oc-logo-dropdown-popover": "",
2731
+ children: [
2732
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-primary border-b px-4 py-2", children: "\xA7 the orangecheck family" }),
2733
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-[min(28rem,70vh)] overflow-y-auto py-1", role: "none", children: SECTIONS.map(({ category, label }) => {
2734
+ if (category === "owner" && !showOwnerEntries) return null;
2735
+ const sectionEntries = FAMILY_PROPERTIES.filter(
2736
+ (e) => e.category === category
2737
+ );
2738
+ if (sectionEntries.length === 0) return null;
2739
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "none", "data-oc-section": category, children: [
2740
+ /* @__PURE__ */ jsxRuntime.jsx(
2741
+ "div",
2742
+ {
2743
+ role: "separator",
2744
+ "aria-hidden": true,
2745
+ className: "text-muted-foreground/60 px-4 pt-2.5 pb-1 font-mono text-[9px] font-medium tracking-widest uppercase " + (category === "hub" ? "" : "border-t mt-1"),
2746
+ children: label
2747
+ }
2748
+ ),
2749
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "none", className: "pb-1", children: sectionEntries.map((e) => {
2750
+ const isActive2 = e.slug === current;
2751
+ const href = isActive2 ? homeHref : e.origin;
2752
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { role: "none", children: /* @__PURE__ */ jsxRuntime.jsxs(
2753
+ Link6__default.default,
2754
+ {
2755
+ href,
2756
+ role: "menuitem",
2757
+ onClick: () => setOpen(false),
2758
+ "aria-current": isActive2 ? "page" : void 0,
2759
+ className: "group flex items-center gap-2 px-4 py-2 transition-colors " + (isActive2 ? "bg-primary/8 border-primary -ml-px border-l-2" : "hover:bg-muted -ml-px border-l-2 border-transparent"),
2760
+ "data-oc-logo-dropdown-item": isActive2 ? "current" : "sibling",
2761
+ "data-oc-entry-category": e.category,
2762
+ children: [
2763
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
2764
+ /* @__PURE__ */ jsxRuntime.jsx(
2765
+ "span",
2766
+ {
2767
+ className: "font-display text-[12px] font-semibold tracking-tight " + (isActive2 ? "text-primary" : "text-foreground group-hover:text-primary transition-colors"),
2768
+ children: e.label
2769
+ }
2770
+ ),
2771
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground mt-0.5 font-mono text-[10px] tracking-wide", children: e.sub })
2772
+ ] }),
2773
+ /* @__PURE__ */ jsxRuntime.jsx(MenuCategoryChip, { category: e.category }),
2774
+ isActive2 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-primary inline-flex shrink-0 items-center gap-1 font-mono text-[10px] tracking-widest uppercase", children: [
2775
+ "home",
2776
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" })
2777
+ ] }) : null
2778
+ ]
2779
+ }
2780
+ ) }, e.slug);
2781
+ }) })
2782
+ ] }, category);
2783
+ }) }),
2784
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t px-4 py-2 font-mono text-[10px] tracking-widest uppercase", children: /* @__PURE__ */ jsxRuntime.jsx(
2785
+ Link6__default.default,
2786
+ {
2787
+ href: "https://docs.ochk.io",
2788
+ onClick: () => setOpen(false),
2789
+ className: "text-muted-foreground hover:text-foreground inline-block transition-colors",
2790
+ children: "docs.ochk.io \u2192"
2791
+ }
2792
+ ) })
2793
+ ]
2794
+ }
2795
+ )
2796
+ ]
2797
+ }
2798
+ );
2799
+ }
2800
+ function obscureIdentity(value) {
2801
+ if (value.length <= 12) {
2802
+ return `${value.slice(0, 4)}\u2026${value.slice(-3)}`;
2803
+ }
2804
+ return `${value.slice(0, 6)}\u2026${value.slice(-4)}`;
2805
+ }
2806
+ var IDENTITY_KIND_LABEL = {
2807
+ did: "did:oc",
2808
+ btc: "bitcoin",
2809
+ email: "email",
2810
+ nostr: "nostr"
2811
+ };
2812
+ async function writeClipboard(text) {
2813
+ try {
2814
+ if (navigator.clipboard?.writeText) {
2815
+ await navigator.clipboard.writeText(text);
2816
+ return true;
2817
+ }
2818
+ } catch {
2819
+ }
2820
+ try {
2821
+ const ta = document.createElement("textarea");
2822
+ ta.value = text;
2823
+ ta.setAttribute("readonly", "");
2824
+ ta.style.position = "fixed";
2825
+ ta.style.top = "-1000px";
2826
+ ta.style.opacity = "0";
2827
+ document.body.appendChild(ta);
2828
+ ta.select();
2829
+ const ok = document.execCommand("copy");
2830
+ document.body.removeChild(ta);
2831
+ return ok;
2832
+ } catch {
2833
+ return false;
2834
+ }
2835
+ }
2836
+ function CopyableDid({ did }) {
2837
+ const [copied, setCopied] = React2.useState(false);
2838
+ const timerRef = React2.useRef(null);
2839
+ React2.useEffect(
2840
+ () => () => {
2841
+ if (timerRef.current) clearTimeout(timerRef.current);
2842
+ },
2843
+ []
2844
+ );
2845
+ const onCopy = async () => {
2846
+ const ok = await writeClipboard(did);
2847
+ if (!ok) return;
2848
+ setCopied(true);
2849
+ if (timerRef.current) clearTimeout(timerRef.current);
2850
+ timerRef.current = setTimeout(() => setCopied(false), 1600);
2851
+ };
2852
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2853
+ "button",
2854
+ {
2855
+ type: "button",
2856
+ onClick: onCopy,
2857
+ "aria-label": copied ? "OrangeCheck identity copied to clipboard" : `Copy OrangeCheck identity ${did} to clipboard`,
2858
+ title: "Copy identity",
2859
+ "data-oc-account-menu-copy-did": "",
2860
+ "data-copied": copied ? "" : void 0,
2861
+ className: "group/did hover:bg-accent focus-visible:ring-ring/60 -mx-1.5 mt-px flex w-[calc(100%+0.75rem)] items-start gap-1.5 rounded px-1.5 py-1 text-left transition-colors focus-visible:ring-2 focus-visible:outline-none",
2862
+ children: [
2863
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground/90 min-w-0 flex-1 font-mono text-[11px] leading-tight break-all", children: did }),
2864
+ /* @__PURE__ */ jsxRuntime.jsx(
2865
+ "span",
2866
+ {
2867
+ className: "mt-px shrink-0 transition-colors " + (copied ? "text-primary" : "text-muted-foreground/50 group-hover/did:text-foreground/80"),
2868
+ "aria-hidden": true,
2869
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "size-3.5" })
2870
+ }
2871
+ ),
2872
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", "aria-live": "polite", children: copied ? "Copied to clipboard" : "" })
2873
+ ]
2874
+ }
2875
+ );
2876
+ }
2877
+ function PromoteRow({
2878
+ kind,
2879
+ value,
2880
+ active,
2881
+ busy,
2882
+ disabled,
2883
+ onPromote
2884
+ }) {
2885
+ const [copied, setCopied] = React2.useState(false);
2886
+ const timerRef = React2.useRef(null);
2887
+ React2.useEffect(
2888
+ () => () => {
2889
+ if (timerRef.current) clearTimeout(timerRef.current);
2890
+ },
2891
+ []
2892
+ );
2893
+ const onCopy = async () => {
2894
+ const ok = await writeClipboard(value);
2895
+ if (!ok) return;
2896
+ setCopied(true);
2897
+ if (timerRef.current) clearTimeout(timerRef.current);
2898
+ timerRef.current = setTimeout(() => setCopied(false), 1600);
2899
+ };
2900
+ const kindLabel = IDENTITY_KIND_LABEL[kind];
2901
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2902
+ "div",
2903
+ {
2904
+ className: "hover:bg-accent flex items-center gap-1 pr-2 transition-colors",
2905
+ "data-oc-account-menu-promote-row": kind,
2906
+ "data-active": active ? "" : void 0,
2907
+ children: [
2908
+ /* @__PURE__ */ jsxRuntime.jsxs(
2909
+ "button",
2910
+ {
2911
+ type: "button",
2912
+ role: "menuitemradio",
2913
+ "aria-checked": active,
2914
+ "aria-label": active ? `Showing as ${kindLabel}` : `Show as ${kindLabel}`,
2915
+ disabled: disabled || active,
2916
+ onClick: onPromote,
2917
+ "data-oc-account-menu-promote": kind,
2918
+ className: "flex min-w-0 flex-1 items-center gap-2 py-2 pl-3 text-left font-mono text-[11px] tracking-wide disabled:cursor-default",
2919
+ children: [
2920
+ /* @__PURE__ */ jsxRuntime.jsx(
2921
+ "span",
2922
+ {
2923
+ className: "flex size-3.5 shrink-0 items-center justify-center rounded-full border " + (active ? "border-primary" : "border-muted-foreground/40"),
2924
+ "aria-hidden": true,
2925
+ children: active ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary size-1.5 rounded-full" }) : null
2926
+ }
2927
+ ),
2928
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground/90 min-w-0 flex-1 truncate", children: obscureIdentity(value) })
2929
+ ]
2930
+ }
2931
+ ),
2932
+ /* @__PURE__ */ jsxRuntime.jsx(
2933
+ "button",
2934
+ {
2935
+ type: "button",
2936
+ onClick: () => void onCopy(),
2937
+ "aria-label": copied ? `${kindLabel} copied to clipboard` : `Copy ${kindLabel} to clipboard`,
2938
+ title: "Copy",
2939
+ "data-oc-account-menu-promote-copy": kind,
2940
+ "data-copied": copied ? "" : void 0,
2941
+ className: "hover:bg-background/70 focus-visible:ring-ring/60 flex size-6 shrink-0 items-center justify-center rounded transition-colors focus-visible:ring-2 focus-visible:outline-none",
2942
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "text-primary size-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "text-muted-foreground/50 size-3.5" })
2943
+ }
2944
+ ),
2945
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 w-14 shrink-0 text-right text-[9px] tracking-widest uppercase", children: busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "ml-auto size-3 animate-spin" }) : kindLabel }),
2946
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", "aria-live": "polite", children: copied ? "Copied to clipboard" : "" })
2947
+ ]
2948
+ }
2949
+ );
2950
+ }
2951
+ function IdentityPromoteSection({
2952
+ didOc,
2953
+ nostrNpub,
2954
+ current,
2955
+ open,
2956
+ setDisplayIdentity
2957
+ }) {
2958
+ const [identities, setIdentities] = React2.useState(null);
2959
+ const [loadFailed, setLoadFailed] = React2.useState(false);
2960
+ const [promoting, setPromoting] = React2.useState(null);
2961
+ const [promoteErr, setPromoteErr] = React2.useState(null);
2962
+ const lastFetchKeyRef = React2.useRef(null);
2963
+ React2.useEffect(() => {
2964
+ if (!open) return;
2965
+ if (lastFetchKeyRef.current === didOc) return;
2966
+ lastFetchKeyRef.current = didOc;
2967
+ let cancelled = false;
2968
+ setIdentities(null);
2969
+ setLoadFailed(false);
2970
+ void authClient.fetchOcLinkedIdentities().then((rows) => {
2971
+ if (!cancelled) setIdentities(rows);
2972
+ }).catch(() => {
2973
+ if (!cancelled) setLoadFailed(true);
2974
+ });
2975
+ return () => {
2976
+ cancelled = true;
2977
+ };
2978
+ }, [open, didOc]);
2979
+ if (identities === null && !loadFailed) return null;
2980
+ const btc = identities?.find((i) => i.kind === "btc" && i.is_primary && i.value) ?? identities?.find((i) => i.kind === "btc" && i.value);
2981
+ const email = identities?.find((i) => i.kind === "email" && i.is_primary && i.value) ?? identities?.find((i) => i.kind === "email" && i.value);
2982
+ const options = [
2983
+ { kind: "did", value: didOc }
2984
+ ];
2985
+ if (btc?.value) options.push({ kind: "btc", value: btc.value });
2986
+ if (email?.value) options.push({ kind: "email", value: email.value });
2987
+ if (nostrNpub) options.push({ kind: "nostr", value: nostrNpub });
2988
+ if (options.length < 2) return null;
2989
+ const promote = async (kind) => {
2990
+ if (promoting || kind === current.kind) return;
2991
+ setPromoting(kind);
2992
+ setPromoteErr(null);
2993
+ try {
2994
+ await setDisplayIdentity(kind);
2995
+ } catch (e) {
2996
+ setPromoteErr(e instanceof Error ? e.message : "promotion failed");
2997
+ } finally {
2998
+ setPromoting(null);
2999
+ }
3000
+ };
3001
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border border-b p-1", "data-oc-account-menu-section": "show-as", children: [
3002
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 show as" }),
3003
+ options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
3004
+ PromoteRow,
3005
+ {
3006
+ kind: opt.kind,
3007
+ value: opt.value,
3008
+ active: opt.kind === current.kind,
3009
+ busy: promoting === opt.kind,
3010
+ disabled: promoting !== null,
3011
+ onPromote: () => void promote(opt.kind)
3012
+ },
3013
+ opt.kind
3014
+ )),
3015
+ promoteErr ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-destructive/80 px-3 pt-1 pb-2 font-mono text-[10px]", children: promoteErr }) : null
3016
+ ] });
3017
+ }
3018
+ function OcAccountMenu(props) {
3019
+ const session = authClient.useOcSession();
3020
+ return /* @__PURE__ */ jsxRuntime.jsx(
3021
+ OcAccountMenuView,
3022
+ {
3023
+ ...props,
3024
+ session: {
3025
+ status: session.status,
3026
+ account: session.account ? {
3027
+ didOc: session.account.didOc,
3028
+ displayName: session.account.displayName ?? null,
3029
+ displayIdentity: session.account.displayIdentity,
3030
+ nostrNpub: session.account.nostrNpub ?? null
3031
+ } : null,
3032
+ signOut: session.signOut,
3033
+ refresh: session.refresh,
3034
+ setDisplayIdentity: session.setDisplayIdentity,
3035
+ // Multi-account · the connected variant always forwards
3036
+ // these from useOcSession(). The View variant accepts
3037
+ // them as optional so sites running their own auth
3038
+ // context (oc-www) can opt in incrementally.
3039
+ roster: session.roster,
3040
+ switchAccount: session.switchAccount,
3041
+ addAccountUrl: session.addAccountUrl
3042
+ }
3043
+ }
3044
+ );
3045
+ }
3046
+ function OcAccountMenuView({
3047
+ current,
3048
+ signInUrl = "/signin",
3049
+ signInLabel = "sign in",
3050
+ signOutRedirect = "/",
3051
+ menuItems,
3052
+ primaryNavLinks,
3053
+ secondaryNavLinks,
3054
+ showFamilyDashboard,
3055
+ build,
3056
+ siteState,
3057
+ className,
3058
+ triggerClassName,
3059
+ popoverClassName,
3060
+ session
3061
+ }) {
3062
+ const {
3063
+ status,
3064
+ account,
3065
+ signOut,
3066
+ refresh,
3067
+ setDisplayIdentity,
3068
+ roster,
3069
+ switchAccount,
3070
+ addAccountUrl
3071
+ } = session;
3072
+ const [hydrated, setHydrated] = React2.useState(false);
3073
+ const [open, setOpen] = React2.useState(false);
3074
+ const wrapRef = React2.useRef(null);
3075
+ const property = findFamilyProperty(current);
3076
+ const hostname = property?.hostname ?? `${current}.ochk.io`;
3077
+ const isHome = current === "home";
3078
+ const familyDashboardEnabled = showFamilyDashboard ?? !isHome;
3079
+ React2.useEffect(() => setHydrated(true), []);
3080
+ React2.useEffect(() => {
3081
+ const onWake = () => {
3082
+ if (document.visibilityState === "visible") void refresh();
3083
+ };
3084
+ const onFocus = () => void refresh();
3085
+ document.addEventListener("visibilitychange", onWake);
3086
+ window.addEventListener("focus", onFocus);
3087
+ return () => {
3088
+ document.removeEventListener("visibilitychange", onWake);
3089
+ window.removeEventListener("focus", onFocus);
3090
+ };
3091
+ }, [refresh]);
3092
+ React2.useEffect(() => {
3093
+ if (!open) return;
3094
+ const onClick = (e) => {
3095
+ if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
3096
+ };
3097
+ const onKey = (e) => {
3098
+ if (e.key === "Escape") setOpen(false);
3099
+ };
3100
+ document.addEventListener("mousedown", onClick);
3101
+ document.addEventListener("keydown", onKey);
3102
+ return () => {
3103
+ document.removeEventListener("mousedown", onClick);
3104
+ document.removeEventListener("keydown", onKey);
3105
+ };
3106
+ }, [open]);
3107
+ const signInTrigger = /* @__PURE__ */ jsxRuntime.jsx(
3108
+ "a",
3109
+ {
3110
+ href: signInUrl,
3111
+ "aria-label": signInLabel,
3112
+ "data-oc-account-menu-signin": "",
3113
+ className: triggerClassName ?? "border-input bg-background hover:bg-accent inline-flex h-8 items-center justify-center rounded-md border px-3 font-mono text-[11px] font-semibold tracking-widest uppercase transition-colors",
3114
+ children: signInLabel
3115
+ }
3116
+ );
3117
+ if (!hydrated || status === "loading") {
3118
+ return signInTrigger;
3119
+ }
3120
+ if (status !== "authenticated" || !account) {
3121
+ return signInTrigger;
3122
+ }
3123
+ const displayName = account.displayName ?? null;
3124
+ const label = displayName ?? obscureIdentity(account.displayIdentity.value);
3125
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3126
+ "div",
3127
+ {
3128
+ ref: wrapRef,
3129
+ className: "relative inline-block " + (className ?? ""),
3130
+ "data-oc-account-menu": "",
3131
+ children: [
3132
+ /* @__PURE__ */ jsxRuntime.jsxs(
3133
+ "button",
3134
+ {
3135
+ type: "button",
3136
+ onClick: () => setOpen((v) => !v),
3137
+ "aria-haspopup": "menu",
3138
+ "aria-expanded": open,
3139
+ "aria-label": `Signed in as ${account.didOc}. Open account menu.`,
3140
+ 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",
3141
+ "data-oc-account-menu-trigger": "",
3142
+ children: [
3143
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary inline-block size-1.5 rounded-full", "aria-hidden": true }),
3144
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: label }),
3145
+ /* @__PURE__ */ jsxRuntime.jsx(
3146
+ "svg",
3147
+ {
3148
+ width: "9",
3149
+ height: "9",
3150
+ viewBox: "0 0 10 10",
3151
+ "aria-hidden": true,
3152
+ className: "opacity-60 transition-transform " + (open ? "rotate-180" : "rotate-0"),
3153
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3154
+ "path",
3155
+ {
3156
+ d: "M2 4 L5 7 L8 4",
3157
+ stroke: "currentColor",
3158
+ strokeWidth: "1.5",
3159
+ fill: "none",
3160
+ strokeLinecap: "round"
3161
+ }
3162
+ )
3163
+ }
3164
+ )
3165
+ ]
3166
+ }
3167
+ ),
3168
+ open && /* @__PURE__ */ jsxRuntime.jsxs(
3169
+ "div",
3170
+ {
3171
+ role: "menu",
3172
+ "aria-label": "Account menu",
3173
+ 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",
3174
+ "data-oc-account-menu-popover": "",
3175
+ children: [
3176
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border border-b p-3", children: [
3177
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-primary mb-1 font-mono text-[10px] tracking-widest uppercase", children: [
3178
+ "\xA7 signed in \xB7 ",
3179
+ hostname
3180
+ ] }),
3181
+ /* @__PURE__ */ jsxRuntime.jsx(CopyableDid, { did: account.didOc }),
3182
+ displayName ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/80 mt-1 font-mono text-[10px] tracking-wide", children: displayName }) : null
3183
+ ] }),
3184
+ /* @__PURE__ */ jsxRuntime.jsx(
3185
+ IdentityPromoteSection,
3186
+ {
3187
+ didOc: account.didOc,
3188
+ nostrNpub: account.nostrNpub ?? null,
3189
+ current: account.displayIdentity,
3190
+ open,
3191
+ setDisplayIdentity
3192
+ }
3193
+ ),
3194
+ /* @__PURE__ */ jsxRuntime.jsx(
3195
+ AccountsSection,
3196
+ {
3197
+ roster: roster ?? [],
3198
+ switchAccount,
3199
+ addAccountUrl,
3200
+ signOut,
3201
+ onActionStart: () => setOpen(false)
3202
+ }
3203
+ ),
3204
+ primaryNavLinks && primaryNavLinks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
3205
+ PopoverSection,
3206
+ {
3207
+ label: "navigate",
3208
+ items: primaryNavLinks,
3209
+ onItemClick: () => setOpen(false)
3210
+ }
3211
+ ) : null,
3212
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-1", "data-oc-account-menu-section": "account", children: [
3213
+ primaryNavLinks && primaryNavLinks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/60 px-3 pb-1 pt-2 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 account" }) : null,
3214
+ menuItems?.map((item) => {
3215
+ const onClick = () => setOpen(false);
3216
+ const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
3217
+ const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3218
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
3219
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
3220
+ item.external ? /* @__PURE__ */ jsxRuntime.jsx(
3221
+ "span",
3222
+ {
3223
+ className: "text-muted-foreground/70 text-[10px]",
3224
+ "aria-hidden": true,
3225
+ children: "\u2197"
3226
+ }
3227
+ ) : null
3228
+ ] });
3229
+ return item.external ? /* @__PURE__ */ jsxRuntime.jsx(
3230
+ "a",
3231
+ {
3232
+ href: item.href,
3233
+ target: "_blank",
3234
+ rel: "noreferrer",
3235
+ onClick,
3236
+ role: "menuitem",
3237
+ className: cls,
3238
+ "data-oc-account-menu-item": "",
3239
+ children: inner
3240
+ },
3241
+ item.href
3242
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3243
+ Link6__default.default,
3244
+ {
3245
+ href: item.href,
3246
+ onClick,
3247
+ role: "menuitem",
3248
+ className: cls,
3249
+ "data-oc-account-menu-item": "",
3250
+ children: inner
3251
+ },
3252
+ item.href
3253
+ );
3254
+ }),
3255
+ familyDashboardEnabled ? /* @__PURE__ */ jsxRuntime.jsxs(
3256
+ "a",
3257
+ {
3258
+ href: "https://ochk.io/dashboard",
3259
+ target: "_blank",
3260
+ rel: "noreferrer",
3261
+ onClick: () => setOpen(false),
3262
+ role: "menuitem",
3263
+ className: "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors",
3264
+ "data-oc-account-menu-item": "",
3265
+ "data-oc-account-menu-family-dashboard": "",
3266
+ children: [
3267
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
3268
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: "family dashboard" }),
3269
+ /* @__PURE__ */ jsxRuntime.jsx(
3270
+ "span",
3271
+ {
3272
+ className: "text-muted-foreground/70 text-[10px]",
3273
+ "aria-hidden": true,
3274
+ children: "\u2197"
3275
+ }
3276
+ )
3277
+ ]
3278
+ }
3279
+ ) : null,
3280
+ /* @__PURE__ */ jsxRuntime.jsxs(
3281
+ "button",
3282
+ {
3283
+ type: "button",
3284
+ role: "menuitem",
3285
+ onClick: () => {
3286
+ setOpen(false);
3287
+ void (async () => {
3288
+ await signOut();
3289
+ if (typeof window !== "undefined") {
3290
+ window.location.assign(signOutRedirect);
3291
+ }
3292
+ })();
3293
+ },
3294
+ 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",
3295
+ "data-oc-account-menu-item": "",
3296
+ "data-oc-account-menu-signout": "",
3297
+ children: [
3298
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
3299
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: "sign out" })
3300
+ ]
3301
+ }
3302
+ )
3303
+ ] }),
3304
+ secondaryNavLinks && secondaryNavLinks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
3305
+ PopoverSection,
3306
+ {
3307
+ label: "more",
3308
+ items: secondaryNavLinks,
3309
+ onItemClick: () => setOpen(false),
3310
+ bordered: true
3311
+ }
3312
+ ) : null,
3313
+ build ? /* @__PURE__ */ jsxRuntime.jsx(BuildFooter, { hostname, build, state: siteState }) : null
3314
+ ]
3315
+ }
3316
+ )
3317
+ ]
3318
+ }
3319
+ );
3320
+ }
3321
+ function AccountsSection({
3322
+ roster,
3323
+ switchAccount,
3324
+ addAccountUrl,
3325
+ signOut,
3326
+ onActionStart
3327
+ }) {
3328
+ const [switching, setSwitching] = React2.useState(null);
3329
+ const [err, setErr] = React2.useState(null);
3330
+ if (!addAccountUrl) return null;
3331
+ const onSwitch = async (didOc) => {
3332
+ if (!switchAccount || switching) return;
3333
+ setSwitching(didOc);
3334
+ setErr(null);
3335
+ try {
3336
+ await switchAccount(didOc);
3337
+ } catch (e) {
3338
+ setErr(e instanceof Error ? e.message : "switch failed");
3339
+ } finally {
3340
+ setSwitching(null);
3341
+ }
3342
+ };
3343
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border border-b p-1", "data-oc-account-menu-section": "accounts", children: [
3344
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 accounts" }),
3345
+ roster.map((peer) => /* @__PURE__ */ jsxRuntime.jsx(
3346
+ SwitchRow,
3347
+ {
3348
+ peer,
3349
+ busy: switching === peer.didOc,
3350
+ disabled: switching !== null,
3351
+ onSwitch: () => void onSwitch(peer.didOc)
3352
+ },
3353
+ peer.didOc
3354
+ )),
3355
+ /* @__PURE__ */ jsxRuntime.jsxs(
3356
+ "a",
3357
+ {
3358
+ href: addAccountUrl(),
3359
+ onClick: () => onActionStart(),
3360
+ role: "menuitem",
3361
+ "data-oc-account-menu-add-account": "",
3362
+ className: "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors",
3363
+ children: [
3364
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "text-muted-foreground size-3.5 shrink-0", "aria-hidden": true }),
3365
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: roster.length === 0 ? "add another account" : "add another" })
3366
+ ]
3367
+ }
3368
+ ),
3369
+ roster.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
3370
+ "button",
3371
+ {
3372
+ type: "button",
3373
+ role: "menuitem",
3374
+ onClick: () => {
3375
+ onActionStart();
3376
+ void (async () => {
3377
+ try {
3378
+ await signOut({ scope: "current" });
3379
+ } catch {
3380
+ }
3381
+ })();
3382
+ },
3383
+ "data-oc-account-menu-leave-current": "",
3384
+ 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",
3385
+ children: [
3386
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
3387
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: "leave this account" })
3388
+ ]
3389
+ }
3390
+ ) : null,
3391
+ err ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-destructive/80 px-3 pt-1 pb-2 font-mono text-[10px]", children: err }) : null
3392
+ ] });
3393
+ }
3394
+ function SwitchRow({
3395
+ peer,
3396
+ busy,
3397
+ disabled,
3398
+ onSwitch
3399
+ }) {
3400
+ const label = peer.displayName ?? obscureIdentity(peer.displayIdentity.value);
3401
+ const kindLabel = IDENTITY_KIND_LABEL[peer.displayIdentity.kind];
3402
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3403
+ "button",
3404
+ {
3405
+ type: "button",
3406
+ role: "menuitemradio",
3407
+ "aria-checked": false,
3408
+ "aria-label": `Switch to ${peer.didOc}`,
3409
+ disabled,
3410
+ onClick: onSwitch,
3411
+ "data-oc-account-menu-switch-row": "",
3412
+ 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 disabled:cursor-default",
3413
+ children: [
3414
+ /* @__PURE__ */ jsxRuntime.jsx(
3415
+ "span",
3416
+ {
3417
+ className: "border-muted-foreground/40 flex size-3.5 shrink-0 items-center justify-center rounded-full border",
3418
+ "aria-hidden": true
3419
+ }
3420
+ ),
3421
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground/90 min-w-0 flex-1 truncate", children: label }),
3422
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 w-14 shrink-0 text-right text-[9px] tracking-widest uppercase", children: busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "ml-auto size-3 animate-spin" }) : kindLabel })
3423
+ ]
3424
+ }
3425
+ );
3426
+ }
3427
+ function PopoverSection({
3428
+ label,
3429
+ items,
3430
+ onItemClick,
3431
+ bordered
3432
+ }) {
3433
+ const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
3434
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3435
+ "div",
3436
+ {
3437
+ className: "p-1 " + (bordered ? "border-border border-t" : ""),
3438
+ "data-oc-account-menu-section": label,
3439
+ children: [
3440
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-muted-foreground/60 px-3 pt-2 pb-1 font-mono text-[10px] tracking-widest uppercase", children: [
3441
+ "\xA7 ",
3442
+ label
3443
+ ] }),
3444
+ items.map((item) => {
3445
+ const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3446
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
3447
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
3448
+ item.external ? /* @__PURE__ */ jsxRuntime.jsx(
3449
+ "span",
3450
+ {
3451
+ className: "text-muted-foreground/70 text-[10px]",
3452
+ "aria-hidden": true,
3453
+ children: "\u2197"
3454
+ }
3455
+ ) : null
3456
+ ] });
3457
+ return item.external ? /* @__PURE__ */ jsxRuntime.jsx(
3458
+ "a",
3459
+ {
3460
+ href: item.href,
3461
+ target: "_blank",
3462
+ rel: "noreferrer",
3463
+ onClick: onItemClick,
3464
+ role: "menuitem",
3465
+ className: cls,
3466
+ "data-oc-account-menu-item": "",
3467
+ children: inner
3468
+ },
3469
+ item.href
3470
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3471
+ Link6__default.default,
3472
+ {
3473
+ href: item.href,
3474
+ onClick: onItemClick,
3475
+ role: "menuitem",
3476
+ className: cls,
3477
+ "data-oc-account-menu-item": "",
3478
+ children: inner
3479
+ },
3480
+ item.href
3481
+ );
3482
+ })
3483
+ ]
3484
+ }
3485
+ );
3486
+ }
3487
+ function BuildFooter({
3488
+ hostname,
3489
+ build,
3490
+ state
3491
+ }) {
3492
+ const sha = build.sha;
3493
+ const showSha = !!sha && sha !== "dev";
3494
+ const commitUrl = showSha && build.repo ? `https://github.com/${build.repo}/commit/${sha}` : null;
3495
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3496
+ "div",
3497
+ {
3498
+ className: "text-muted-foreground/60 border-border border-t px-3 py-2 font-mono text-[9.5px] tracking-widest uppercase",
3499
+ "data-oc-account-menu-build": "",
3500
+ children: [
3501
+ hostname,
3502
+ state && state !== "live" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3503
+ " \xB7 ",
3504
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/80", children: state })
3505
+ ] }) : null,
3506
+ " ",
3507
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground/80", children: [
3508
+ "v",
3509
+ build.version,
3510
+ showSha ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3511
+ " \xB7 ",
3512
+ commitUrl ? /* @__PURE__ */ jsxRuntime.jsx(
3513
+ "a",
3514
+ {
3515
+ href: commitUrl,
3516
+ target: "_blank",
3517
+ rel: "noreferrer",
3518
+ className: "hover:text-foreground/90 underline decoration-dotted underline-offset-2",
3519
+ children: sha
3520
+ }
3521
+ ) : sha
3522
+ ] }) : null
3523
+ ] })
3524
+ ]
3525
+ }
3526
+ );
3527
+ }
3528
+ function isActive(pathname, link) {
3529
+ if (link.external) return false;
3530
+ if (link.matchExact) return pathname === link.href;
3531
+ if (link.href === "/") return pathname === "/";
3532
+ return pathname === link.href || pathname.startsWith(link.href + "/");
3533
+ }
3534
+ function OcPrimaryNav({ activePath, links, className }) {
3535
+ return /* @__PURE__ */ jsxRuntime.jsx(
3536
+ "nav",
3537
+ {
3538
+ "aria-label": "primary",
3539
+ 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 ?? ""),
3540
+ "data-oc-primary-nav": "",
3541
+ children: links.map((link) => {
3542
+ const active = isActive(activePath, link);
3543
+ const className2 = "font-display relative shrink-0 px-2 py-1 sm:px-3 text-[11px] sm:text-[12px] font-semibold tracking-wider uppercase transition-colors " + (active ? 'text-primary after:bg-primary after:absolute after:inset-x-2 after:-bottom-[13px] after:h-px after:content-[""]' : "text-muted-foreground hover:text-foreground");
3544
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3545
+ link.label,
3546
+ link.external ? /* @__PURE__ */ jsxRuntime.jsx(
3547
+ "span",
3548
+ {
3549
+ "aria-hidden": true,
3550
+ className: "text-muted-foreground/60 ml-1 text-[9px]",
3551
+ children: "\u2197"
3552
+ }
3553
+ ) : null
3554
+ ] });
3555
+ return link.external ? /* @__PURE__ */ jsxRuntime.jsx(
3556
+ "a",
3557
+ {
3558
+ href: link.href,
3559
+ target: "_blank",
3560
+ rel: "noreferrer",
3561
+ className: className2,
3562
+ "data-oc-primary-nav-item": "",
3563
+ children: content
3564
+ },
3565
+ link.href
3566
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3567
+ Link6__default.default,
3568
+ {
3569
+ href: link.href,
3570
+ "aria-current": active ? "page" : void 0,
3571
+ className: className2,
3572
+ "data-oc-primary-nav-item": active ? "active" : "sibling",
3573
+ children: content
3574
+ },
3575
+ link.href
3576
+ );
3577
+ })
3578
+ }
3579
+ );
3580
+ }
3581
+ function OcDashboardShell({
3582
+ rootHref = "/dashboard",
3583
+ siteLabel,
3584
+ tools,
3585
+ active,
3586
+ eyebrow,
3587
+ title,
3588
+ description,
3589
+ children,
3590
+ className
3591
+ }) {
3592
+ const [drawerOpen, setDrawerOpen] = React2.useState(false);
3593
+ React2.useEffect(() => {
3594
+ if (!drawerOpen) return;
3595
+ function onKey(e) {
3596
+ if (e.key === "Escape") setDrawerOpen(false);
3597
+ }
3598
+ document.addEventListener("keydown", onKey);
3599
+ const prevOverflow = document.body.style.overflow;
3600
+ document.body.style.overflow = "hidden";
3601
+ return () => {
3602
+ document.removeEventListener("keydown", onKey);
3603
+ document.body.style.overflow = prevOverflow;
3604
+ };
3605
+ }, [drawerOpen]);
3606
+ const hasHeader = Boolean(title) || Boolean(eyebrow);
3607
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3608
+ "div",
3609
+ {
3610
+ className: "container " + (className ?? ""),
3611
+ "data-oc-dashboard-shell": "",
3612
+ children: [
3613
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[calc(100vh-3rem)] flex-col md:flex-row md:gap-8", children: [
3614
+ /* @__PURE__ */ jsxRuntime.jsx(
3615
+ Sidebar,
3616
+ {
3617
+ rootHref,
3618
+ siteLabel,
3619
+ tools,
3620
+ active,
3621
+ variant: "desktop"
3622
+ }
3623
+ ),
3624
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
3625
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border flex items-center justify-between border-b py-3 md:hidden", children: [
3626
+ /* @__PURE__ */ jsxRuntime.jsxs(
3627
+ "button",
3628
+ {
3629
+ type: "button",
3630
+ onClick: () => setDrawerOpen(true),
3631
+ className: "text-muted-foreground hover:text-foreground inline-flex h-9 items-center gap-2 px-1 font-mono text-[11px] tracking-widest uppercase transition-colors",
3632
+ "aria-label": "open dashboard tools",
3633
+ "aria-expanded": drawerOpen,
3634
+ "data-oc-dashboard-mobile-trigger": "",
3635
+ children: [
3636
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[14px] leading-none", children: "\u2261" }),
3637
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "tools" })
3638
+ ]
3639
+ }
3640
+ ),
3641
+ /* @__PURE__ */ jsxRuntime.jsx(
3642
+ Link6__default.default,
3643
+ {
3644
+ href: rootHref,
3645
+ className: "text-primary font-mono text-[11px] tracking-widest uppercase",
3646
+ children: "\xA7 dashboard"
3647
+ }
3648
+ )
3649
+ ] }),
3650
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-6 md:pt-3", children: [
3651
+ hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-3xl", children: [
3652
+ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-primary mb-3 font-mono text-[10px] tracking-widest uppercase", children: eyebrow }) : null,
3653
+ title ? /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "font-display text-2xl font-bold tracking-tight sm:text-3xl", children: title }) : null,
3654
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-3 max-w-[64ch] text-sm leading-relaxed", children: description }) : null
3655
+ ] }),
3656
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: hasHeader ? "mt-8 pb-12" : "pb-12", children })
3657
+ ] })
3658
+ ] })
3659
+ ] }),
3660
+ drawerOpen ? /* @__PURE__ */ jsxRuntime.jsxs(
3661
+ "div",
3662
+ {
3663
+ className: "fixed inset-0 z-50 md:hidden",
3664
+ role: "dialog",
3665
+ "aria-modal": "true",
3666
+ "aria-label": "dashboard tools",
3667
+ "data-oc-dashboard-drawer": "",
3668
+ children: [
3669
+ /* @__PURE__ */ jsxRuntime.jsx(
3670
+ "div",
3671
+ {
3672
+ className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
3673
+ onClick: () => setDrawerOpen(false),
3674
+ "aria-hidden": true
3675
+ }
3676
+ ),
3677
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-background absolute top-0 left-0 h-full w-[85vw] max-w-sm border-r shadow-xl", children: /* @__PURE__ */ jsxRuntime.jsx(
3678
+ Sidebar,
3679
+ {
3680
+ rootHref,
3681
+ siteLabel,
3682
+ tools,
3683
+ active,
3684
+ variant: "drawer",
3685
+ onClose: () => setDrawerOpen(false)
3686
+ }
3687
+ ) })
3688
+ ]
3689
+ }
3690
+ ) : null
3691
+ ]
3692
+ }
3693
+ );
3694
+ }
3695
+ function Sidebar({
3696
+ rootHref,
3697
+ siteLabel,
3698
+ tools,
3699
+ active,
3700
+ variant,
3701
+ onClose
3702
+ }) {
3703
+ const isDrawer = variant === "drawer";
3704
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3705
+ "aside",
3706
+ {
3707
+ className: isDrawer ? "flex h-full w-full flex-col bg-card" : "hidden md:sticky md:top-4 md:flex md:h-[calc(100vh-2rem)] md:w-56 md:shrink-0 md:flex-col md:self-start md:overflow-y-auto md:rounded md:border md:bg-card/40 lg:w-60",
3708
+ "aria-label": "dashboard tools",
3709
+ "data-oc-dashboard-sidebar": variant,
3710
+ children: [
3711
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b px-4 py-3", children: [
3712
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
3713
+ /* @__PURE__ */ jsxRuntime.jsx(
3714
+ Link6__default.default,
3715
+ {
3716
+ href: rootHref,
3717
+ onClick: onClose,
3718
+ className: "hover:text-foreground font-display text-sm font-bold tracking-tight",
3719
+ children: "\xA7 dashboard"
3720
+ }
3721
+ ),
3722
+ isDrawer ? /* @__PURE__ */ jsxRuntime.jsx(
3723
+ "button",
3724
+ {
3725
+ type: "button",
3726
+ onClick: onClose,
3727
+ className: "text-muted-foreground hover:text-foreground -mr-2 inline-flex h-8 w-8 items-center justify-center rounded font-mono text-lg",
3728
+ "aria-label": "close navigation",
3729
+ children: "\xD7"
3730
+ }
3731
+ ) : null
3732
+ ] }),
3733
+ siteLabel ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/70 mt-1 font-mono text-[10px] tracking-widest uppercase", children: siteLabel }) : null
3734
+ ] }),
3735
+ /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "flex-1 overflow-y-auto px-2 py-3", children: [
3736
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground/60 mb-1 px-3 font-mono text-[10px] tracking-widest uppercase", children: "\xA7 tools" }),
3737
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-0.5", children: tools.map((tool) => {
3738
+ const isActive2 = tool.id === active;
3739
+ const innerCls = "flex items-baseline gap-2 rounded px-3 py-1.5 text-[12.5px] transition-colors " + (isActive2 ? "bg-primary/10 text-primary font-semibold" : "text-muted-foreground hover:text-foreground hover:bg-muted/30");
3740
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3741
+ tool.icon ? /* @__PURE__ */ jsxRuntime.jsx(
3742
+ "span",
3743
+ {
3744
+ className: "shrink-0 font-mono text-[11px] " + (isActive2 ? "text-primary" : "text-muted-foreground/70"),
3745
+ "aria-hidden": true,
3746
+ children: tool.icon
3747
+ }
3748
+ ) : null,
3749
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex-1 leading-tight", children: [
3750
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: tool.label }),
3751
+ tool.tagline ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/60 mt-0.5 block font-mono text-[10px] tracking-wide normal-case", children: tool.tagline }) : null
3752
+ ] }),
3753
+ tool.external ? /* @__PURE__ */ jsxRuntime.jsx(
3754
+ "span",
3755
+ {
3756
+ className: "text-muted-foreground/60 text-[10px]",
3757
+ "aria-hidden": true,
3758
+ children: "\u2197"
3759
+ }
3760
+ ) : null
3761
+ ] });
3762
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: tool.external ? /* @__PURE__ */ jsxRuntime.jsx(
3763
+ "a",
3764
+ {
3765
+ href: tool.href,
3766
+ target: "_blank",
3767
+ rel: "noreferrer",
3768
+ onClick: onClose,
3769
+ className: innerCls,
3770
+ "data-oc-dashboard-tool": isActive2 ? "active" : "sibling",
3771
+ children: content
3772
+ }
3773
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3774
+ Link6__default.default,
3775
+ {
3776
+ href: tool.href,
3777
+ onClick: onClose,
3778
+ "aria-current": isActive2 ? "page" : void 0,
3779
+ className: innerCls,
3780
+ "data-oc-dashboard-tool": isActive2 ? "active" : "sibling",
3781
+ children: content
3782
+ }
3783
+ ) }, tool.id);
3784
+ }) })
3785
+ ] })
3786
+ ]
3787
+ }
3788
+ );
3789
+ }
3790
+ function OcDashboardHub({ tools, className }) {
3791
+ return /* @__PURE__ */ jsxRuntime.jsx(
3792
+ "ul",
3793
+ {
3794
+ className: "grid gap-px border-t border-l sm:grid-cols-2 " + (className ?? ""),
3795
+ "data-oc-dashboard-hub": "",
3796
+ children: tools.map((tool) => {
3797
+ const content = /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex h-full flex-col gap-3 p-5 transition-colors", children: [
3798
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-baseline gap-3", children: [
3799
+ tool.icon ? /* @__PURE__ */ jsxRuntime.jsx(
3800
+ "span",
3801
+ {
3802
+ className: "text-primary font-mono text-[13px]",
3803
+ "aria-hidden": true,
3804
+ children: tool.icon
3805
+ }
3806
+ ) : null,
3807
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-display text-foreground text-base font-bold tracking-tight", children: tool.label }),
3808
+ tool.external ? /* @__PURE__ */ jsxRuntime.jsx(
3809
+ "span",
3810
+ {
3811
+ className: "text-muted-foreground/60 ml-auto text-xs",
3812
+ "aria-hidden": true,
3813
+ children: "\u2197"
3814
+ }
3815
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3816
+ "span",
3817
+ {
3818
+ className: "text-muted-foreground/60 ml-auto text-xs",
3819
+ "aria-hidden": true,
3820
+ children: "\u2192"
3821
+ }
3822
+ )
3823
+ ] }),
3824
+ tool.tagline ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm leading-relaxed", children: tool.tagline }) : null
3825
+ ] });
3826
+ const cls = "hover:bg-muted/30 group block border-r border-b transition-colors";
3827
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: tool.external ? /* @__PURE__ */ jsxRuntime.jsx(
3828
+ "a",
3829
+ {
3830
+ href: tool.href,
3831
+ target: "_blank",
3832
+ rel: "noreferrer",
3833
+ className: cls,
3834
+ children: content
3835
+ }
3836
+ ) : /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: tool.href, className: cls, children: content }) }, tool.id);
3837
+ })
3838
+ }
3839
+ );
3840
+ }
3841
+ function AppShell({
3842
+ eyebrow,
3843
+ title,
3844
+ description,
3845
+ headerActions,
3846
+ children,
3847
+ className
3848
+ }) {
3849
+ const hasHeader = Boolean(title);
3850
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container " + (className ?? ""), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[calc(100vh-3rem)] flex-col", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-6 md:pt-8", children: [
3851
+ hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between", children: [
3852
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-3xl", children: [
3853
+ eyebrow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-primary mb-3", children: eyebrow }),
3854
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "font-display text-2xl font-bold tracking-tight sm:text-3xl", children: title }),
3855
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-3 max-w-[64ch] text-sm leading-relaxed", children: description })
3856
+ ] }),
3857
+ headerActions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: headerActions })
3858
+ ] }),
3859
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: hasHeader ? "mt-8 pb-12" : "pb-12", children })
3860
+ ] }) }) }) });
3861
+ }
3862
+ var HIDE = {
3863
+ sm: "hidden sm:inline",
3864
+ md: "hidden md:inline",
3865
+ lg: "hidden lg:inline"
3866
+ };
3867
+ function LayoutSubHeader({
3868
+ product,
3869
+ status = "live \xB7 mainnet",
3870
+ tags = [],
3871
+ noHeartbeat = false,
3872
+ className
3873
+ }) {
3874
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("border-b", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "container flex flex-wrap items-center justify-between gap-x-6 gap-y-1 py-2 font-mono text-[11px]", children: [
3875
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
3876
+ !noHeartbeat && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary inline-block h-1.5 w-1.5 animate-pulse rounded-full" }),
3877
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground tracking-widest uppercase", children: status }),
3878
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: product })
3879
+ ] }),
3880
+ tags.length > 0 && /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("span", { className: tag.hideBelow ? HIDE[tag.hideBelow] : void 0, children: tag.label }, i)) })
3881
+ ] }) });
3882
+ }
2129
3883
 
2130
3884
  exports.Accordion = Accordion;
2131
3885
  exports.AccordionContent = AccordionContent;
@@ -2136,15 +3890,19 @@ exports.AlertDescription = AlertDescription;
2136
3890
  exports.AlertTitle = AlertTitle;
2137
3891
  exports.AlertWithAction = AlertWithAction;
2138
3892
  exports.AlertWithCountdown = AlertWithCountdown;
3893
+ exports.AppShell = AppShell;
2139
3894
  exports.Badge = Badge;
2140
3895
  exports.Bar = Bar;
2141
3896
  exports.BitcoinAddress = BitcoinAddress;
2142
3897
  exports.Button = Button;
3898
+ exports.Callout = Callout;
2143
3899
  exports.Card = Card;
2144
3900
  exports.Checkbox = Checkbox;
2145
3901
  exports.ConfirmHost = ConfirmHost;
2146
3902
  exports.CopyButton = CopyButton;
2147
3903
  exports.DEFAULT_OC_THEME = DEFAULT_OC_THEME;
3904
+ exports.DataRow = DataRow;
3905
+ exports.DefinitionList = DefinitionList;
2148
3906
  exports.Dialog = Dialog;
2149
3907
  exports.DialogClose = DialogClose;
2150
3908
  exports.DialogContent = DialogContent;
@@ -2155,14 +3913,25 @@ exports.DialogOverlay = DialogOverlay;
2155
3913
  exports.DialogPortal = DialogPortal;
2156
3914
  exports.DialogTitle = DialogTitle;
2157
3915
  exports.DialogTrigger = DialogTrigger;
3916
+ exports.EcosystemSwitcher = EcosystemSwitcher;
3917
+ exports.EmptyState = EmptyState;
2158
3918
  exports.ErrorBoundary = ErrorBoundary;
3919
+ exports.FAMILY_PROPERTIES = FAMILY_PROPERTIES;
3920
+ exports.HelpHint = HelpHint;
2159
3921
  exports.Input = Input;
2160
3922
  exports.Label = Label;
3923
+ exports.LayoutSubHeader = LayoutSubHeader;
2161
3924
  exports.Modal = Modal;
2162
3925
  exports.OC_DEFAULT_ACCENT = OC_DEFAULT_ACCENT;
2163
3926
  exports.OC_SKIN_COOKIE = OC_SKIN_COOKIE;
2164
3927
  exports.OC_THEMES = OC_THEMES;
3928
+ exports.OcAccountMenu = OcAccountMenu;
3929
+ exports.OcAccountMenuView = OcAccountMenuView;
2165
3930
  exports.OcAppearanceMenu = OcAppearanceMenu;
3931
+ exports.OcDashboardHub = OcDashboardHub;
3932
+ exports.OcDashboardShell = OcDashboardShell;
3933
+ exports.OcLogoDropdown = OcLogoDropdown;
3934
+ exports.OcPrimaryNav = OcPrimaryNav;
2166
3935
  exports.OcThemeBridge = OcThemeBridge;
2167
3936
  exports.OcThemePicker = OcThemePicker;
2168
3937
  exports.OcThemeProvider = OcThemeProvider;
@@ -2176,7 +3945,9 @@ exports.QrCode = QrCode;
2176
3945
  exports.REFERENCE_BTC_USD = REFERENCE_BTC_USD;
2177
3946
  exports.RadioGroup = RadioGroup;
2178
3947
  exports.RadioGroupItem = RadioGroupItem;
3948
+ exports.SITE_STATE_LABEL = SITE_STATE_LABEL;
2179
3949
  exports.SatsAmount = SatsAmount;
3950
+ exports.SectionHeader = SectionHeader;
2180
3951
  exports.Select = Select;
2181
3952
  exports.SelectContent = SelectContent;
2182
3953
  exports.SelectGroup = SelectGroup;
@@ -2201,8 +3972,14 @@ exports.SheetTrigger = SheetTrigger;
2201
3972
  exports.Skeleton = Skeleton;
2202
3973
  exports.Sparkline = Sparkline;
2203
3974
  exports.StatBlock = StatBlock;
3975
+ exports.StatGrid = StatGrid;
3976
+ exports.StatTile = StatTile;
2204
3977
  exports.StatusPill = StatusPill;
2205
3978
  exports.Switch = Switch;
3979
+ exports.Tabs = Tabs;
3980
+ exports.TabsContent = TabsContent;
3981
+ exports.TabsList = TabsList;
3982
+ exports.TabsTrigger = TabsTrigger;
2206
3983
  exports.Textarea = Textarea;
2207
3984
  exports.ThemeToggle = ThemeToggle;
2208
3985
  exports.ThemeToggleLink = ThemeToggleLink;
@@ -2215,10 +3992,12 @@ exports.buttonVariants = buttonVariants;
2215
3992
  exports.cn = cn;
2216
3993
  exports.confirm = confirm;
2217
3994
  exports.explorerUrl = explorerUrl;
3995
+ exports.findFamilyProperty = findFamilyProperty;
2218
3996
  exports.formatSats = formatSats;
2219
3997
  exports.formatSatsCompact = formatSatsCompact;
2220
3998
  exports.getOcThemeInitScript = getOcThemeInitScript;
2221
3999
  exports.isKnownTheme = isKnownTheme;
4000
+ exports.makeStatusPill = makeStatusPill;
2222
4001
  exports.priceBoth = priceBoth;
2223
4002
  exports.prompt = prompt;
2224
4003
  exports.relativeTime = relativeTime;