@orangecheck/ui 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { Boxes, ChevronDown, Check } from 'lucide-react';
2
2
  import Link from 'next/link';
3
3
  import { useState, useRef, useEffect, useId } from 'react';
4
- import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+ import { useOcSession } from '@orangecheck/auth-client';
5
6
 
6
7
  // src/ecosystem-switcher.tsx
7
8
  var ENTRIES = [
@@ -172,88 +173,162 @@ function EcosystemSwitcher({
172
173
  )
173
174
  ] });
174
175
  }
175
- var ENTRIES2 = [
176
+
177
+ // src/family-properties.ts
178
+ var FAMILY_PROPERTIES = [
176
179
  {
177
180
  slug: "home",
178
- href: "https://ochk.io",
181
+ origin: "https://ochk.io",
182
+ hostname: "ochk.io",
179
183
  label: "orangecheck",
180
184
  sub: "umbrella \xB7 sign-in",
181
- docsHref: "https://docs.ochk.io"
185
+ docsHref: "https://docs.ochk.io",
186
+ category: "hub"
187
+ },
188
+ {
189
+ slug: "docs",
190
+ origin: "https://docs.ochk.io",
191
+ hostname: "docs.ochk.io",
192
+ label: "oc\xB7docs",
193
+ sub: "unified reference",
194
+ docsHref: "https://docs.ochk.io",
195
+ category: "hub"
182
196
  },
183
197
  {
184
198
  slug: "me",
185
- href: "https://me.ochk.io",
199
+ origin: "https://me.ochk.io",
200
+ hostname: "me.ochk.io",
186
201
  label: "oc\xB7me",
187
202
  sub: "earn \u2014 consumer identity",
188
- docsHref: "https://docs.ochk.io/me"
203
+ docsHref: "https://docs.ochk.io/me",
204
+ category: "product"
189
205
  },
190
206
  {
191
207
  slug: "vault",
192
- href: "https://vault.ochk.io",
208
+ origin: "https://vault.ochk.io",
209
+ hostname: "vault.ochk.io",
193
210
  label: "oc\xB7vault",
194
211
  sub: "keep \u2014 encrypted secrets",
195
- docsHref: "https://docs.ochk.io/vault"
212
+ docsHref: "https://docs.ochk.io/vault",
213
+ category: "product"
196
214
  },
197
215
  {
198
216
  slug: "fleet",
199
- href: "https://fleet.ochk.io",
217
+ origin: "https://fleet.ochk.io",
218
+ hostname: "fleet.ochk.io",
200
219
  label: "oc\xB7fleet",
201
220
  sub: "managed \u2014 agent fleet",
202
- docsHref: "https://docs.ochk.io/fleet"
221
+ docsHref: "https://docs.ochk.io/fleet",
222
+ category: "product"
203
223
  },
204
224
  {
205
225
  slug: "attest",
206
- href: "https://attest.ochk.io",
226
+ origin: "https://attest.ochk.io",
227
+ hostname: "attest.ochk.io",
207
228
  label: "oc\xB7attest",
208
229
  sub: "am \u2014 sybil resistance",
209
- docsHref: "https://docs.ochk.io/attest"
230
+ docsHref: "https://docs.ochk.io/attest",
231
+ category: "protocol"
210
232
  },
211
233
  {
212
234
  slug: "lock",
213
- href: "https://lock.ochk.io",
235
+ origin: "https://lock.ochk.io",
236
+ hostname: "lock.ochk.io",
214
237
  label: "oc\xB7lock",
215
238
  sub: "whisper \u2014 encryption",
216
- docsHref: "https://docs.ochk.io/lock"
239
+ docsHref: "https://docs.ochk.io/lock",
240
+ category: "protocol"
217
241
  },
218
242
  {
219
243
  slug: "vote",
220
- href: "https://vote.ochk.io",
244
+ origin: "https://vote.ochk.io",
245
+ hostname: "vote.ochk.io",
221
246
  label: "oc\xB7vote",
222
247
  sub: "decide \u2014 polls",
223
- docsHref: "https://docs.ochk.io/vote"
248
+ docsHref: "https://docs.ochk.io/vote",
249
+ category: "protocol"
224
250
  },
225
251
  {
226
252
  slug: "stamp",
227
- href: "https://stamp.ochk.io",
253
+ origin: "https://stamp.ochk.io",
254
+ hostname: "stamp.ochk.io",
228
255
  label: "oc\xB7stamp",
229
256
  sub: "declare \u2014 block-anchored",
230
- docsHref: "https://docs.ochk.io/stamp"
257
+ docsHref: "https://docs.ochk.io/stamp",
258
+ category: "protocol"
231
259
  },
232
260
  {
233
261
  slug: "agent",
234
- href: "https://agent.ochk.io",
262
+ origin: "https://agent.ochk.io",
263
+ hostname: "agent.ochk.io",
235
264
  label: "oc\xB7agent",
236
265
  sub: "delegate \u2014 scoped auth",
237
- docsHref: "https://docs.ochk.io/agent"
266
+ docsHref: "https://docs.ochk.io/agent",
267
+ category: "protocol"
238
268
  },
239
269
  {
240
270
  slug: "pledge",
241
- href: "https://pledge.ochk.io",
271
+ origin: "https://pledge.ochk.io",
272
+ hostname: "pledge.ochk.io",
242
273
  label: "oc\xB7pledge",
243
274
  sub: "swear \u2014 bonded commitment",
244
- docsHref: "https://docs.ochk.io/pledge"
245
- },
246
- {
247
- slug: "docs",
248
- href: "https://docs.ochk.io",
249
- label: "oc\xB7docs",
250
- sub: "unified reference",
251
- docsHref: "https://docs.ochk.io"
275
+ docsHref: "https://docs.ochk.io/pledge",
276
+ category: "protocol"
252
277
  }
253
278
  ];
279
+ var SITE_STATE_LABEL = {
280
+ alpha: "alpha",
281
+ beta: "beta"
282
+ };
283
+ function findFamilyProperty(slug) {
284
+ return FAMILY_PROPERTIES.find((p) => p.slug === slug);
285
+ }
286
+ var SECTIONS = [
287
+ { category: "hub", label: "hub" },
288
+ { category: "product", label: "products" },
289
+ { category: "protocol", label: "protocols" }
290
+ ];
291
+ function CategoryChip({ category }) {
292
+ if (category === "hub") return null;
293
+ const isProduct = category === "product";
294
+ return /* @__PURE__ */ jsx(
295
+ "span",
296
+ {
297
+ "aria-label": isProduct ? "commercial product" : "protocol reference",
298
+ className: "ml-1 hidden rounded-sm border px-1.5 py-[1px] font-mono text-[9px] font-medium tracking-widest uppercase sm:inline-block " + (isProduct ? "border-primary/25 bg-primary/10 text-primary" : "border-muted-foreground/20 bg-muted/40 text-muted-foreground/85"),
299
+ "data-oc-category": category,
300
+ children: isProduct ? "product" : "protocol"
301
+ }
302
+ );
303
+ }
304
+ function SiteStateBadge({ state }) {
305
+ if (state === "live") return null;
306
+ return /* @__PURE__ */ jsx(
307
+ "span",
308
+ {
309
+ "aria-label": `site lifecycle: ${state}`,
310
+ className: "text-muted-foreground/70 ml-1 hidden font-mono text-[9px] font-medium tracking-widest uppercase sm:inline-block",
311
+ "data-oc-site-state": state,
312
+ children: SITE_STATE_LABEL[state]
313
+ }
314
+ );
315
+ }
316
+ function MenuCategoryChip({ category }) {
317
+ if (category === "hub") return null;
318
+ const isProduct = category === "product";
319
+ return /* @__PURE__ */ jsx(
320
+ "span",
321
+ {
322
+ "aria-hidden": true,
323
+ className: "inline-block shrink-0 rounded-sm px-1 py-[1px] font-mono text-[9px] font-medium tracking-widest uppercase " + (isProduct ? "bg-primary/10 text-primary" : "bg-muted/60 text-muted-foreground/80"),
324
+ children: isProduct ? "pro" : "spec"
325
+ }
326
+ );
327
+ }
254
328
  function OcLogoDropdown({
255
329
  current,
256
330
  homeHref = "/",
331
+ siteState = "live",
257
332
  children,
258
333
  className,
259
334
  triggerClassName,
@@ -262,6 +337,7 @@ function OcLogoDropdown({
262
337
  const [open, setOpen] = useState(false);
263
338
  const containerRef = useRef(null);
264
339
  const menuId = useId();
340
+ const currentCategory = findFamilyProperty(current)?.category ?? "hub";
265
341
  useEffect(() => {
266
342
  if (!open) return;
267
343
  function onDoc(e) {
@@ -284,6 +360,8 @@ function OcLogoDropdown({
284
360
  ref: containerRef,
285
361
  className: "relative " + (className ?? ""),
286
362
  "data-oc-logo-dropdown": "",
363
+ "data-oc-current-category": currentCategory,
364
+ "data-oc-site-state": siteState,
287
365
  children: [
288
366
  /* @__PURE__ */ jsxs(
289
367
  "button",
@@ -295,10 +373,12 @@ function OcLogoDropdown({
295
373
  "aria-label": "OrangeCheck family \xB7 open property menu",
296
374
  title: "Switch OrangeCheck product",
297
375
  onClick: () => setOpen((v) => !v),
298
- className: triggerClassName ?? "group hover:bg-accent/30 flex min-h-[40px] items-center gap-2 rounded-sm px-1.5 py-1 -mx-1.5 -my-1 transition-colors",
376
+ 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",
299
377
  "data-oc-logo-dropdown-trigger": "",
300
378
  children: [
301
379
  children,
380
+ /* @__PURE__ */ jsx(CategoryChip, { category: currentCategory }),
381
+ /* @__PURE__ */ jsx(SiteStateBadge, { state: siteState }),
302
382
  /* @__PURE__ */ jsx(
303
383
  ChevronDown,
304
384
  {
@@ -315,18 +395,28 @@ function OcLogoDropdown({
315
395
  id: menuId,
316
396
  role: "menu",
317
397
  "aria-label": "OrangeCheck family",
318
- className: popoverClassName ?? "bg-background absolute left-0 top-full z-[60] mt-2 w-[min(20rem,calc(100vw-1rem))] border shadow-lg",
398
+ className: popoverClassName ?? "bg-background absolute top-full left-0 z-[60] mt-2 w-[min(20rem,calc(100vw-1rem))] border shadow-lg",
319
399
  "data-oc-logo-dropdown-popover": "",
320
400
  children: [
321
401
  /* @__PURE__ */ jsx("div", { className: "label-mono text-primary border-b px-4 py-2", children: "\xA7 the orangecheck family" }),
322
- /* @__PURE__ */ jsx(
323
- "ul",
324
- {
325
- className: "max-h-[min(28rem,70vh)] overflow-y-auto py-1",
326
- role: "none",
327
- children: ENTRIES2.map((e) => {
402
+ /* @__PURE__ */ jsx("div", { className: "max-h-[min(28rem,70vh)] overflow-y-auto py-1", role: "none", children: SECTIONS.map(({ category, label }) => {
403
+ const sectionEntries = FAMILY_PROPERTIES.filter(
404
+ (e) => e.category === category
405
+ );
406
+ if (sectionEntries.length === 0) return null;
407
+ return /* @__PURE__ */ jsxs("div", { role: "none", "data-oc-section": category, children: [
408
+ /* @__PURE__ */ jsx(
409
+ "div",
410
+ {
411
+ role: "separator",
412
+ "aria-hidden": true,
413
+ 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"),
414
+ children: label
415
+ }
416
+ ),
417
+ /* @__PURE__ */ jsx("ul", { role: "none", className: "pb-1", children: sectionEntries.map((e) => {
328
418
  const isActive = e.slug === current;
329
- const href = isActive ? homeHref : e.href;
419
+ const href = isActive ? homeHref : e.origin;
330
420
  return /* @__PURE__ */ jsx("li", { role: "none", children: /* @__PURE__ */ jsxs(
331
421
  Link,
332
422
  {
@@ -334,27 +424,31 @@ function OcLogoDropdown({
334
424
  role: "menuitem",
335
425
  onClick: () => setOpen(false),
336
426
  "aria-current": isActive ? "page" : void 0,
337
- className: "group flex items-baseline gap-3 px-4 py-2.5 transition-colors " + (isActive ? "bg-primary/8 border-primary border-l-2 -ml-px" : "hover:bg-muted border-l-2 border-transparent -ml-px"),
427
+ className: "group flex items-center gap-2 px-4 py-2 transition-colors " + (isActive ? "bg-primary/8 border-primary -ml-px border-l-2" : "hover:bg-muted -ml-px border-l-2 border-transparent"),
338
428
  "data-oc-logo-dropdown-item": isActive ? "current" : "sibling",
429
+ "data-oc-entry-category": e.category,
339
430
  children: [
340
- /* @__PURE__ */ jsx(
341
- "span",
342
- {
343
- className: "font-display flex-1 text-[12px] font-semibold tracking-tight " + (isActive ? "text-primary" : "text-foreground group-hover:text-primary transition-colors"),
344
- children: e.label
345
- }
346
- ),
347
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-mono text-[10px] tracking-wider uppercase", children: e.sub }),
348
- isActive ? /* @__PURE__ */ jsxs("span", { className: "text-primary inline-flex items-center gap-1 font-mono text-[10px] tracking-widest uppercase", children: [
431
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
432
+ /* @__PURE__ */ jsx(
433
+ "span",
434
+ {
435
+ className: "font-display text-[12px] font-semibold tracking-tight " + (isActive ? "text-primary" : "text-foreground group-hover:text-primary transition-colors"),
436
+ children: e.label
437
+ }
438
+ ),
439
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground mt-0.5 font-mono text-[10px] tracking-wide", children: e.sub })
440
+ ] }),
441
+ /* @__PURE__ */ jsx(MenuCategoryChip, { category: e.category }),
442
+ isActive ? /* @__PURE__ */ jsxs("span", { className: "text-primary inline-flex shrink-0 items-center gap-1 font-mono text-[10px] tracking-widest uppercase", children: [
349
443
  "home",
350
444
  /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" })
351
445
  ] }) : null
352
446
  ]
353
447
  }
354
448
  ) }, e.slug);
355
- })
356
- }
357
- ),
449
+ }) })
450
+ ] }, category);
451
+ }) }),
358
452
  /* @__PURE__ */ jsx("div", { className: "border-t px-4 py-2 font-mono text-[10px] tracking-widest uppercase", children: /* @__PURE__ */ jsx(
359
453
  Link,
360
454
  {
@@ -371,6 +465,271 @@ function OcLogoDropdown({
371
465
  }
372
466
  );
373
467
  }
468
+ function shortenDid(s) {
469
+ if (s.length <= 14) return s;
470
+ return `${s.slice(0, 7)}\u2026${s.slice(-5)}`;
471
+ }
472
+ function OcAccountMenu({
473
+ current,
474
+ signInUrl = "/signin",
475
+ signInLabel = "sign in",
476
+ menuItems,
477
+ showFamilyDashboard,
478
+ build,
479
+ siteState,
480
+ className,
481
+ triggerClassName,
482
+ popoverClassName
483
+ }) {
484
+ const session = useOcSession();
485
+ const { status, account, signOut, refresh } = session;
486
+ const [hydrated, setHydrated] = useState(false);
487
+ const [open, setOpen] = useState(false);
488
+ const wrapRef = useRef(null);
489
+ const property = findFamilyProperty(current);
490
+ const hostname = property?.hostname ?? `${current}.ochk.io`;
491
+ const isHome = current === "home";
492
+ const familyDashboardEnabled = showFamilyDashboard ?? !isHome;
493
+ useEffect(() => setHydrated(true), []);
494
+ useEffect(() => {
495
+ const onWake = () => {
496
+ if (document.visibilityState === "visible") void refresh();
497
+ };
498
+ const onFocus = () => void refresh();
499
+ document.addEventListener("visibilitychange", onWake);
500
+ window.addEventListener("focus", onFocus);
501
+ return () => {
502
+ document.removeEventListener("visibilitychange", onWake);
503
+ window.removeEventListener("focus", onFocus);
504
+ };
505
+ }, [refresh]);
506
+ useEffect(() => {
507
+ if (!open) return;
508
+ const onClick = (e) => {
509
+ if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
510
+ };
511
+ const onKey = (e) => {
512
+ if (e.key === "Escape") setOpen(false);
513
+ };
514
+ document.addEventListener("mousedown", onClick);
515
+ document.addEventListener("keydown", onKey);
516
+ return () => {
517
+ document.removeEventListener("mousedown", onClick);
518
+ document.removeEventListener("keydown", onKey);
519
+ };
520
+ }, [open]);
521
+ const signInTrigger = /* @__PURE__ */ jsx(
522
+ "a",
523
+ {
524
+ href: signInUrl,
525
+ "aria-label": signInLabel,
526
+ "data-oc-account-menu-signin": "",
527
+ 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",
528
+ children: signInLabel
529
+ }
530
+ );
531
+ if (!hydrated || status === "loading") {
532
+ return signInTrigger;
533
+ }
534
+ if (status !== "authenticated" || !account) {
535
+ return signInTrigger;
536
+ }
537
+ const displayName = account.displayName ?? null;
538
+ const label = displayName ?? shortenDid(account.didOc);
539
+ return /* @__PURE__ */ jsxs(
540
+ "div",
541
+ {
542
+ ref: wrapRef,
543
+ className: "relative inline-block " + (className ?? ""),
544
+ "data-oc-account-menu": "",
545
+ children: [
546
+ /* @__PURE__ */ jsxs(
547
+ "button",
548
+ {
549
+ type: "button",
550
+ onClick: () => setOpen((v) => !v),
551
+ "aria-haspopup": "menu",
552
+ "aria-expanded": open,
553
+ "aria-label": `Signed in as ${account.didOc}. Open account menu.`,
554
+ 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",
555
+ "data-oc-account-menu-trigger": "",
556
+ children: [
557
+ /* @__PURE__ */ jsx("span", { className: "bg-primary inline-block size-1.5 rounded-full", "aria-hidden": true }),
558
+ /* @__PURE__ */ jsx("span", { className: "text-foreground", children: label }),
559
+ /* @__PURE__ */ jsx(
560
+ "svg",
561
+ {
562
+ width: "9",
563
+ height: "9",
564
+ viewBox: "0 0 10 10",
565
+ "aria-hidden": true,
566
+ className: "opacity-60 transition-transform " + (open ? "rotate-180" : "rotate-0"),
567
+ children: /* @__PURE__ */ jsx(
568
+ "path",
569
+ {
570
+ d: "M2 4 L5 7 L8 4",
571
+ stroke: "currentColor",
572
+ strokeWidth: "1.5",
573
+ fill: "none",
574
+ strokeLinecap: "round"
575
+ }
576
+ )
577
+ }
578
+ )
579
+ ]
580
+ }
581
+ ),
582
+ open && /* @__PURE__ */ jsxs(
583
+ "div",
584
+ {
585
+ role: "menu",
586
+ "aria-label": "Account menu",
587
+ className: popoverClassName ?? "border-border bg-popover text-popover-foreground absolute top-[calc(100%+6px)] right-0 z-50 w-[min(18rem,calc(100vw-1rem))] border shadow-xl",
588
+ "data-oc-account-menu-popover": "",
589
+ children: [
590
+ /* @__PURE__ */ jsxs("div", { className: "border-border border-b p-3", children: [
591
+ /* @__PURE__ */ jsxs("div", { className: "text-primary mb-1 font-mono text-[10px] tracking-widest uppercase", children: [
592
+ "\xA7 signed in \xB7 ",
593
+ hostname
594
+ ] }),
595
+ /* @__PURE__ */ jsx("div", { className: "text-foreground/90 font-mono text-[11px] leading-tight break-all", children: account.didOc }),
596
+ displayName ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground/80 mt-1 font-mono text-[10px] tracking-wide", children: displayName }) : null
597
+ ] }),
598
+ /* @__PURE__ */ jsxs("div", { className: "p-1", children: [
599
+ menuItems?.map((item) => {
600
+ const onClick = () => setOpen(false);
601
+ const cls = "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors";
602
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
603
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
604
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
605
+ item.external ? /* @__PURE__ */ jsx(
606
+ "span",
607
+ {
608
+ className: "text-muted-foreground/70 text-[10px]",
609
+ "aria-hidden": true,
610
+ children: "\u2197"
611
+ }
612
+ ) : null
613
+ ] });
614
+ return item.external ? /* @__PURE__ */ jsx(
615
+ "a",
616
+ {
617
+ href: item.href,
618
+ target: "_blank",
619
+ rel: "noreferrer",
620
+ onClick,
621
+ role: "menuitem",
622
+ className: cls,
623
+ "data-oc-account-menu-item": "",
624
+ children: inner
625
+ },
626
+ item.href
627
+ ) : /* @__PURE__ */ jsx(
628
+ Link,
629
+ {
630
+ href: item.href,
631
+ onClick,
632
+ role: "menuitem",
633
+ className: cls,
634
+ "data-oc-account-menu-item": "",
635
+ children: inner
636
+ },
637
+ item.href
638
+ );
639
+ }),
640
+ familyDashboardEnabled ? /* @__PURE__ */ jsxs(
641
+ "a",
642
+ {
643
+ href: "https://ochk.io/dashboard",
644
+ target: "_blank",
645
+ rel: "noreferrer",
646
+ onClick: () => setOpen(false),
647
+ role: "menuitem",
648
+ className: "hover:bg-accent flex items-center gap-2 px-3 py-2 font-mono text-[11px] tracking-wide transition-colors",
649
+ "data-oc-account-menu-item": "",
650
+ "data-oc-account-menu-family-dashboard": "",
651
+ children: [
652
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
653
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "family dashboard" }),
654
+ /* @__PURE__ */ jsx(
655
+ "span",
656
+ {
657
+ className: "text-muted-foreground/70 text-[10px]",
658
+ "aria-hidden": true,
659
+ children: "\u2197"
660
+ }
661
+ )
662
+ ]
663
+ }
664
+ ) : null,
665
+ /* @__PURE__ */ jsxs(
666
+ "button",
667
+ {
668
+ type: "button",
669
+ role: "menuitem",
670
+ onClick: () => {
671
+ setOpen(false);
672
+ void signOut();
673
+ },
674
+ 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",
675
+ "data-oc-account-menu-item": "",
676
+ "data-oc-account-menu-signout": "",
677
+ children: [
678
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2192" }),
679
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "sign out" })
680
+ ]
681
+ }
682
+ )
683
+ ] }),
684
+ build ? /* @__PURE__ */ jsx(BuildFooter, { hostname, build, state: siteState }) : null
685
+ ]
686
+ }
687
+ )
688
+ ]
689
+ }
690
+ );
691
+ }
692
+ function BuildFooter({
693
+ hostname,
694
+ build,
695
+ state
696
+ }) {
697
+ const sha = build.sha;
698
+ const showSha = !!sha && sha !== "dev";
699
+ const commitUrl = showSha && build.repo ? `https://github.com/${build.repo}/commit/${sha}` : null;
700
+ return /* @__PURE__ */ jsxs(
701
+ "div",
702
+ {
703
+ className: "text-muted-foreground/60 border-border border-t px-3 py-2 font-mono text-[9.5px] tracking-widest uppercase",
704
+ "data-oc-account-menu-build": "",
705
+ children: [
706
+ hostname,
707
+ state && state !== "live" ? /* @__PURE__ */ jsxs(Fragment, { children: [
708
+ " \xB7 ",
709
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/80", children: state })
710
+ ] }) : null,
711
+ " ",
712
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/80", children: [
713
+ "v",
714
+ build.version,
715
+ showSha ? /* @__PURE__ */ jsxs(Fragment, { children: [
716
+ " \xB7 ",
717
+ commitUrl ? /* @__PURE__ */ jsx(
718
+ "a",
719
+ {
720
+ href: commitUrl,
721
+ target: "_blank",
722
+ rel: "noreferrer",
723
+ className: "hover:text-foreground/90 underline decoration-dotted underline-offset-2",
724
+ children: sha
725
+ }
726
+ ) : sha
727
+ ] }) : null
728
+ ] })
729
+ ]
730
+ }
731
+ );
732
+ }
374
733
  function AppShell({
375
734
  eyebrow,
376
735
  title,
@@ -494,6 +853,6 @@ function StatTile({ children, ...item }) {
494
853
  ] });
495
854
  }
496
855
 
497
- export { AppShell, EcosystemSwitcher, EmptyState, OcLogoDropdown, SectionHeader, StatGrid, StatTile };
856
+ export { AppShell, EcosystemSwitcher, EmptyState, FAMILY_PROPERTIES, OcAccountMenu, OcLogoDropdown, SITE_STATE_LABEL, SectionHeader, StatGrid, StatTile, findFamilyProperty };
498
857
  //# sourceMappingURL=index.mjs.map
499
858
  //# sourceMappingURL=index.mjs.map