@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.js
CHANGED
|
@@ -15,8 +15,11 @@ var PopoverPrimitive = require('@radix-ui/react-popover');
|
|
|
15
15
|
var AccordionPrimitive = require('@radix-ui/react-accordion');
|
|
16
16
|
var SelectPrimitive = require('@radix-ui/react-select');
|
|
17
17
|
var sonner = require('sonner');
|
|
18
|
+
var QRCode = require('qrcode');
|
|
18
19
|
var ui_star = require('@orangecheck/ui');
|
|
19
20
|
|
|
21
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
|
+
|
|
20
23
|
function _interopNamespace(e) {
|
|
21
24
|
if (e && e.__esModule) return e;
|
|
22
25
|
var n = Object.create(null);
|
|
@@ -42,6 +45,7 @@ var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive)
|
|
|
42
45
|
var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
|
|
43
46
|
var AccordionPrimitive__namespace = /*#__PURE__*/_interopNamespace(AccordionPrimitive);
|
|
44
47
|
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
|
|
48
|
+
var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
|
|
45
49
|
var ui_star__namespace = /*#__PURE__*/_interopNamespace(ui_star);
|
|
46
50
|
|
|
47
51
|
var __defProp = Object.defineProperty;
|
|
@@ -75,8 +79,12 @@ __export(src_exports, {
|
|
|
75
79
|
AlertWithAction: () => AlertWithAction,
|
|
76
80
|
AlertWithCountdown: () => AlertWithCountdown,
|
|
77
81
|
Badge: () => Badge,
|
|
82
|
+
Bar: () => Bar,
|
|
83
|
+
BitcoinAddress: () => BitcoinAddress,
|
|
78
84
|
Button: () => Button,
|
|
85
|
+
Card: () => Card,
|
|
79
86
|
ConfirmHost: () => ConfirmHost,
|
|
87
|
+
CopyButton: () => CopyButton,
|
|
80
88
|
DEFAULT_OC_THEME: () => DEFAULT_OC_THEME,
|
|
81
89
|
Dialog: () => Dialog,
|
|
82
90
|
DialogClose: () => DialogClose,
|
|
@@ -94,6 +102,7 @@ __export(src_exports, {
|
|
|
94
102
|
Modal: () => Modal,
|
|
95
103
|
OC_SKIN_COOKIE: () => OC_SKIN_COOKIE,
|
|
96
104
|
OC_THEMES: () => OC_THEMES,
|
|
105
|
+
OcAppearanceMenu: () => OcAppearanceMenu,
|
|
97
106
|
OcThemeBridge: () => OcThemeBridge,
|
|
98
107
|
OcThemePicker: () => OcThemePicker,
|
|
99
108
|
OcThemeProvider: () => OcThemeProvider,
|
|
@@ -103,6 +112,9 @@ __export(src_exports, {
|
|
|
103
112
|
PopoverContent: () => PopoverContent,
|
|
104
113
|
PopoverTrigger: () => PopoverTrigger,
|
|
105
114
|
PromptHost: () => PromptHost,
|
|
115
|
+
QrCode: () => QrCode,
|
|
116
|
+
REFERENCE_BTC_USD: () => REFERENCE_BTC_USD,
|
|
117
|
+
SatsAmount: () => SatsAmount,
|
|
106
118
|
Select: () => Select,
|
|
107
119
|
SelectContent: () => SelectContent,
|
|
108
120
|
SelectGroup: () => SelectGroup,
|
|
@@ -123,6 +135,9 @@ __export(src_exports, {
|
|
|
123
135
|
SheetTitle: () => SheetTitle,
|
|
124
136
|
SheetTrigger: () => SheetTrigger,
|
|
125
137
|
Skeleton: () => Skeleton,
|
|
138
|
+
Sparkline: () => Sparkline,
|
|
139
|
+
StatBlock: () => StatBlock,
|
|
140
|
+
StatusPill: () => StatusPill,
|
|
126
141
|
Textarea: () => Textarea,
|
|
127
142
|
ThemeToggle: () => ThemeToggle,
|
|
128
143
|
ThemeToggleLink: () => ThemeToggleLink,
|
|
@@ -133,10 +148,18 @@ __export(src_exports, {
|
|
|
133
148
|
buttonVariants: () => buttonVariants,
|
|
134
149
|
cn: () => cn,
|
|
135
150
|
confirm: () => confirm,
|
|
151
|
+
explorerUrl: () => explorerUrl,
|
|
152
|
+
formatSats: () => formatSats,
|
|
153
|
+
formatSatsCompact: () => formatSatsCompact,
|
|
136
154
|
getOcThemeInitScript: () => getOcThemeInitScript,
|
|
137
155
|
isKnownTheme: () => isKnownTheme,
|
|
156
|
+
priceBoth: () => priceBoth,
|
|
138
157
|
prompt: () => prompt,
|
|
158
|
+
relativeTime: () => relativeTime,
|
|
139
159
|
resolveTheme: () => resolveTheme,
|
|
160
|
+
satsToUsd: () => satsToUsd,
|
|
161
|
+
shortenAddress: () => shortenAddress,
|
|
162
|
+
usdToSats: () => usdToSats,
|
|
140
163
|
useOcSkin: () => useOcSkin
|
|
141
164
|
});
|
|
142
165
|
function cn(...inputs) {
|
|
@@ -381,6 +404,115 @@ function OcThemePicker({ className, triggerClassName, popoverClassName }) {
|
|
|
381
404
|
)
|
|
382
405
|
] });
|
|
383
406
|
}
|
|
407
|
+
var MODES = [
|
|
408
|
+
{ id: "light", label: "light", Icon: lucideReact.Sun },
|
|
409
|
+
{ id: "dark", label: "dark", Icon: lucideReact.Moon },
|
|
410
|
+
{ id: "system", label: "system", Icon: lucideReact.Monitor }
|
|
411
|
+
];
|
|
412
|
+
function OcAppearanceMenu({
|
|
413
|
+
className,
|
|
414
|
+
triggerClassName,
|
|
415
|
+
popoverClassName
|
|
416
|
+
}) {
|
|
417
|
+
const { skin, setSkin, themes } = useOcSkin();
|
|
418
|
+
const { theme, setTheme } = nextThemes.useTheme();
|
|
419
|
+
const [open, setOpen] = React2.useState(false);
|
|
420
|
+
const [mounted, setMounted] = React2.useState(false);
|
|
421
|
+
const rootRef = React2.useRef(null);
|
|
422
|
+
React2.useEffect(() => setMounted(true), []);
|
|
423
|
+
React2.useEffect(() => {
|
|
424
|
+
if (!open) return;
|
|
425
|
+
function onDown(e) {
|
|
426
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
|
|
427
|
+
}
|
|
428
|
+
function onKey(e) {
|
|
429
|
+
if (e.key === "Escape") setOpen(false);
|
|
430
|
+
}
|
|
431
|
+
document.addEventListener("mousedown", onDown);
|
|
432
|
+
document.addEventListener("keydown", onKey);
|
|
433
|
+
return () => {
|
|
434
|
+
document.removeEventListener("mousedown", onDown);
|
|
435
|
+
document.removeEventListener("keydown", onKey);
|
|
436
|
+
};
|
|
437
|
+
}, [open]);
|
|
438
|
+
const activeMode = mounted ? theme ?? "system" : null;
|
|
439
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: cn("relative", className), children: [
|
|
440
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
441
|
+
"button",
|
|
442
|
+
{
|
|
443
|
+
type: "button",
|
|
444
|
+
"aria-label": "appearance settings",
|
|
445
|
+
"aria-haspopup": "menu",
|
|
446
|
+
"aria-expanded": open,
|
|
447
|
+
title: "appearance \xB7 mode + theme",
|
|
448
|
+
onClick: () => setOpen((v) => !v),
|
|
449
|
+
className: cn(
|
|
450
|
+
"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",
|
|
451
|
+
triggerClassName
|
|
452
|
+
),
|
|
453
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Palette, { className: "size-4", "aria-hidden": true })
|
|
454
|
+
}
|
|
455
|
+
),
|
|
456
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
457
|
+
"div",
|
|
458
|
+
{
|
|
459
|
+
role: "menu",
|
|
460
|
+
className: cn(
|
|
461
|
+
"bg-popover text-popover-foreground absolute right-0 z-50 mt-2 w-64 overflow-hidden rounded-md border shadow-md",
|
|
462
|
+
popoverClassName
|
|
463
|
+
),
|
|
464
|
+
children: [
|
|
465
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-muted-foreground px-3 pt-3 pb-2", children: "mode" }),
|
|
466
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-1 px-2 pb-2", children: MODES.map(({ id, label, Icon: Icon2 }) => {
|
|
467
|
+
const active = activeMode === id;
|
|
468
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
469
|
+
"button",
|
|
470
|
+
{
|
|
471
|
+
type: "button",
|
|
472
|
+
role: "menuitemradio",
|
|
473
|
+
"aria-checked": active,
|
|
474
|
+
onClick: () => setTheme(id),
|
|
475
|
+
className: cn(
|
|
476
|
+
"flex flex-col items-center gap-1 rounded-md border py-2 text-[11px] transition-colors",
|
|
477
|
+
active ? "border-primary text-foreground bg-accent" : "border-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
478
|
+
),
|
|
479
|
+
children: [
|
|
480
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "size-4", "aria-hidden": true }),
|
|
481
|
+
label
|
|
482
|
+
]
|
|
483
|
+
},
|
|
484
|
+
id
|
|
485
|
+
);
|
|
486
|
+
}) }),
|
|
487
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-muted-foreground border-t px-3 pt-3 pb-1", children: "theme" }),
|
|
488
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "pb-1", children: themes.map((t) => {
|
|
489
|
+
const active = t.id === skin;
|
|
490
|
+
return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
491
|
+
"button",
|
|
492
|
+
{
|
|
493
|
+
type: "button",
|
|
494
|
+
role: "menuitemradio",
|
|
495
|
+
"aria-checked": active,
|
|
496
|
+
onClick: () => setSkin(t.id),
|
|
497
|
+
className: cn(
|
|
498
|
+
"hover:bg-accent hover:text-accent-foreground flex w-full items-start gap-2 px-3 py-2 text-left transition-colors",
|
|
499
|
+
active && "text-foreground"
|
|
500
|
+
),
|
|
501
|
+
children: [
|
|
502
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 size-4 shrink-0", children: active && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "text-primary size-4", "aria-hidden": true }) }),
|
|
503
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0", children: [
|
|
504
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-sm font-medium", children: t.label }),
|
|
505
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground block text-xs leading-snug", children: t.description })
|
|
506
|
+
] })
|
|
507
|
+
]
|
|
508
|
+
}
|
|
509
|
+
) }, t.id);
|
|
510
|
+
}) })
|
|
511
|
+
]
|
|
512
|
+
}
|
|
513
|
+
)
|
|
514
|
+
] });
|
|
515
|
+
}
|
|
384
516
|
var buttonVariants = classVarianceAuthority.cva(
|
|
385
517
|
"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",
|
|
386
518
|
{
|
|
@@ -1503,6 +1635,345 @@ var Toaster = ({ ...props }) => {
|
|
|
1503
1635
|
}
|
|
1504
1636
|
);
|
|
1505
1637
|
};
|
|
1638
|
+
function Card({
|
|
1639
|
+
id,
|
|
1640
|
+
title,
|
|
1641
|
+
subtitle,
|
|
1642
|
+
refreshedAt,
|
|
1643
|
+
actions,
|
|
1644
|
+
children,
|
|
1645
|
+
className,
|
|
1646
|
+
tone = "default",
|
|
1647
|
+
expandable = true
|
|
1648
|
+
}) {
|
|
1649
|
+
const [expanded, setExpanded] = React2.useState(false);
|
|
1650
|
+
const toneClass = tone === "warning" ? "border-warning/60" : tone === "destructive" ? "border-destructive/60" : tone === "muted" ? "border-border opacity-90" : "border-border";
|
|
1651
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1652
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1653
|
+
"section",
|
|
1654
|
+
{
|
|
1655
|
+
id,
|
|
1656
|
+
className: cn("terminal flex flex-col rounded-sm border scroll-mt-16", toneClass, className),
|
|
1657
|
+
children: [
|
|
1658
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "terminal-title flex items-center justify-between gap-3", children: [
|
|
1659
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1660
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "terminal-dot", "aria-hidden": true }),
|
|
1661
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "terminal-dot opacity-70", "aria-hidden": true }),
|
|
1662
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "terminal-dot opacity-50", "aria-hidden": true }),
|
|
1663
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 truncate", children: title }),
|
|
1664
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground/70 ml-1 truncate text-[10px] tracking-normal normal-case", children: [
|
|
1665
|
+
"\xB7 ",
|
|
1666
|
+
subtitle
|
|
1667
|
+
] })
|
|
1668
|
+
] }),
|
|
1669
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1670
|
+
refreshedAt && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/60 hidden text-[10px] tracking-normal normal-case sm:inline", children: refreshedAt }),
|
|
1671
|
+
actions,
|
|
1672
|
+
expandable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1673
|
+
"button",
|
|
1674
|
+
{
|
|
1675
|
+
type: "button",
|
|
1676
|
+
onClick: () => setExpanded(true),
|
|
1677
|
+
"aria-label": `expand ${title}`,
|
|
1678
|
+
title: "expand to fullscreen",
|
|
1679
|
+
className: "text-muted-foreground/70 hover:text-foreground inline-flex h-6 w-6 items-center justify-center rounded-sm",
|
|
1680
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "size-3" })
|
|
1681
|
+
}
|
|
1682
|
+
)
|
|
1683
|
+
] })
|
|
1684
|
+
] }),
|
|
1685
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-4 sm:p-5", children })
|
|
1686
|
+
]
|
|
1687
|
+
}
|
|
1688
|
+
),
|
|
1689
|
+
expandable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1690
|
+
Modal,
|
|
1691
|
+
{
|
|
1692
|
+
open: expanded,
|
|
1693
|
+
onOpenChange: setExpanded,
|
|
1694
|
+
title,
|
|
1695
|
+
...subtitle ? { subtitle } : {},
|
|
1696
|
+
actions: refreshedAt ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/60 hidden text-[10px] tracking-normal normal-case sm:inline", children: refreshedAt }) : null,
|
|
1697
|
+
children
|
|
1698
|
+
}
|
|
1699
|
+
)
|
|
1700
|
+
] });
|
|
1701
|
+
}
|
|
1702
|
+
function Sparkline({ data, width = 96, height = 24, area = false, className }) {
|
|
1703
|
+
if (data.length === 0) {
|
|
1704
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width, height, className: cn(className), "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1705
|
+
"line",
|
|
1706
|
+
{
|
|
1707
|
+
x1: 0,
|
|
1708
|
+
x2: width,
|
|
1709
|
+
y1: height / 2,
|
|
1710
|
+
y2: height / 2,
|
|
1711
|
+
stroke: "currentColor",
|
|
1712
|
+
strokeWidth: 1,
|
|
1713
|
+
opacity: 0.25
|
|
1714
|
+
}
|
|
1715
|
+
) });
|
|
1716
|
+
}
|
|
1717
|
+
const min = Math.min(...data);
|
|
1718
|
+
const max = Math.max(...data);
|
|
1719
|
+
const range = max - min || 1;
|
|
1720
|
+
const step = data.length === 1 ? width : width / (data.length - 1);
|
|
1721
|
+
const points = data.map((v, i) => {
|
|
1722
|
+
const x = i * step;
|
|
1723
|
+
const y = height - (v - min) / range * (height - 2) - 1;
|
|
1724
|
+
return [x, y];
|
|
1725
|
+
});
|
|
1726
|
+
const linePath = points.map(([x, y], i) => `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
|
|
1727
|
+
const areaPath = area ? `${linePath} L${width.toFixed(2)},${height.toFixed(2)} L0,${height.toFixed(2)} Z` : null;
|
|
1728
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1729
|
+
"svg",
|
|
1730
|
+
{
|
|
1731
|
+
width,
|
|
1732
|
+
height,
|
|
1733
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
1734
|
+
className: cn("text-primary", className),
|
|
1735
|
+
"aria-hidden": true,
|
|
1736
|
+
children: [
|
|
1737
|
+
areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "currentColor", opacity: 0.12 }),
|
|
1738
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "currentColor", strokeWidth: 1.25 })
|
|
1739
|
+
]
|
|
1740
|
+
}
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
function StatBlock({ label, value, sub, delta, tone = "default", className }) {
|
|
1744
|
+
const toneClass = tone === "success" ? "text-success" : tone === "warning" ? "text-warning" : tone === "destructive" ? "text-destructive" : "text-foreground";
|
|
1745
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1", className), children: [
|
|
1746
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "label-mono text-[10px]", children: label }),
|
|
1747
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-display text-2xl leading-none", toneClass), children: value }),
|
|
1748
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
1749
|
+
sub && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground font-mono text-[11px] tracking-wide lowercase", children: sub }),
|
|
1750
|
+
delta && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1751
|
+
"span",
|
|
1752
|
+
{
|
|
1753
|
+
className: cn(
|
|
1754
|
+
"font-mono text-[11px] tracking-wide",
|
|
1755
|
+
delta.value > 0 ? "text-success" : delta.value < 0 ? "text-destructive" : "text-muted-foreground"
|
|
1756
|
+
),
|
|
1757
|
+
children: [
|
|
1758
|
+
delta.value > 0 ? "\u25B2" : delta.value < 0 ? "\u25BC" : "\xB7",
|
|
1759
|
+
" ",
|
|
1760
|
+
Math.abs(delta.value).toFixed(1),
|
|
1761
|
+
delta.suffix ?? "%"
|
|
1762
|
+
]
|
|
1763
|
+
}
|
|
1764
|
+
)
|
|
1765
|
+
] })
|
|
1766
|
+
] });
|
|
1767
|
+
}
|
|
1768
|
+
var ACCENT = {
|
|
1769
|
+
primary: "bg-primary",
|
|
1770
|
+
warning: "bg-warning",
|
|
1771
|
+
destructive: "bg-destructive",
|
|
1772
|
+
success: "bg-success"
|
|
1773
|
+
};
|
|
1774
|
+
function Bar({ pct, accent = "primary", label, right, className }) {
|
|
1775
|
+
const clamped = Math.max(0, Math.min(100, pct));
|
|
1776
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(className), children: [
|
|
1777
|
+
(label || right) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between font-mono text-[10.5px] tracking-widest uppercase", children: [
|
|
1778
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
|
|
1779
|
+
right && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground tabular-nums", children: right })
|
|
1780
|
+
] }),
|
|
1781
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted mt-1.5 h-1.5 w-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-full", ACCENT[accent]), style: { width: `${clamped}%` } }) })
|
|
1782
|
+
] });
|
|
1783
|
+
}
|
|
1784
|
+
var TONE = {
|
|
1785
|
+
success: "text-success",
|
|
1786
|
+
warning: "text-warning",
|
|
1787
|
+
destructive: "text-destructive",
|
|
1788
|
+
muted: "text-muted-foreground",
|
|
1789
|
+
primary: "text-primary",
|
|
1790
|
+
info: "text-info"
|
|
1791
|
+
};
|
|
1792
|
+
function StatusPill({ label, tone = "muted", icon, className }) {
|
|
1793
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1794
|
+
"span",
|
|
1795
|
+
{
|
|
1796
|
+
className: cn(
|
|
1797
|
+
"inline-flex items-center gap-1.5 font-mono text-[11px] tracking-wider lowercase",
|
|
1798
|
+
TONE[tone],
|
|
1799
|
+
className
|
|
1800
|
+
),
|
|
1801
|
+
children: [
|
|
1802
|
+
icon,
|
|
1803
|
+
label
|
|
1804
|
+
]
|
|
1805
|
+
}
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
// src/format/index.ts
|
|
1810
|
+
var REFERENCE_BTC_USD = 95e3;
|
|
1811
|
+
function formatSats(sats) {
|
|
1812
|
+
return new Intl.NumberFormat("en-US").format(Math.round(sats));
|
|
1813
|
+
}
|
|
1814
|
+
function formatSatsCompact(sats) {
|
|
1815
|
+
const n = Math.round(sats);
|
|
1816
|
+
if (n < 1e3) return `${n} sats`;
|
|
1817
|
+
const k = n / 1e3;
|
|
1818
|
+
return `${Number.isInteger(k) ? k : k.toFixed(1)}k sats`;
|
|
1819
|
+
}
|
|
1820
|
+
function satsToUsd(sats, btcUsd = REFERENCE_BTC_USD) {
|
|
1821
|
+
const usd = sats / 1e8 * btcUsd;
|
|
1822
|
+
if (usd > 0 && usd < 0.01) return "< $0.01";
|
|
1823
|
+
const fractionDigits = usd >= 100 ? 0 : 2;
|
|
1824
|
+
return new Intl.NumberFormat("en-US", {
|
|
1825
|
+
style: "currency",
|
|
1826
|
+
currency: "USD",
|
|
1827
|
+
minimumFractionDigits: fractionDigits,
|
|
1828
|
+
maximumFractionDigits: fractionDigits
|
|
1829
|
+
}).format(usd);
|
|
1830
|
+
}
|
|
1831
|
+
function usdToSats(usd, btcUsd = REFERENCE_BTC_USD) {
|
|
1832
|
+
return Math.round(usd / btcUsd * 1e8);
|
|
1833
|
+
}
|
|
1834
|
+
function priceBoth(sats, btcUsd = REFERENCE_BTC_USD) {
|
|
1835
|
+
return `${formatSats(sats)} sats \xB7 ${satsToUsd(sats, btcUsd)}`;
|
|
1836
|
+
}
|
|
1837
|
+
function relativeTime(when) {
|
|
1838
|
+
const t = when instanceof Date ? when.getTime() : new Date(when).getTime();
|
|
1839
|
+
if (Number.isNaN(t)) return "";
|
|
1840
|
+
const diff = Date.now() - t;
|
|
1841
|
+
const m = Math.floor(diff / 6e4);
|
|
1842
|
+
if (m < 1) return "now";
|
|
1843
|
+
if (m < 60) return `${m}m ago`;
|
|
1844
|
+
const h = Math.floor(m / 60);
|
|
1845
|
+
if (h < 24) return `${h}h ago`;
|
|
1846
|
+
const d = Math.floor(h / 24);
|
|
1847
|
+
if (d < 30) return `${d}d ago`;
|
|
1848
|
+
const mo = Math.floor(d / 30);
|
|
1849
|
+
if (mo < 12) return `${mo}mo ago`;
|
|
1850
|
+
return `${Math.floor(mo / 12)}y ago`;
|
|
1851
|
+
}
|
|
1852
|
+
function shortenAddress(value, head = 8, tail = 4) {
|
|
1853
|
+
if (!value) return "";
|
|
1854
|
+
if (value.length <= head + tail + 1) return value;
|
|
1855
|
+
return `${value.slice(0, head)}\u2026${value.slice(-tail)}`;
|
|
1856
|
+
}
|
|
1857
|
+
function explorerUrl(target, network = "mainnet") {
|
|
1858
|
+
const base = network === "mainnet" ? "https://mempool.space" : `https://mempool.space/${network}`;
|
|
1859
|
+
if ("address" in target) return `${base}/address/${target.address}`;
|
|
1860
|
+
if ("tx" in target) return `${base}/tx/${target.tx}`;
|
|
1861
|
+
return `${base}/block/${target.block}`;
|
|
1862
|
+
}
|
|
1863
|
+
function SatsAmount({ sats, unit = true, usd = false, btcUsd, className }) {
|
|
1864
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-mono tabular-nums", className), children: [
|
|
1865
|
+
formatSats(sats),
|
|
1866
|
+
unit && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: " sats" }),
|
|
1867
|
+
usd && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
1868
|
+
" \xB7 ",
|
|
1869
|
+
satsToUsd(sats, btcUsd)
|
|
1870
|
+
] })
|
|
1871
|
+
] });
|
|
1872
|
+
}
|
|
1873
|
+
function CopyButton({
|
|
1874
|
+
value,
|
|
1875
|
+
label,
|
|
1876
|
+
clearAfter,
|
|
1877
|
+
size = "md",
|
|
1878
|
+
className,
|
|
1879
|
+
title,
|
|
1880
|
+
onCopied
|
|
1881
|
+
}) {
|
|
1882
|
+
const [copied, setCopied] = React2.useState(false);
|
|
1883
|
+
const resetRef = React2.useRef(null);
|
|
1884
|
+
const copy = React2.useCallback(async () => {
|
|
1885
|
+
try {
|
|
1886
|
+
await navigator.clipboard.writeText(value);
|
|
1887
|
+
setCopied(true);
|
|
1888
|
+
onCopied?.();
|
|
1889
|
+
if (resetRef.current) clearTimeout(resetRef.current);
|
|
1890
|
+
resetRef.current = setTimeout(() => setCopied(false), 1500);
|
|
1891
|
+
if (clearAfter && clearAfter > 0) {
|
|
1892
|
+
setTimeout(() => void wipeIfUnchanged(value), clearAfter * 1e3);
|
|
1893
|
+
}
|
|
1894
|
+
} catch {
|
|
1895
|
+
}
|
|
1896
|
+
}, [value, clearAfter, onCopied]);
|
|
1897
|
+
const iconSize = size === "sm" ? "size-3" : "size-3.5";
|
|
1898
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1899
|
+
"button",
|
|
1900
|
+
{
|
|
1901
|
+
type: "button",
|
|
1902
|
+
onClick: copy,
|
|
1903
|
+
"aria-label": title ?? (copied ? "copied" : "copy"),
|
|
1904
|
+
title: title ?? "copy",
|
|
1905
|
+
className: cn(
|
|
1906
|
+
"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",
|
|
1907
|
+
size === "sm" ? "text-[11px]" : "text-xs",
|
|
1908
|
+
className
|
|
1909
|
+
),
|
|
1910
|
+
children: [
|
|
1911
|
+
copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn(iconSize, "text-success"), "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: iconSize, "aria-hidden": true }),
|
|
1912
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: copied ? "copied" : label })
|
|
1913
|
+
]
|
|
1914
|
+
}
|
|
1915
|
+
);
|
|
1916
|
+
}
|
|
1917
|
+
async function wipeIfUnchanged(expected) {
|
|
1918
|
+
try {
|
|
1919
|
+
const current = await navigator.clipboard.readText();
|
|
1920
|
+
if (current !== expected) return;
|
|
1921
|
+
await navigator.clipboard.writeText("");
|
|
1922
|
+
} catch {
|
|
1923
|
+
try {
|
|
1924
|
+
await navigator.clipboard.writeText("");
|
|
1925
|
+
} catch {
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
function BitcoinAddress({
|
|
1930
|
+
address,
|
|
1931
|
+
head = 8,
|
|
1932
|
+
tail = 4,
|
|
1933
|
+
copyable = true,
|
|
1934
|
+
full = false,
|
|
1935
|
+
className
|
|
1936
|
+
}) {
|
|
1937
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("inline-flex items-center gap-1.5 font-mono text-xs", className), children: [
|
|
1938
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { title: address, children: full ? address : shortenAddress(address, head, tail) }),
|
|
1939
|
+
copyable && /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: address, size: "sm", title: "copy address" })
|
|
1940
|
+
] });
|
|
1941
|
+
}
|
|
1942
|
+
function QrCode({ value, size = 200, label, className }) {
|
|
1943
|
+
const [svg, setSvg] = React2.useState(null);
|
|
1944
|
+
React2.useEffect(() => {
|
|
1945
|
+
let cancelled = false;
|
|
1946
|
+
QRCode__default.default.toString(value, {
|
|
1947
|
+
type: "svg",
|
|
1948
|
+
errorCorrectionLevel: "M",
|
|
1949
|
+
margin: 1,
|
|
1950
|
+
color: { dark: "#000000", light: "#ffffff" }
|
|
1951
|
+
}).then((out) => {
|
|
1952
|
+
if (!cancelled) setSvg(out);
|
|
1953
|
+
}).catch(() => {
|
|
1954
|
+
if (!cancelled) setSvg(null);
|
|
1955
|
+
});
|
|
1956
|
+
return () => {
|
|
1957
|
+
cancelled = true;
|
|
1958
|
+
};
|
|
1959
|
+
}, [value]);
|
|
1960
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1961
|
+
"div",
|
|
1962
|
+
{
|
|
1963
|
+
role: "img",
|
|
1964
|
+
"aria-label": label ?? `QR code for ${value.slice(0, 24)}\u2026`,
|
|
1965
|
+
className: "inline-block overflow-hidden rounded-md bg-white p-3 " + (className ?? ""),
|
|
1966
|
+
style: { width: size, height: size },
|
|
1967
|
+
children: svg ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1968
|
+
"div",
|
|
1969
|
+
{
|
|
1970
|
+
className: "size-full [&_svg]:block [&_svg]:size-full",
|
|
1971
|
+
dangerouslySetInnerHTML: { __html: svg }
|
|
1972
|
+
}
|
|
1973
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted/40 size-full animate-pulse rounded", "aria-hidden": true })
|
|
1974
|
+
}
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1506
1977
|
|
|
1507
1978
|
// src/components/index.ts
|
|
1508
1979
|
var components_exports = {};
|
|
@@ -1521,8 +1992,12 @@ exports.AlertTitle = AlertTitle;
|
|
|
1521
1992
|
exports.AlertWithAction = AlertWithAction;
|
|
1522
1993
|
exports.AlertWithCountdown = AlertWithCountdown;
|
|
1523
1994
|
exports.Badge = Badge;
|
|
1995
|
+
exports.Bar = Bar;
|
|
1996
|
+
exports.BitcoinAddress = BitcoinAddress;
|
|
1524
1997
|
exports.Button = Button;
|
|
1998
|
+
exports.Card = Card;
|
|
1525
1999
|
exports.ConfirmHost = ConfirmHost;
|
|
2000
|
+
exports.CopyButton = CopyButton;
|
|
1526
2001
|
exports.DEFAULT_OC_THEME = DEFAULT_OC_THEME;
|
|
1527
2002
|
exports.Dialog = Dialog;
|
|
1528
2003
|
exports.DialogClose = DialogClose;
|
|
@@ -1540,6 +2015,7 @@ exports.Label = Label;
|
|
|
1540
2015
|
exports.Modal = Modal;
|
|
1541
2016
|
exports.OC_SKIN_COOKIE = OC_SKIN_COOKIE;
|
|
1542
2017
|
exports.OC_THEMES = OC_THEMES;
|
|
2018
|
+
exports.OcAppearanceMenu = OcAppearanceMenu;
|
|
1543
2019
|
exports.OcThemeBridge = OcThemeBridge;
|
|
1544
2020
|
exports.OcThemePicker = OcThemePicker;
|
|
1545
2021
|
exports.OcThemeProvider = OcThemeProvider;
|
|
@@ -1549,6 +2025,9 @@ exports.PopoverAnchor = PopoverAnchor;
|
|
|
1549
2025
|
exports.PopoverContent = PopoverContent;
|
|
1550
2026
|
exports.PopoverTrigger = PopoverTrigger;
|
|
1551
2027
|
exports.PromptHost = PromptHost;
|
|
2028
|
+
exports.QrCode = QrCode;
|
|
2029
|
+
exports.REFERENCE_BTC_USD = REFERENCE_BTC_USD;
|
|
2030
|
+
exports.SatsAmount = SatsAmount;
|
|
1552
2031
|
exports.Select = Select;
|
|
1553
2032
|
exports.SelectContent = SelectContent;
|
|
1554
2033
|
exports.SelectGroup = SelectGroup;
|
|
@@ -1569,6 +2048,9 @@ exports.SheetPortal = SheetPortal;
|
|
|
1569
2048
|
exports.SheetTitle = SheetTitle;
|
|
1570
2049
|
exports.SheetTrigger = SheetTrigger;
|
|
1571
2050
|
exports.Skeleton = Skeleton;
|
|
2051
|
+
exports.Sparkline = Sparkline;
|
|
2052
|
+
exports.StatBlock = StatBlock;
|
|
2053
|
+
exports.StatusPill = StatusPill;
|
|
1572
2054
|
exports.Textarea = Textarea;
|
|
1573
2055
|
exports.ThemeToggle = ThemeToggle;
|
|
1574
2056
|
exports.ThemeToggleLink = ThemeToggleLink;
|
|
@@ -1579,10 +2061,18 @@ exports.badgeVariants = badgeVariants;
|
|
|
1579
2061
|
exports.buttonVariants = buttonVariants;
|
|
1580
2062
|
exports.cn = cn;
|
|
1581
2063
|
exports.confirm = confirm;
|
|
2064
|
+
exports.explorerUrl = explorerUrl;
|
|
2065
|
+
exports.formatSats = formatSats;
|
|
2066
|
+
exports.formatSatsCompact = formatSatsCompact;
|
|
1582
2067
|
exports.getOcThemeInitScript = getOcThemeInitScript;
|
|
1583
2068
|
exports.isKnownTheme = isKnownTheme;
|
|
2069
|
+
exports.priceBoth = priceBoth;
|
|
1584
2070
|
exports.prompt = prompt;
|
|
2071
|
+
exports.relativeTime = relativeTime;
|
|
1585
2072
|
exports.resolveTheme = resolveTheme;
|
|
2073
|
+
exports.satsToUsd = satsToUsd;
|
|
2074
|
+
exports.shortenAddress = shortenAddress;
|
|
2075
|
+
exports.usdToSats = usdToSats;
|
|
1586
2076
|
exports.useOcSkin = useOcSkin;
|
|
1587
2077
|
//# sourceMappingURL=index.js.map
|
|
1588
2078
|
//# sourceMappingURL=index.js.map
|