@orangecheck/design 0.2.0 → 0.3.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 +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +379 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +361 -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/package.json +8 -1
package/dist/primitives.d.mts
CHANGED
|
@@ -202,4 +202,95 @@ declare function SelectScrollDownButton({ className, ...props }: React.Component
|
|
|
202
202
|
|
|
203
203
|
declare const Toaster: ({ ...props }: ToasterProps) => react_jsx_runtime.JSX.Element;
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
interface CardProps {
|
|
206
|
+
id?: string;
|
|
207
|
+
title: string;
|
|
208
|
+
subtitle?: string;
|
|
209
|
+
refreshedAt?: string | null;
|
|
210
|
+
actions?: ReactNode;
|
|
211
|
+
children: ReactNode;
|
|
212
|
+
className?: string;
|
|
213
|
+
tone?: 'default' | 'warning' | 'destructive' | 'muted';
|
|
214
|
+
expandable?: boolean;
|
|
215
|
+
}
|
|
216
|
+
declare function Card({ id, title, subtitle, refreshedAt, actions, children, className, tone, expandable, }: CardProps): react_jsx_runtime.JSX.Element;
|
|
217
|
+
|
|
218
|
+
interface SparklineProps {
|
|
219
|
+
data: ReadonlyArray<number>;
|
|
220
|
+
width?: number;
|
|
221
|
+
height?: number;
|
|
222
|
+
className?: string;
|
|
223
|
+
area?: boolean;
|
|
224
|
+
}
|
|
225
|
+
declare function Sparkline({ data, width, height, area, className }: SparklineProps): react_jsx_runtime.JSX.Element;
|
|
226
|
+
|
|
227
|
+
interface StatBlockProps {
|
|
228
|
+
label: string;
|
|
229
|
+
value: ReactNode;
|
|
230
|
+
sub?: ReactNode;
|
|
231
|
+
delta?: {
|
|
232
|
+
value: number;
|
|
233
|
+
suffix?: string;
|
|
234
|
+
} | null;
|
|
235
|
+
tone?: 'default' | 'success' | 'warning' | 'destructive';
|
|
236
|
+
className?: string;
|
|
237
|
+
}
|
|
238
|
+
declare function StatBlock({ label, value, sub, delta, tone, className }: StatBlockProps): react_jsx_runtime.JSX.Element;
|
|
239
|
+
|
|
240
|
+
interface BarProps {
|
|
241
|
+
pct: number;
|
|
242
|
+
accent?: 'primary' | 'warning' | 'destructive' | 'success';
|
|
243
|
+
label?: string;
|
|
244
|
+
right?: string;
|
|
245
|
+
className?: string;
|
|
246
|
+
}
|
|
247
|
+
declare function Bar({ pct, accent, label, right, className }: BarProps): react_jsx_runtime.JSX.Element;
|
|
248
|
+
|
|
249
|
+
type StatusTone = 'success' | 'warning' | 'destructive' | 'muted' | 'primary' | 'info';
|
|
250
|
+
interface StatusPillProps {
|
|
251
|
+
label: string;
|
|
252
|
+
tone?: StatusTone;
|
|
253
|
+
icon?: ReactNode;
|
|
254
|
+
className?: string;
|
|
255
|
+
}
|
|
256
|
+
declare function StatusPill({ label, tone, icon, className }: StatusPillProps): react_jsx_runtime.JSX.Element;
|
|
257
|
+
|
|
258
|
+
interface SatsAmountProps {
|
|
259
|
+
sats: number;
|
|
260
|
+
unit?: boolean;
|
|
261
|
+
usd?: boolean;
|
|
262
|
+
btcUsd?: number;
|
|
263
|
+
className?: string;
|
|
264
|
+
}
|
|
265
|
+
declare function SatsAmount({ sats, unit, usd, btcUsd, className }: SatsAmountProps): react_jsx_runtime.JSX.Element;
|
|
266
|
+
|
|
267
|
+
interface BitcoinAddressProps {
|
|
268
|
+
address: string;
|
|
269
|
+
head?: number;
|
|
270
|
+
tail?: number;
|
|
271
|
+
copyable?: boolean;
|
|
272
|
+
full?: boolean;
|
|
273
|
+
className?: string;
|
|
274
|
+
}
|
|
275
|
+
declare function BitcoinAddress({ address, head, tail, copyable, full, className, }: BitcoinAddressProps): react_jsx_runtime.JSX.Element;
|
|
276
|
+
|
|
277
|
+
interface CopyButtonProps {
|
|
278
|
+
value: string;
|
|
279
|
+
label?: string;
|
|
280
|
+
clearAfter?: number;
|
|
281
|
+
size?: 'sm' | 'md';
|
|
282
|
+
className?: string;
|
|
283
|
+
title?: string;
|
|
284
|
+
onCopied?: () => void;
|
|
285
|
+
}
|
|
286
|
+
declare function CopyButton({ value, label, clearAfter, size, className, title, onCopied, }: CopyButtonProps): react_jsx_runtime.JSX.Element;
|
|
287
|
+
|
|
288
|
+
interface QrCodeProps {
|
|
289
|
+
value: string;
|
|
290
|
+
size?: number;
|
|
291
|
+
label?: string;
|
|
292
|
+
className?: string;
|
|
293
|
+
}
|
|
294
|
+
declare function QrCode({ value, size, label, className }: QrCodeProps): react_jsx_runtime.JSX.Element;
|
|
295
|
+
|
|
296
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertTitle, AlertWithAction, type AlertWithActionProps, AlertWithCountdown, type AlertWithCountdownProps, Badge, Bar, type BarProps, BitcoinAddress, type BitcoinAddressProps, Button, Card, type CardProps, ConfirmHost, type ConfirmOptions, CopyButton, type CopyButtonProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, ErrorBoundary, Input, Label, Modal, type ModalProps, Pagination, type PaginationProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PromptHost, type PromptOptions, QrCode, type QrCodeProps, SatsAmount, type SatsAmountProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, type SkeletonProps, Sparkline, type SparklineProps, StatBlock, type StatBlockProps, StatusPill, type StatusPillProps, type StatusTone, Textarea, ThemeToggle, ThemeToggleLink, Toaster, Working, WorkingPanel, type WorkingProps, badgeVariants, buttonVariants, confirm, prompt };
|
package/dist/primitives.d.ts
CHANGED
|
@@ -202,4 +202,95 @@ declare function SelectScrollDownButton({ className, ...props }: React.Component
|
|
|
202
202
|
|
|
203
203
|
declare const Toaster: ({ ...props }: ToasterProps) => react_jsx_runtime.JSX.Element;
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
interface CardProps {
|
|
206
|
+
id?: string;
|
|
207
|
+
title: string;
|
|
208
|
+
subtitle?: string;
|
|
209
|
+
refreshedAt?: string | null;
|
|
210
|
+
actions?: ReactNode;
|
|
211
|
+
children: ReactNode;
|
|
212
|
+
className?: string;
|
|
213
|
+
tone?: 'default' | 'warning' | 'destructive' | 'muted';
|
|
214
|
+
expandable?: boolean;
|
|
215
|
+
}
|
|
216
|
+
declare function Card({ id, title, subtitle, refreshedAt, actions, children, className, tone, expandable, }: CardProps): react_jsx_runtime.JSX.Element;
|
|
217
|
+
|
|
218
|
+
interface SparklineProps {
|
|
219
|
+
data: ReadonlyArray<number>;
|
|
220
|
+
width?: number;
|
|
221
|
+
height?: number;
|
|
222
|
+
className?: string;
|
|
223
|
+
area?: boolean;
|
|
224
|
+
}
|
|
225
|
+
declare function Sparkline({ data, width, height, area, className }: SparklineProps): react_jsx_runtime.JSX.Element;
|
|
226
|
+
|
|
227
|
+
interface StatBlockProps {
|
|
228
|
+
label: string;
|
|
229
|
+
value: ReactNode;
|
|
230
|
+
sub?: ReactNode;
|
|
231
|
+
delta?: {
|
|
232
|
+
value: number;
|
|
233
|
+
suffix?: string;
|
|
234
|
+
} | null;
|
|
235
|
+
tone?: 'default' | 'success' | 'warning' | 'destructive';
|
|
236
|
+
className?: string;
|
|
237
|
+
}
|
|
238
|
+
declare function StatBlock({ label, value, sub, delta, tone, className }: StatBlockProps): react_jsx_runtime.JSX.Element;
|
|
239
|
+
|
|
240
|
+
interface BarProps {
|
|
241
|
+
pct: number;
|
|
242
|
+
accent?: 'primary' | 'warning' | 'destructive' | 'success';
|
|
243
|
+
label?: string;
|
|
244
|
+
right?: string;
|
|
245
|
+
className?: string;
|
|
246
|
+
}
|
|
247
|
+
declare function Bar({ pct, accent, label, right, className }: BarProps): react_jsx_runtime.JSX.Element;
|
|
248
|
+
|
|
249
|
+
type StatusTone = 'success' | 'warning' | 'destructive' | 'muted' | 'primary' | 'info';
|
|
250
|
+
interface StatusPillProps {
|
|
251
|
+
label: string;
|
|
252
|
+
tone?: StatusTone;
|
|
253
|
+
icon?: ReactNode;
|
|
254
|
+
className?: string;
|
|
255
|
+
}
|
|
256
|
+
declare function StatusPill({ label, tone, icon, className }: StatusPillProps): react_jsx_runtime.JSX.Element;
|
|
257
|
+
|
|
258
|
+
interface SatsAmountProps {
|
|
259
|
+
sats: number;
|
|
260
|
+
unit?: boolean;
|
|
261
|
+
usd?: boolean;
|
|
262
|
+
btcUsd?: number;
|
|
263
|
+
className?: string;
|
|
264
|
+
}
|
|
265
|
+
declare function SatsAmount({ sats, unit, usd, btcUsd, className }: SatsAmountProps): react_jsx_runtime.JSX.Element;
|
|
266
|
+
|
|
267
|
+
interface BitcoinAddressProps {
|
|
268
|
+
address: string;
|
|
269
|
+
head?: number;
|
|
270
|
+
tail?: number;
|
|
271
|
+
copyable?: boolean;
|
|
272
|
+
full?: boolean;
|
|
273
|
+
className?: string;
|
|
274
|
+
}
|
|
275
|
+
declare function BitcoinAddress({ address, head, tail, copyable, full, className, }: BitcoinAddressProps): react_jsx_runtime.JSX.Element;
|
|
276
|
+
|
|
277
|
+
interface CopyButtonProps {
|
|
278
|
+
value: string;
|
|
279
|
+
label?: string;
|
|
280
|
+
clearAfter?: number;
|
|
281
|
+
size?: 'sm' | 'md';
|
|
282
|
+
className?: string;
|
|
283
|
+
title?: string;
|
|
284
|
+
onCopied?: () => void;
|
|
285
|
+
}
|
|
286
|
+
declare function CopyButton({ value, label, clearAfter, size, className, title, onCopied, }: CopyButtonProps): react_jsx_runtime.JSX.Element;
|
|
287
|
+
|
|
288
|
+
interface QrCodeProps {
|
|
289
|
+
value: string;
|
|
290
|
+
size?: number;
|
|
291
|
+
label?: string;
|
|
292
|
+
className?: string;
|
|
293
|
+
}
|
|
294
|
+
declare function QrCode({ value, size, label, className }: QrCodeProps): react_jsx_runtime.JSX.Element;
|
|
295
|
+
|
|
296
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertTitle, AlertWithAction, type AlertWithActionProps, AlertWithCountdown, type AlertWithCountdownProps, Badge, Bar, type BarProps, BitcoinAddress, type BitcoinAddressProps, Button, Card, type CardProps, ConfirmHost, type ConfirmOptions, CopyButton, type CopyButtonProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, ErrorBoundary, Input, Label, Modal, type ModalProps, Pagination, type PaginationProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PromptHost, type PromptOptions, QrCode, type QrCodeProps, SatsAmount, type SatsAmountProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, type SkeletonProps, Sparkline, type SparklineProps, StatBlock, type StatBlockProps, StatusPill, type StatusPillProps, type StatusTone, Textarea, ThemeToggle, ThemeToggleLink, Toaster, Working, WorkingPanel, type WorkingProps, badgeVariants, buttonVariants, confirm, prompt };
|
package/dist/primitives.js
CHANGED
|
@@ -15,6 +15,9 @@ 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');
|
|
19
|
+
|
|
20
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
21
|
|
|
19
22
|
function _interopNamespace(e) {
|
|
20
23
|
if (e && e.__esModule) return e;
|
|
@@ -41,6 +44,7 @@ var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive)
|
|
|
41
44
|
var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
|
|
42
45
|
var AccordionPrimitive__namespace = /*#__PURE__*/_interopNamespace(AccordionPrimitive);
|
|
43
46
|
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
|
|
47
|
+
var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
|
|
44
48
|
|
|
45
49
|
// src/primitives/button.tsx
|
|
46
50
|
function cn(...inputs) {
|
|
@@ -1168,6 +1172,312 @@ var Toaster = ({ ...props }) => {
|
|
|
1168
1172
|
}
|
|
1169
1173
|
);
|
|
1170
1174
|
};
|
|
1175
|
+
function Card({
|
|
1176
|
+
id,
|
|
1177
|
+
title,
|
|
1178
|
+
subtitle,
|
|
1179
|
+
refreshedAt,
|
|
1180
|
+
actions,
|
|
1181
|
+
children,
|
|
1182
|
+
className,
|
|
1183
|
+
tone = "default",
|
|
1184
|
+
expandable = true
|
|
1185
|
+
}) {
|
|
1186
|
+
const [expanded, setExpanded] = React2.useState(false);
|
|
1187
|
+
const toneClass = tone === "warning" ? "border-warning/60" : tone === "destructive" ? "border-destructive/60" : tone === "muted" ? "border-border opacity-90" : "border-border";
|
|
1188
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1189
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1190
|
+
"section",
|
|
1191
|
+
{
|
|
1192
|
+
id,
|
|
1193
|
+
className: cn("terminal flex flex-col rounded-sm border scroll-mt-16", toneClass, className),
|
|
1194
|
+
children: [
|
|
1195
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "terminal-title flex items-center justify-between gap-3", children: [
|
|
1196
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1197
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "terminal-dot", "aria-hidden": true }),
|
|
1198
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "terminal-dot opacity-70", "aria-hidden": true }),
|
|
1199
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "terminal-dot opacity-50", "aria-hidden": true }),
|
|
1200
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 truncate", children: title }),
|
|
1201
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground/70 ml-1 truncate text-[10px] tracking-normal normal-case", children: [
|
|
1202
|
+
"\xB7 ",
|
|
1203
|
+
subtitle
|
|
1204
|
+
] })
|
|
1205
|
+
] }),
|
|
1206
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1207
|
+
refreshedAt && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/60 hidden text-[10px] tracking-normal normal-case sm:inline", children: refreshedAt }),
|
|
1208
|
+
actions,
|
|
1209
|
+
expandable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1210
|
+
"button",
|
|
1211
|
+
{
|
|
1212
|
+
type: "button",
|
|
1213
|
+
onClick: () => setExpanded(true),
|
|
1214
|
+
"aria-label": `expand ${title}`,
|
|
1215
|
+
title: "expand to fullscreen",
|
|
1216
|
+
className: "text-muted-foreground/70 hover:text-foreground inline-flex h-6 w-6 items-center justify-center rounded-sm",
|
|
1217
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "size-3" })
|
|
1218
|
+
}
|
|
1219
|
+
)
|
|
1220
|
+
] })
|
|
1221
|
+
] }),
|
|
1222
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-4 sm:p-5", children })
|
|
1223
|
+
]
|
|
1224
|
+
}
|
|
1225
|
+
),
|
|
1226
|
+
expandable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1227
|
+
Modal,
|
|
1228
|
+
{
|
|
1229
|
+
open: expanded,
|
|
1230
|
+
onOpenChange: setExpanded,
|
|
1231
|
+
title,
|
|
1232
|
+
...subtitle ? { subtitle } : {},
|
|
1233
|
+
actions: refreshedAt ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/60 hidden text-[10px] tracking-normal normal-case sm:inline", children: refreshedAt }) : null,
|
|
1234
|
+
children
|
|
1235
|
+
}
|
|
1236
|
+
)
|
|
1237
|
+
] });
|
|
1238
|
+
}
|
|
1239
|
+
function Sparkline({ data, width = 96, height = 24, area = false, className }) {
|
|
1240
|
+
if (data.length === 0) {
|
|
1241
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width, height, className: cn(className), "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1242
|
+
"line",
|
|
1243
|
+
{
|
|
1244
|
+
x1: 0,
|
|
1245
|
+
x2: width,
|
|
1246
|
+
y1: height / 2,
|
|
1247
|
+
y2: height / 2,
|
|
1248
|
+
stroke: "currentColor",
|
|
1249
|
+
strokeWidth: 1,
|
|
1250
|
+
opacity: 0.25
|
|
1251
|
+
}
|
|
1252
|
+
) });
|
|
1253
|
+
}
|
|
1254
|
+
const min = Math.min(...data);
|
|
1255
|
+
const max = Math.max(...data);
|
|
1256
|
+
const range = max - min || 1;
|
|
1257
|
+
const step = data.length === 1 ? width : width / (data.length - 1);
|
|
1258
|
+
const points = data.map((v, i) => {
|
|
1259
|
+
const x = i * step;
|
|
1260
|
+
const y = height - (v - min) / range * (height - 2) - 1;
|
|
1261
|
+
return [x, y];
|
|
1262
|
+
});
|
|
1263
|
+
const linePath = points.map(([x, y], i) => `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
|
|
1264
|
+
const areaPath = area ? `${linePath} L${width.toFixed(2)},${height.toFixed(2)} L0,${height.toFixed(2)} Z` : null;
|
|
1265
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1266
|
+
"svg",
|
|
1267
|
+
{
|
|
1268
|
+
width,
|
|
1269
|
+
height,
|
|
1270
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
1271
|
+
className: cn("text-primary", className),
|
|
1272
|
+
"aria-hidden": true,
|
|
1273
|
+
children: [
|
|
1274
|
+
areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "currentColor", opacity: 0.12 }),
|
|
1275
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "currentColor", strokeWidth: 1.25 })
|
|
1276
|
+
]
|
|
1277
|
+
}
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
function StatBlock({ label, value, sub, delta, tone = "default", className }) {
|
|
1281
|
+
const toneClass = tone === "success" ? "text-success" : tone === "warning" ? "text-warning" : tone === "destructive" ? "text-destructive" : "text-foreground";
|
|
1282
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1", className), children: [
|
|
1283
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "label-mono text-[10px]", children: label }),
|
|
1284
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-display text-2xl leading-none", toneClass), children: value }),
|
|
1285
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
1286
|
+
sub && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground font-mono text-[11px] tracking-wide lowercase", children: sub }),
|
|
1287
|
+
delta && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1288
|
+
"span",
|
|
1289
|
+
{
|
|
1290
|
+
className: cn(
|
|
1291
|
+
"font-mono text-[11px] tracking-wide",
|
|
1292
|
+
delta.value > 0 ? "text-success" : delta.value < 0 ? "text-destructive" : "text-muted-foreground"
|
|
1293
|
+
),
|
|
1294
|
+
children: [
|
|
1295
|
+
delta.value > 0 ? "\u25B2" : delta.value < 0 ? "\u25BC" : "\xB7",
|
|
1296
|
+
" ",
|
|
1297
|
+
Math.abs(delta.value).toFixed(1),
|
|
1298
|
+
delta.suffix ?? "%"
|
|
1299
|
+
]
|
|
1300
|
+
}
|
|
1301
|
+
)
|
|
1302
|
+
] })
|
|
1303
|
+
] });
|
|
1304
|
+
}
|
|
1305
|
+
var ACCENT = {
|
|
1306
|
+
primary: "bg-primary",
|
|
1307
|
+
warning: "bg-warning",
|
|
1308
|
+
destructive: "bg-destructive",
|
|
1309
|
+
success: "bg-success"
|
|
1310
|
+
};
|
|
1311
|
+
function Bar({ pct, accent = "primary", label, right, className }) {
|
|
1312
|
+
const clamped = Math.max(0, Math.min(100, pct));
|
|
1313
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(className), children: [
|
|
1314
|
+
(label || right) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between font-mono text-[10.5px] tracking-widest uppercase", children: [
|
|
1315
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
|
|
1316
|
+
right && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground tabular-nums", children: right })
|
|
1317
|
+
] }),
|
|
1318
|
+
/* @__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}%` } }) })
|
|
1319
|
+
] });
|
|
1320
|
+
}
|
|
1321
|
+
var TONE = {
|
|
1322
|
+
success: "text-success",
|
|
1323
|
+
warning: "text-warning",
|
|
1324
|
+
destructive: "text-destructive",
|
|
1325
|
+
muted: "text-muted-foreground",
|
|
1326
|
+
primary: "text-primary",
|
|
1327
|
+
info: "text-info"
|
|
1328
|
+
};
|
|
1329
|
+
function StatusPill({ label, tone = "muted", icon, className }) {
|
|
1330
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1331
|
+
"span",
|
|
1332
|
+
{
|
|
1333
|
+
className: cn(
|
|
1334
|
+
"inline-flex items-center gap-1.5 font-mono text-[11px] tracking-wider lowercase",
|
|
1335
|
+
TONE[tone],
|
|
1336
|
+
className
|
|
1337
|
+
),
|
|
1338
|
+
children: [
|
|
1339
|
+
icon,
|
|
1340
|
+
label
|
|
1341
|
+
]
|
|
1342
|
+
}
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
// src/format/index.ts
|
|
1347
|
+
var REFERENCE_BTC_USD = 95e3;
|
|
1348
|
+
function formatSats(sats) {
|
|
1349
|
+
return new Intl.NumberFormat("en-US").format(Math.round(sats));
|
|
1350
|
+
}
|
|
1351
|
+
function satsToUsd(sats, btcUsd = REFERENCE_BTC_USD) {
|
|
1352
|
+
const usd = sats / 1e8 * btcUsd;
|
|
1353
|
+
if (usd > 0 && usd < 0.01) return "< $0.01";
|
|
1354
|
+
const fractionDigits = usd >= 100 ? 0 : 2;
|
|
1355
|
+
return new Intl.NumberFormat("en-US", {
|
|
1356
|
+
style: "currency",
|
|
1357
|
+
currency: "USD",
|
|
1358
|
+
minimumFractionDigits: fractionDigits,
|
|
1359
|
+
maximumFractionDigits: fractionDigits
|
|
1360
|
+
}).format(usd);
|
|
1361
|
+
}
|
|
1362
|
+
function shortenAddress(value, head = 8, tail = 4) {
|
|
1363
|
+
if (!value) return "";
|
|
1364
|
+
if (value.length <= head + tail + 1) return value;
|
|
1365
|
+
return `${value.slice(0, head)}\u2026${value.slice(-tail)}`;
|
|
1366
|
+
}
|
|
1367
|
+
function SatsAmount({ sats, unit = true, usd = false, btcUsd, className }) {
|
|
1368
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-mono tabular-nums", className), children: [
|
|
1369
|
+
formatSats(sats),
|
|
1370
|
+
unit && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: " sats" }),
|
|
1371
|
+
usd && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
1372
|
+
" \xB7 ",
|
|
1373
|
+
satsToUsd(sats, btcUsd)
|
|
1374
|
+
] })
|
|
1375
|
+
] });
|
|
1376
|
+
}
|
|
1377
|
+
function CopyButton({
|
|
1378
|
+
value,
|
|
1379
|
+
label,
|
|
1380
|
+
clearAfter,
|
|
1381
|
+
size = "md",
|
|
1382
|
+
className,
|
|
1383
|
+
title,
|
|
1384
|
+
onCopied
|
|
1385
|
+
}) {
|
|
1386
|
+
const [copied, setCopied] = React2.useState(false);
|
|
1387
|
+
const resetRef = React2.useRef(null);
|
|
1388
|
+
const copy = React2.useCallback(async () => {
|
|
1389
|
+
try {
|
|
1390
|
+
await navigator.clipboard.writeText(value);
|
|
1391
|
+
setCopied(true);
|
|
1392
|
+
onCopied?.();
|
|
1393
|
+
if (resetRef.current) clearTimeout(resetRef.current);
|
|
1394
|
+
resetRef.current = setTimeout(() => setCopied(false), 1500);
|
|
1395
|
+
if (clearAfter && clearAfter > 0) {
|
|
1396
|
+
setTimeout(() => void wipeIfUnchanged(value), clearAfter * 1e3);
|
|
1397
|
+
}
|
|
1398
|
+
} catch {
|
|
1399
|
+
}
|
|
1400
|
+
}, [value, clearAfter, onCopied]);
|
|
1401
|
+
const iconSize = size === "sm" ? "size-3" : "size-3.5";
|
|
1402
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1403
|
+
"button",
|
|
1404
|
+
{
|
|
1405
|
+
type: "button",
|
|
1406
|
+
onClick: copy,
|
|
1407
|
+
"aria-label": title ?? (copied ? "copied" : "copy"),
|
|
1408
|
+
title: title ?? "copy",
|
|
1409
|
+
className: cn(
|
|
1410
|
+
"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",
|
|
1411
|
+
size === "sm" ? "text-[11px]" : "text-xs",
|
|
1412
|
+
className
|
|
1413
|
+
),
|
|
1414
|
+
children: [
|
|
1415
|
+
copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn(iconSize, "text-success"), "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: iconSize, "aria-hidden": true }),
|
|
1416
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: copied ? "copied" : label })
|
|
1417
|
+
]
|
|
1418
|
+
}
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
async function wipeIfUnchanged(expected) {
|
|
1422
|
+
try {
|
|
1423
|
+
const current = await navigator.clipboard.readText();
|
|
1424
|
+
if (current !== expected) return;
|
|
1425
|
+
await navigator.clipboard.writeText("");
|
|
1426
|
+
} catch {
|
|
1427
|
+
try {
|
|
1428
|
+
await navigator.clipboard.writeText("");
|
|
1429
|
+
} catch {
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
function BitcoinAddress({
|
|
1434
|
+
address,
|
|
1435
|
+
head = 8,
|
|
1436
|
+
tail = 4,
|
|
1437
|
+
copyable = true,
|
|
1438
|
+
full = false,
|
|
1439
|
+
className
|
|
1440
|
+
}) {
|
|
1441
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("inline-flex items-center gap-1.5 font-mono text-xs", className), children: [
|
|
1442
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { title: address, children: full ? address : shortenAddress(address, head, tail) }),
|
|
1443
|
+
copyable && /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: address, size: "sm", title: "copy address" })
|
|
1444
|
+
] });
|
|
1445
|
+
}
|
|
1446
|
+
function QrCode({ value, size = 200, label, className }) {
|
|
1447
|
+
const [svg, setSvg] = React2.useState(null);
|
|
1448
|
+
React2.useEffect(() => {
|
|
1449
|
+
let cancelled = false;
|
|
1450
|
+
QRCode__default.default.toString(value, {
|
|
1451
|
+
type: "svg",
|
|
1452
|
+
errorCorrectionLevel: "M",
|
|
1453
|
+
margin: 1,
|
|
1454
|
+
color: { dark: "#000000", light: "#ffffff" }
|
|
1455
|
+
}).then((out) => {
|
|
1456
|
+
if (!cancelled) setSvg(out);
|
|
1457
|
+
}).catch(() => {
|
|
1458
|
+
if (!cancelled) setSvg(null);
|
|
1459
|
+
});
|
|
1460
|
+
return () => {
|
|
1461
|
+
cancelled = true;
|
|
1462
|
+
};
|
|
1463
|
+
}, [value]);
|
|
1464
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1465
|
+
"div",
|
|
1466
|
+
{
|
|
1467
|
+
role: "img",
|
|
1468
|
+
"aria-label": label ?? `QR code for ${value.slice(0, 24)}\u2026`,
|
|
1469
|
+
className: "inline-block overflow-hidden rounded-md bg-white p-3 " + (className ?? ""),
|
|
1470
|
+
style: { width: size, height: size },
|
|
1471
|
+
children: svg ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1472
|
+
"div",
|
|
1473
|
+
{
|
|
1474
|
+
className: "size-full [&_svg]:block [&_svg]:size-full",
|
|
1475
|
+
dangerouslySetInnerHTML: { __html: svg }
|
|
1476
|
+
}
|
|
1477
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted/40 size-full animate-pulse rounded", "aria-hidden": true })
|
|
1478
|
+
}
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1171
1481
|
|
|
1172
1482
|
exports.Accordion = Accordion;
|
|
1173
1483
|
exports.AccordionContent = AccordionContent;
|
|
@@ -1179,8 +1489,12 @@ exports.AlertTitle = AlertTitle;
|
|
|
1179
1489
|
exports.AlertWithAction = AlertWithAction;
|
|
1180
1490
|
exports.AlertWithCountdown = AlertWithCountdown;
|
|
1181
1491
|
exports.Badge = Badge;
|
|
1492
|
+
exports.Bar = Bar;
|
|
1493
|
+
exports.BitcoinAddress = BitcoinAddress;
|
|
1182
1494
|
exports.Button = Button;
|
|
1495
|
+
exports.Card = Card;
|
|
1183
1496
|
exports.ConfirmHost = ConfirmHost;
|
|
1497
|
+
exports.CopyButton = CopyButton;
|
|
1184
1498
|
exports.Dialog = Dialog;
|
|
1185
1499
|
exports.DialogClose = DialogClose;
|
|
1186
1500
|
exports.DialogContent = DialogContent;
|
|
@@ -1201,6 +1515,8 @@ exports.PopoverAnchor = PopoverAnchor;
|
|
|
1201
1515
|
exports.PopoverContent = PopoverContent;
|
|
1202
1516
|
exports.PopoverTrigger = PopoverTrigger;
|
|
1203
1517
|
exports.PromptHost = PromptHost;
|
|
1518
|
+
exports.QrCode = QrCode;
|
|
1519
|
+
exports.SatsAmount = SatsAmount;
|
|
1204
1520
|
exports.Select = Select;
|
|
1205
1521
|
exports.SelectContent = SelectContent;
|
|
1206
1522
|
exports.SelectGroup = SelectGroup;
|
|
@@ -1221,6 +1537,9 @@ exports.SheetPortal = SheetPortal;
|
|
|
1221
1537
|
exports.SheetTitle = SheetTitle;
|
|
1222
1538
|
exports.SheetTrigger = SheetTrigger;
|
|
1223
1539
|
exports.Skeleton = Skeleton;
|
|
1540
|
+
exports.Sparkline = Sparkline;
|
|
1541
|
+
exports.StatBlock = StatBlock;
|
|
1542
|
+
exports.StatusPill = StatusPill;
|
|
1224
1543
|
exports.Textarea = Textarea;
|
|
1225
1544
|
exports.ThemeToggle = ThemeToggle;
|
|
1226
1545
|
exports.ThemeToggleLink = ThemeToggleLink;
|