@orangecheck/design 0.2.0 → 0.4.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/format.d.mts +19 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.js +68 -0
- package/dist/format.js.map +1 -0
- package/dist/format.mjs +58 -0
- package/dist/format.mjs.map +1 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +490 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +471 -3
- package/dist/index.mjs.map +1 -1
- package/dist/primitives.d.mts +92 -1
- package/dist/primitives.d.ts +92 -1
- package/dist/primitives.js +319 -0
- package/dist/primitives.js.map +1 -1
- package/dist/primitives.mjs +310 -3
- package/dist/primitives.mjs.map +1 -1
- package/dist/tokens.d.mts +8 -1
- package/dist/tokens.d.ts +8 -1
- package/dist/tokens.js +110 -0
- package/dist/tokens.js.map +1 -1
- package/dist/tokens.mjs +111 -2
- package/dist/tokens.mjs.map +1 -1
- package/package.json +8 -1
package/dist/index.mjs
CHANGED
|
@@ -2,9 +2,9 @@ import { clsx } from 'clsx';
|
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
3
|
import * as React2 from 'react';
|
|
4
4
|
import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
|
|
5
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { useTheme } from 'next-themes';
|
|
7
|
-
import { ChevronDown, Palette, Check, Sun, Moon, X, XIcon, AlertTriangle, Pencil, ChevronLeft, ChevronRight, ChevronDownIcon, CheckIcon, ChevronUpIcon } from 'lucide-react';
|
|
7
|
+
import { ChevronDown, Palette, Check, Sun, Moon, Monitor, X, XIcon, AlertTriangle, Pencil, ChevronLeft, ChevronRight, ChevronDownIcon, CheckIcon, ChevronUpIcon, Maximize2, Copy } from 'lucide-react';
|
|
8
8
|
import { Slot } from '@radix-ui/react-slot';
|
|
9
9
|
import { cva } from 'class-variance-authority';
|
|
10
10
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
@@ -14,6 +14,7 @@ import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
|
14
14
|
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
15
15
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
16
16
|
import { Toaster as Toaster$1 } from 'sonner';
|
|
17
|
+
import QRCode from 'qrcode';
|
|
17
18
|
import * as ui_star from '@orangecheck/ui';
|
|
18
19
|
|
|
19
20
|
var __defProp = Object.defineProperty;
|
|
@@ -47,8 +48,12 @@ __export(src_exports, {
|
|
|
47
48
|
AlertWithAction: () => AlertWithAction,
|
|
48
49
|
AlertWithCountdown: () => AlertWithCountdown,
|
|
49
50
|
Badge: () => Badge,
|
|
51
|
+
Bar: () => Bar,
|
|
52
|
+
BitcoinAddress: () => BitcoinAddress,
|
|
50
53
|
Button: () => Button,
|
|
54
|
+
Card: () => Card,
|
|
51
55
|
ConfirmHost: () => ConfirmHost,
|
|
56
|
+
CopyButton: () => CopyButton,
|
|
52
57
|
DEFAULT_OC_THEME: () => DEFAULT_OC_THEME,
|
|
53
58
|
Dialog: () => Dialog,
|
|
54
59
|
DialogClose: () => DialogClose,
|
|
@@ -66,6 +71,7 @@ __export(src_exports, {
|
|
|
66
71
|
Modal: () => Modal,
|
|
67
72
|
OC_SKIN_COOKIE: () => OC_SKIN_COOKIE,
|
|
68
73
|
OC_THEMES: () => OC_THEMES,
|
|
74
|
+
OcAppearanceMenu: () => OcAppearanceMenu,
|
|
69
75
|
OcThemeBridge: () => OcThemeBridge,
|
|
70
76
|
OcThemePicker: () => OcThemePicker,
|
|
71
77
|
OcThemeProvider: () => OcThemeProvider,
|
|
@@ -75,6 +81,9 @@ __export(src_exports, {
|
|
|
75
81
|
PopoverContent: () => PopoverContent,
|
|
76
82
|
PopoverTrigger: () => PopoverTrigger,
|
|
77
83
|
PromptHost: () => PromptHost,
|
|
84
|
+
QrCode: () => QrCode,
|
|
85
|
+
REFERENCE_BTC_USD: () => REFERENCE_BTC_USD,
|
|
86
|
+
SatsAmount: () => SatsAmount,
|
|
78
87
|
Select: () => Select,
|
|
79
88
|
SelectContent: () => SelectContent,
|
|
80
89
|
SelectGroup: () => SelectGroup,
|
|
@@ -95,6 +104,9 @@ __export(src_exports, {
|
|
|
95
104
|
SheetTitle: () => SheetTitle,
|
|
96
105
|
SheetTrigger: () => SheetTrigger,
|
|
97
106
|
Skeleton: () => Skeleton,
|
|
107
|
+
Sparkline: () => Sparkline,
|
|
108
|
+
StatBlock: () => StatBlock,
|
|
109
|
+
StatusPill: () => StatusPill,
|
|
98
110
|
Textarea: () => Textarea,
|
|
99
111
|
ThemeToggle: () => ThemeToggle,
|
|
100
112
|
ThemeToggleLink: () => ThemeToggleLink,
|
|
@@ -105,10 +117,18 @@ __export(src_exports, {
|
|
|
105
117
|
buttonVariants: () => buttonVariants,
|
|
106
118
|
cn: () => cn,
|
|
107
119
|
confirm: () => confirm,
|
|
120
|
+
explorerUrl: () => explorerUrl,
|
|
121
|
+
formatSats: () => formatSats,
|
|
122
|
+
formatSatsCompact: () => formatSatsCompact,
|
|
108
123
|
getOcThemeInitScript: () => getOcThemeInitScript,
|
|
109
124
|
isKnownTheme: () => isKnownTheme,
|
|
125
|
+
priceBoth: () => priceBoth,
|
|
110
126
|
prompt: () => prompt,
|
|
127
|
+
relativeTime: () => relativeTime,
|
|
111
128
|
resolveTheme: () => resolveTheme,
|
|
129
|
+
satsToUsd: () => satsToUsd,
|
|
130
|
+
shortenAddress: () => shortenAddress,
|
|
131
|
+
usdToSats: () => usdToSats,
|
|
112
132
|
useOcSkin: () => useOcSkin
|
|
113
133
|
});
|
|
114
134
|
function cn(...inputs) {
|
|
@@ -353,6 +373,115 @@ function OcThemePicker({ className, triggerClassName, popoverClassName }) {
|
|
|
353
373
|
)
|
|
354
374
|
] });
|
|
355
375
|
}
|
|
376
|
+
var MODES = [
|
|
377
|
+
{ id: "light", label: "light", Icon: Sun },
|
|
378
|
+
{ id: "dark", label: "dark", Icon: Moon },
|
|
379
|
+
{ id: "system", label: "system", Icon: Monitor }
|
|
380
|
+
];
|
|
381
|
+
function OcAppearanceMenu({
|
|
382
|
+
className,
|
|
383
|
+
triggerClassName,
|
|
384
|
+
popoverClassName
|
|
385
|
+
}) {
|
|
386
|
+
const { skin, setSkin, themes } = useOcSkin();
|
|
387
|
+
const { theme, setTheme } = useTheme();
|
|
388
|
+
const [open, setOpen] = useState(false);
|
|
389
|
+
const [mounted, setMounted] = useState(false);
|
|
390
|
+
const rootRef = useRef(null);
|
|
391
|
+
useEffect(() => setMounted(true), []);
|
|
392
|
+
useEffect(() => {
|
|
393
|
+
if (!open) return;
|
|
394
|
+
function onDown(e) {
|
|
395
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
|
|
396
|
+
}
|
|
397
|
+
function onKey(e) {
|
|
398
|
+
if (e.key === "Escape") setOpen(false);
|
|
399
|
+
}
|
|
400
|
+
document.addEventListener("mousedown", onDown);
|
|
401
|
+
document.addEventListener("keydown", onKey);
|
|
402
|
+
return () => {
|
|
403
|
+
document.removeEventListener("mousedown", onDown);
|
|
404
|
+
document.removeEventListener("keydown", onKey);
|
|
405
|
+
};
|
|
406
|
+
}, [open]);
|
|
407
|
+
const activeMode = mounted ? theme ?? "system" : null;
|
|
408
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative", className), children: [
|
|
409
|
+
/* @__PURE__ */ jsx(
|
|
410
|
+
"button",
|
|
411
|
+
{
|
|
412
|
+
type: "button",
|
|
413
|
+
"aria-label": "appearance settings",
|
|
414
|
+
"aria-haspopup": "menu",
|
|
415
|
+
"aria-expanded": open,
|
|
416
|
+
title: "appearance \xB7 mode + theme",
|
|
417
|
+
onClick: () => setOpen((v) => !v),
|
|
418
|
+
className: cn(
|
|
419
|
+
"text-muted-foreground hover:text-foreground inline-flex size-9 items-center justify-center rounded-md transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
420
|
+
triggerClassName
|
|
421
|
+
),
|
|
422
|
+
children: /* @__PURE__ */ jsx(Palette, { className: "size-4", "aria-hidden": true })
|
|
423
|
+
}
|
|
424
|
+
),
|
|
425
|
+
open && /* @__PURE__ */ jsxs(
|
|
426
|
+
"div",
|
|
427
|
+
{
|
|
428
|
+
role: "menu",
|
|
429
|
+
className: cn(
|
|
430
|
+
"bg-popover text-popover-foreground absolute right-0 z-50 mt-2 w-64 overflow-hidden rounded-md border shadow-md",
|
|
431
|
+
popoverClassName
|
|
432
|
+
),
|
|
433
|
+
children: [
|
|
434
|
+
/* @__PURE__ */ jsx("div", { className: "label-mono text-muted-foreground px-3 pt-3 pb-2", children: "mode" }),
|
|
435
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 px-2 pb-2", children: MODES.map(({ id, label, Icon: Icon2 }) => {
|
|
436
|
+
const active = activeMode === id;
|
|
437
|
+
return /* @__PURE__ */ jsxs(
|
|
438
|
+
"button",
|
|
439
|
+
{
|
|
440
|
+
type: "button",
|
|
441
|
+
role: "menuitemradio",
|
|
442
|
+
"aria-checked": active,
|
|
443
|
+
onClick: () => setTheme(id),
|
|
444
|
+
className: cn(
|
|
445
|
+
"flex flex-col items-center gap-1 rounded-md border py-2 text-[11px] transition-colors",
|
|
446
|
+
active ? "border-primary text-foreground bg-accent" : "border-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
447
|
+
),
|
|
448
|
+
children: [
|
|
449
|
+
/* @__PURE__ */ jsx(Icon2, { className: "size-4", "aria-hidden": true }),
|
|
450
|
+
label
|
|
451
|
+
]
|
|
452
|
+
},
|
|
453
|
+
id
|
|
454
|
+
);
|
|
455
|
+
}) }),
|
|
456
|
+
/* @__PURE__ */ jsx("div", { className: "label-mono text-muted-foreground border-t px-3 pt-3 pb-1", children: "theme" }),
|
|
457
|
+
/* @__PURE__ */ jsx("ul", { className: "pb-1", children: themes.map((t) => {
|
|
458
|
+
const active = t.id === skin;
|
|
459
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
460
|
+
"button",
|
|
461
|
+
{
|
|
462
|
+
type: "button",
|
|
463
|
+
role: "menuitemradio",
|
|
464
|
+
"aria-checked": active,
|
|
465
|
+
onClick: () => setSkin(t.id),
|
|
466
|
+
className: cn(
|
|
467
|
+
"hover:bg-accent hover:text-accent-foreground flex w-full items-start gap-2 px-3 py-2 text-left transition-colors",
|
|
468
|
+
active && "text-foreground"
|
|
469
|
+
),
|
|
470
|
+
children: [
|
|
471
|
+
/* @__PURE__ */ jsx("span", { className: "mt-0.5 size-4 shrink-0", children: active && /* @__PURE__ */ jsx(Check, { className: "text-primary size-4", "aria-hidden": true }) }),
|
|
472
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
|
|
473
|
+
/* @__PURE__ */ jsx("span", { className: "block text-sm font-medium", children: t.label }),
|
|
474
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground block text-xs leading-snug", children: t.description })
|
|
475
|
+
] })
|
|
476
|
+
]
|
|
477
|
+
}
|
|
478
|
+
) }, t.id);
|
|
479
|
+
}) })
|
|
480
|
+
]
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
] });
|
|
484
|
+
}
|
|
356
485
|
var buttonVariants = cva(
|
|
357
486
|
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
358
487
|
{
|
|
@@ -1475,6 +1604,345 @@ var Toaster = ({ ...props }) => {
|
|
|
1475
1604
|
}
|
|
1476
1605
|
);
|
|
1477
1606
|
};
|
|
1607
|
+
function Card({
|
|
1608
|
+
id,
|
|
1609
|
+
title,
|
|
1610
|
+
subtitle,
|
|
1611
|
+
refreshedAt,
|
|
1612
|
+
actions,
|
|
1613
|
+
children,
|
|
1614
|
+
className,
|
|
1615
|
+
tone = "default",
|
|
1616
|
+
expandable = true
|
|
1617
|
+
}) {
|
|
1618
|
+
const [expanded, setExpanded] = useState(false);
|
|
1619
|
+
const toneClass = tone === "warning" ? "border-warning/60" : tone === "destructive" ? "border-destructive/60" : tone === "muted" ? "border-border opacity-90" : "border-border";
|
|
1620
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1621
|
+
/* @__PURE__ */ jsxs(
|
|
1622
|
+
"section",
|
|
1623
|
+
{
|
|
1624
|
+
id,
|
|
1625
|
+
className: cn("terminal flex flex-col rounded-sm border scroll-mt-16", toneClass, className),
|
|
1626
|
+
children: [
|
|
1627
|
+
/* @__PURE__ */ jsxs("div", { className: "terminal-title flex items-center justify-between gap-3", children: [
|
|
1628
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1629
|
+
/* @__PURE__ */ jsx("span", { className: "terminal-dot", "aria-hidden": true }),
|
|
1630
|
+
/* @__PURE__ */ jsx("span", { className: "terminal-dot opacity-70", "aria-hidden": true }),
|
|
1631
|
+
/* @__PURE__ */ jsx("span", { className: "terminal-dot opacity-50", "aria-hidden": true }),
|
|
1632
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2 truncate", children: title }),
|
|
1633
|
+
subtitle && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/70 ml-1 truncate text-[10px] tracking-normal normal-case", children: [
|
|
1634
|
+
"\xB7 ",
|
|
1635
|
+
subtitle
|
|
1636
|
+
] })
|
|
1637
|
+
] }),
|
|
1638
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1639
|
+
refreshedAt && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/60 hidden text-[10px] tracking-normal normal-case sm:inline", children: refreshedAt }),
|
|
1640
|
+
actions,
|
|
1641
|
+
expandable && /* @__PURE__ */ jsx(
|
|
1642
|
+
"button",
|
|
1643
|
+
{
|
|
1644
|
+
type: "button",
|
|
1645
|
+
onClick: () => setExpanded(true),
|
|
1646
|
+
"aria-label": `expand ${title}`,
|
|
1647
|
+
title: "expand to fullscreen",
|
|
1648
|
+
className: "text-muted-foreground/70 hover:text-foreground inline-flex h-6 w-6 items-center justify-center rounded-sm",
|
|
1649
|
+
children: /* @__PURE__ */ jsx(Maximize2, { className: "size-3" })
|
|
1650
|
+
}
|
|
1651
|
+
)
|
|
1652
|
+
] })
|
|
1653
|
+
] }),
|
|
1654
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 p-4 sm:p-5", children })
|
|
1655
|
+
]
|
|
1656
|
+
}
|
|
1657
|
+
),
|
|
1658
|
+
expandable && /* @__PURE__ */ jsx(
|
|
1659
|
+
Modal,
|
|
1660
|
+
{
|
|
1661
|
+
open: expanded,
|
|
1662
|
+
onOpenChange: setExpanded,
|
|
1663
|
+
title,
|
|
1664
|
+
...subtitle ? { subtitle } : {},
|
|
1665
|
+
actions: refreshedAt ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/60 hidden text-[10px] tracking-normal normal-case sm:inline", children: refreshedAt }) : null,
|
|
1666
|
+
children
|
|
1667
|
+
}
|
|
1668
|
+
)
|
|
1669
|
+
] });
|
|
1670
|
+
}
|
|
1671
|
+
function Sparkline({ data, width = 96, height = 24, area = false, className }) {
|
|
1672
|
+
if (data.length === 0) {
|
|
1673
|
+
return /* @__PURE__ */ jsx("svg", { width, height, className: cn(className), "aria-hidden": true, children: /* @__PURE__ */ jsx(
|
|
1674
|
+
"line",
|
|
1675
|
+
{
|
|
1676
|
+
x1: 0,
|
|
1677
|
+
x2: width,
|
|
1678
|
+
y1: height / 2,
|
|
1679
|
+
y2: height / 2,
|
|
1680
|
+
stroke: "currentColor",
|
|
1681
|
+
strokeWidth: 1,
|
|
1682
|
+
opacity: 0.25
|
|
1683
|
+
}
|
|
1684
|
+
) });
|
|
1685
|
+
}
|
|
1686
|
+
const min = Math.min(...data);
|
|
1687
|
+
const max = Math.max(...data);
|
|
1688
|
+
const range = max - min || 1;
|
|
1689
|
+
const step = data.length === 1 ? width : width / (data.length - 1);
|
|
1690
|
+
const points = data.map((v, i) => {
|
|
1691
|
+
const x = i * step;
|
|
1692
|
+
const y = height - (v - min) / range * (height - 2) - 1;
|
|
1693
|
+
return [x, y];
|
|
1694
|
+
});
|
|
1695
|
+
const linePath = points.map(([x, y], i) => `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
|
|
1696
|
+
const areaPath = area ? `${linePath} L${width.toFixed(2)},${height.toFixed(2)} L0,${height.toFixed(2)} Z` : null;
|
|
1697
|
+
return /* @__PURE__ */ jsxs(
|
|
1698
|
+
"svg",
|
|
1699
|
+
{
|
|
1700
|
+
width,
|
|
1701
|
+
height,
|
|
1702
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
1703
|
+
className: cn("text-primary", className),
|
|
1704
|
+
"aria-hidden": true,
|
|
1705
|
+
children: [
|
|
1706
|
+
areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "currentColor", opacity: 0.12 }),
|
|
1707
|
+
/* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "currentColor", strokeWidth: 1.25 })
|
|
1708
|
+
]
|
|
1709
|
+
}
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
function StatBlock({ label, value, sub, delta, tone = "default", className }) {
|
|
1713
|
+
const toneClass = tone === "success" ? "text-success" : tone === "warning" ? "text-warning" : tone === "destructive" ? "text-destructive" : "text-foreground";
|
|
1714
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1", className), children: [
|
|
1715
|
+
/* @__PURE__ */ jsx("span", { className: "label-mono text-[10px]", children: label }),
|
|
1716
|
+
/* @__PURE__ */ jsx("span", { className: cn("font-display text-2xl leading-none", toneClass), children: value }),
|
|
1717
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
1718
|
+
sub && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-mono text-[11px] tracking-wide lowercase", children: sub }),
|
|
1719
|
+
delta && /* @__PURE__ */ jsxs(
|
|
1720
|
+
"span",
|
|
1721
|
+
{
|
|
1722
|
+
className: cn(
|
|
1723
|
+
"font-mono text-[11px] tracking-wide",
|
|
1724
|
+
delta.value > 0 ? "text-success" : delta.value < 0 ? "text-destructive" : "text-muted-foreground"
|
|
1725
|
+
),
|
|
1726
|
+
children: [
|
|
1727
|
+
delta.value > 0 ? "\u25B2" : delta.value < 0 ? "\u25BC" : "\xB7",
|
|
1728
|
+
" ",
|
|
1729
|
+
Math.abs(delta.value).toFixed(1),
|
|
1730
|
+
delta.suffix ?? "%"
|
|
1731
|
+
]
|
|
1732
|
+
}
|
|
1733
|
+
)
|
|
1734
|
+
] })
|
|
1735
|
+
] });
|
|
1736
|
+
}
|
|
1737
|
+
var ACCENT = {
|
|
1738
|
+
primary: "bg-primary",
|
|
1739
|
+
warning: "bg-warning",
|
|
1740
|
+
destructive: "bg-destructive",
|
|
1741
|
+
success: "bg-success"
|
|
1742
|
+
};
|
|
1743
|
+
function Bar({ pct, accent = "primary", label, right, className }) {
|
|
1744
|
+
const clamped = Math.max(0, Math.min(100, pct));
|
|
1745
|
+
return /* @__PURE__ */ jsxs("div", { className: cn(className), children: [
|
|
1746
|
+
(label || right) && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between font-mono text-[10.5px] tracking-widest uppercase", children: [
|
|
1747
|
+
label && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
1748
|
+
right && /* @__PURE__ */ jsx("span", { className: "text-foreground tabular-nums", children: right })
|
|
1749
|
+
] }),
|
|
1750
|
+
/* @__PURE__ */ jsx("div", { className: "bg-muted mt-1.5 h-1.5 w-full overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: cn("h-full", ACCENT[accent]), style: { width: `${clamped}%` } }) })
|
|
1751
|
+
] });
|
|
1752
|
+
}
|
|
1753
|
+
var TONE = {
|
|
1754
|
+
success: "text-success",
|
|
1755
|
+
warning: "text-warning",
|
|
1756
|
+
destructive: "text-destructive",
|
|
1757
|
+
muted: "text-muted-foreground",
|
|
1758
|
+
primary: "text-primary",
|
|
1759
|
+
info: "text-info"
|
|
1760
|
+
};
|
|
1761
|
+
function StatusPill({ label, tone = "muted", icon, className }) {
|
|
1762
|
+
return /* @__PURE__ */ jsxs(
|
|
1763
|
+
"span",
|
|
1764
|
+
{
|
|
1765
|
+
className: cn(
|
|
1766
|
+
"inline-flex items-center gap-1.5 font-mono text-[11px] tracking-wider lowercase",
|
|
1767
|
+
TONE[tone],
|
|
1768
|
+
className
|
|
1769
|
+
),
|
|
1770
|
+
children: [
|
|
1771
|
+
icon,
|
|
1772
|
+
label
|
|
1773
|
+
]
|
|
1774
|
+
}
|
|
1775
|
+
);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// src/format/index.ts
|
|
1779
|
+
var REFERENCE_BTC_USD = 95e3;
|
|
1780
|
+
function formatSats(sats) {
|
|
1781
|
+
return new Intl.NumberFormat("en-US").format(Math.round(sats));
|
|
1782
|
+
}
|
|
1783
|
+
function formatSatsCompact(sats) {
|
|
1784
|
+
const n = Math.round(sats);
|
|
1785
|
+
if (n < 1e3) return `${n} sats`;
|
|
1786
|
+
const k = n / 1e3;
|
|
1787
|
+
return `${Number.isInteger(k) ? k : k.toFixed(1)}k sats`;
|
|
1788
|
+
}
|
|
1789
|
+
function satsToUsd(sats, btcUsd = REFERENCE_BTC_USD) {
|
|
1790
|
+
const usd = sats / 1e8 * btcUsd;
|
|
1791
|
+
if (usd > 0 && usd < 0.01) return "< $0.01";
|
|
1792
|
+
const fractionDigits = usd >= 100 ? 0 : 2;
|
|
1793
|
+
return new Intl.NumberFormat("en-US", {
|
|
1794
|
+
style: "currency",
|
|
1795
|
+
currency: "USD",
|
|
1796
|
+
minimumFractionDigits: fractionDigits,
|
|
1797
|
+
maximumFractionDigits: fractionDigits
|
|
1798
|
+
}).format(usd);
|
|
1799
|
+
}
|
|
1800
|
+
function usdToSats(usd, btcUsd = REFERENCE_BTC_USD) {
|
|
1801
|
+
return Math.round(usd / btcUsd * 1e8);
|
|
1802
|
+
}
|
|
1803
|
+
function priceBoth(sats, btcUsd = REFERENCE_BTC_USD) {
|
|
1804
|
+
return `${formatSats(sats)} sats \xB7 ${satsToUsd(sats, btcUsd)}`;
|
|
1805
|
+
}
|
|
1806
|
+
function relativeTime(when) {
|
|
1807
|
+
const t = when instanceof Date ? when.getTime() : new Date(when).getTime();
|
|
1808
|
+
if (Number.isNaN(t)) return "";
|
|
1809
|
+
const diff = Date.now() - t;
|
|
1810
|
+
const m = Math.floor(diff / 6e4);
|
|
1811
|
+
if (m < 1) return "now";
|
|
1812
|
+
if (m < 60) return `${m}m ago`;
|
|
1813
|
+
const h = Math.floor(m / 60);
|
|
1814
|
+
if (h < 24) return `${h}h ago`;
|
|
1815
|
+
const d = Math.floor(h / 24);
|
|
1816
|
+
if (d < 30) return `${d}d ago`;
|
|
1817
|
+
const mo = Math.floor(d / 30);
|
|
1818
|
+
if (mo < 12) return `${mo}mo ago`;
|
|
1819
|
+
return `${Math.floor(mo / 12)}y ago`;
|
|
1820
|
+
}
|
|
1821
|
+
function shortenAddress(value, head = 8, tail = 4) {
|
|
1822
|
+
if (!value) return "";
|
|
1823
|
+
if (value.length <= head + tail + 1) return value;
|
|
1824
|
+
return `${value.slice(0, head)}\u2026${value.slice(-tail)}`;
|
|
1825
|
+
}
|
|
1826
|
+
function explorerUrl(target, network = "mainnet") {
|
|
1827
|
+
const base = network === "mainnet" ? "https://mempool.space" : `https://mempool.space/${network}`;
|
|
1828
|
+
if ("address" in target) return `${base}/address/${target.address}`;
|
|
1829
|
+
if ("tx" in target) return `${base}/tx/${target.tx}`;
|
|
1830
|
+
return `${base}/block/${target.block}`;
|
|
1831
|
+
}
|
|
1832
|
+
function SatsAmount({ sats, unit = true, usd = false, btcUsd, className }) {
|
|
1833
|
+
return /* @__PURE__ */ jsxs("span", { className: cn("font-mono tabular-nums", className), children: [
|
|
1834
|
+
formatSats(sats),
|
|
1835
|
+
unit && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: " sats" }),
|
|
1836
|
+
usd && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
1837
|
+
" \xB7 ",
|
|
1838
|
+
satsToUsd(sats, btcUsd)
|
|
1839
|
+
] })
|
|
1840
|
+
] });
|
|
1841
|
+
}
|
|
1842
|
+
function CopyButton({
|
|
1843
|
+
value,
|
|
1844
|
+
label,
|
|
1845
|
+
clearAfter,
|
|
1846
|
+
size = "md",
|
|
1847
|
+
className,
|
|
1848
|
+
title,
|
|
1849
|
+
onCopied
|
|
1850
|
+
}) {
|
|
1851
|
+
const [copied, setCopied] = useState(false);
|
|
1852
|
+
const resetRef = useRef(null);
|
|
1853
|
+
const copy = useCallback(async () => {
|
|
1854
|
+
try {
|
|
1855
|
+
await navigator.clipboard.writeText(value);
|
|
1856
|
+
setCopied(true);
|
|
1857
|
+
onCopied?.();
|
|
1858
|
+
if (resetRef.current) clearTimeout(resetRef.current);
|
|
1859
|
+
resetRef.current = setTimeout(() => setCopied(false), 1500);
|
|
1860
|
+
if (clearAfter && clearAfter > 0) {
|
|
1861
|
+
setTimeout(() => void wipeIfUnchanged(value), clearAfter * 1e3);
|
|
1862
|
+
}
|
|
1863
|
+
} catch {
|
|
1864
|
+
}
|
|
1865
|
+
}, [value, clearAfter, onCopied]);
|
|
1866
|
+
const iconSize = size === "sm" ? "size-3" : "size-3.5";
|
|
1867
|
+
return /* @__PURE__ */ jsxs(
|
|
1868
|
+
"button",
|
|
1869
|
+
{
|
|
1870
|
+
type: "button",
|
|
1871
|
+
onClick: copy,
|
|
1872
|
+
"aria-label": title ?? (copied ? "copied" : "copy"),
|
|
1873
|
+
title: title ?? "copy",
|
|
1874
|
+
className: cn(
|
|
1875
|
+
"text-muted-foreground hover:text-foreground inline-flex items-center gap-1.5 rounded-sm transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
1876
|
+
size === "sm" ? "text-[11px]" : "text-xs",
|
|
1877
|
+
className
|
|
1878
|
+
),
|
|
1879
|
+
children: [
|
|
1880
|
+
copied ? /* @__PURE__ */ jsx(Check, { className: cn(iconSize, "text-success"), "aria-hidden": true }) : /* @__PURE__ */ jsx(Copy, { className: iconSize, "aria-hidden": true }),
|
|
1881
|
+
label && /* @__PURE__ */ jsx("span", { className: "font-mono", children: copied ? "copied" : label })
|
|
1882
|
+
]
|
|
1883
|
+
}
|
|
1884
|
+
);
|
|
1885
|
+
}
|
|
1886
|
+
async function wipeIfUnchanged(expected) {
|
|
1887
|
+
try {
|
|
1888
|
+
const current = await navigator.clipboard.readText();
|
|
1889
|
+
if (current !== expected) return;
|
|
1890
|
+
await navigator.clipboard.writeText("");
|
|
1891
|
+
} catch {
|
|
1892
|
+
try {
|
|
1893
|
+
await navigator.clipboard.writeText("");
|
|
1894
|
+
} catch {
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
function BitcoinAddress({
|
|
1899
|
+
address,
|
|
1900
|
+
head = 8,
|
|
1901
|
+
tail = 4,
|
|
1902
|
+
copyable = true,
|
|
1903
|
+
full = false,
|
|
1904
|
+
className
|
|
1905
|
+
}) {
|
|
1906
|
+
return /* @__PURE__ */ jsxs("span", { className: cn("inline-flex items-center gap-1.5 font-mono text-xs", className), children: [
|
|
1907
|
+
/* @__PURE__ */ jsx("span", { title: address, children: full ? address : shortenAddress(address, head, tail) }),
|
|
1908
|
+
copyable && /* @__PURE__ */ jsx(CopyButton, { value: address, size: "sm", title: "copy address" })
|
|
1909
|
+
] });
|
|
1910
|
+
}
|
|
1911
|
+
function QrCode({ value, size = 200, label, className }) {
|
|
1912
|
+
const [svg, setSvg] = useState(null);
|
|
1913
|
+
useEffect(() => {
|
|
1914
|
+
let cancelled = false;
|
|
1915
|
+
QRCode.toString(value, {
|
|
1916
|
+
type: "svg",
|
|
1917
|
+
errorCorrectionLevel: "M",
|
|
1918
|
+
margin: 1,
|
|
1919
|
+
color: { dark: "#000000", light: "#ffffff" }
|
|
1920
|
+
}).then((out) => {
|
|
1921
|
+
if (!cancelled) setSvg(out);
|
|
1922
|
+
}).catch(() => {
|
|
1923
|
+
if (!cancelled) setSvg(null);
|
|
1924
|
+
});
|
|
1925
|
+
return () => {
|
|
1926
|
+
cancelled = true;
|
|
1927
|
+
};
|
|
1928
|
+
}, [value]);
|
|
1929
|
+
return /* @__PURE__ */ jsx(
|
|
1930
|
+
"div",
|
|
1931
|
+
{
|
|
1932
|
+
role: "img",
|
|
1933
|
+
"aria-label": label ?? `QR code for ${value.slice(0, 24)}\u2026`,
|
|
1934
|
+
className: "inline-block overflow-hidden rounded-md bg-white p-3 " + (className ?? ""),
|
|
1935
|
+
style: { width: size, height: size },
|
|
1936
|
+
children: svg ? /* @__PURE__ */ jsx(
|
|
1937
|
+
"div",
|
|
1938
|
+
{
|
|
1939
|
+
className: "size-full [&_svg]:block [&_svg]:size-full",
|
|
1940
|
+
dangerouslySetInnerHTML: { __html: svg }
|
|
1941
|
+
}
|
|
1942
|
+
) : /* @__PURE__ */ jsx("div", { className: "bg-muted/40 size-full animate-pulse rounded", "aria-hidden": true })
|
|
1943
|
+
}
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1478
1946
|
|
|
1479
1947
|
// src/components/index.ts
|
|
1480
1948
|
var components_exports = {};
|
|
@@ -1483,6 +1951,6 @@ __reExport(components_exports, ui_star);
|
|
|
1483
1951
|
// src/index.ts
|
|
1484
1952
|
__reExport(src_exports, components_exports);
|
|
1485
1953
|
|
|
1486
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertTitle, AlertWithAction, AlertWithCountdown, Badge, Button, ConfirmHost, DEFAULT_OC_THEME, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, ErrorBoundary, Input, Label, Modal, OC_SKIN_COOKIE, OC_THEMES, OcThemeBridge, OcThemePicker, OcThemeProvider, Pagination, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PromptHost, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, Textarea, ThemeToggle, ThemeToggleLink, Toaster, Working, WorkingPanel, badgeVariants, buttonVariants, cn, confirm, getOcThemeInitScript, isKnownTheme, prompt, resolveTheme, useOcSkin };
|
|
1954
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertTitle, AlertWithAction, AlertWithCountdown, Badge, Bar, BitcoinAddress, Button, Card, ConfirmHost, CopyButton, DEFAULT_OC_THEME, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, ErrorBoundary, Input, Label, Modal, OC_SKIN_COOKIE, OC_THEMES, OcAppearanceMenu, OcThemeBridge, OcThemePicker, OcThemeProvider, Pagination, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PromptHost, QrCode, REFERENCE_BTC_USD, SatsAmount, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, Sparkline, StatBlock, StatusPill, Textarea, ThemeToggle, ThemeToggleLink, Toaster, Working, WorkingPanel, badgeVariants, buttonVariants, cn, confirm, explorerUrl, formatSats, formatSatsCompact, getOcThemeInitScript, isKnownTheme, priceBoth, prompt, relativeTime, resolveTheme, satsToUsd, shortenAddress, usdToSats, useOcSkin };
|
|
1487
1955
|
//# sourceMappingURL=index.mjs.map
|
|
1488
1956
|
//# sourceMappingURL=index.mjs.map
|