@chainvibe/components 0.2.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/README.md +1 -0
- package/dist/_virtual/config.js +4 -0
- package/dist/_virtual/core.js +4 -0
- package/dist/_virtual/debug.js +4 -0
- package/dist/_virtual/encode.js +4 -0
- package/dist/_virtual/helpers.js +4 -0
- package/dist/_virtual/index.js +5 -0
- package/dist/_virtual/index2.js +4 -0
- package/dist/_virtual/memory.js +4 -0
- package/dist/_virtual/number.js +4 -0
- package/dist/components/NotificationBox/NotificationBox.d.ts +41 -0
- package/dist/components/NotificationBox/NotificationBox.d.ts.map +1 -0
- package/dist/components/NotificationBox/NotificationBox.js +86 -0
- package/dist/components/NotificationBox/NotificationBox.module.css +1 -0
- package/dist/components/NotificationBox/NotificationBox.module.css.js +29 -0
- package/dist/components/NotificationBox/index.d.ts +3 -0
- package/dist/components/NotificationBox/index.d.ts.map +1 -0
- package/dist/components/NotificationBoxAmount/NotificationBoxAmount.d.ts +13 -0
- package/dist/components/NotificationBoxAmount/NotificationBoxAmount.d.ts.map +1 -0
- package/dist/components/NotificationBoxAmount/NotificationBoxAmount.js +45 -0
- package/dist/components/NotificationBoxAmount/NotificationBoxAmount.module.css +1 -0
- package/dist/components/NotificationBoxAmount/NotificationBoxAmount.module.css.js +11 -0
- package/dist/components/NotificationBoxAmount/index.d.ts +2 -0
- package/dist/components/NotificationBoxAmount/index.d.ts.map +1 -0
- package/dist/components/NotificationBoxStack/NotificationBoxStack.d.ts +14 -0
- package/dist/components/NotificationBoxStack/NotificationBoxStack.d.ts.map +1 -0
- package/dist/components/NotificationBoxStack/NotificationBoxStack.js +47 -0
- package/dist/components/NotificationBoxStack/index.d.ts +3 -0
- package/dist/components/NotificationBoxStack/index.d.ts.map +1 -0
- package/dist/components/utils/cn.d.ts +2 -0
- package/dist/components/utils/cn.d.ts.map +1 -0
- package/dist/components/utils/cn.js +4 -0
- package/dist/dev/utils.js +55 -0
- package/dist/hooks/useChainVibeStream.js +60 -0
- package/dist/index.js +10 -0
- package/dist/node_modules/@number-flow/react/dist/NumberFlow-client-48rw3j0J.js +111 -0
- package/dist/node_modules/compress-json/dist/config.js +16 -0
- package/dist/node_modules/compress-json/dist/core.js +92 -0
- package/dist/node_modules/compress-json/dist/debug.js +19 -0
- package/dist/node_modules/compress-json/dist/encode.js +58 -0
- package/dist/node_modules/compress-json/dist/helpers.js +27 -0
- package/dist/node_modules/compress-json/dist/index.js +38 -0
- package/dist/node_modules/compress-json/dist/memory.js +128 -0
- package/dist/node_modules/compress-json/dist/number.js +119 -0
- package/dist/node_modules/number-flow/dist/lite-BtgQ9jUv.js +435 -0
- package/dist/node_modules/sonner/dist/index.js +744 -0
- package/dist/types/events.d.ts +22 -0
- package/dist/types/events.d.ts.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# ChainVibe components
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
import { ChainVibeEvent } from '../../types/events';
|
|
3
|
+
import { Abi } from 'abitype';
|
|
4
|
+
export interface NotificationBoxProps<TAbi extends Abi> extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
event?: ChainVibeEvent<TAbi>;
|
|
6
|
+
wrapperClassName?: string;
|
|
7
|
+
headerClassName?: string;
|
|
8
|
+
titleGroupClassName?: string;
|
|
9
|
+
titleClassName?: string;
|
|
10
|
+
badgeClassName?: string;
|
|
11
|
+
timestampClassName?: string;
|
|
12
|
+
messageClassName?: string;
|
|
13
|
+
metaGridClassName?: string;
|
|
14
|
+
metaItemClassName?: string;
|
|
15
|
+
metaLabelClassName?: string;
|
|
16
|
+
metaValueClassName?: string;
|
|
17
|
+
metaMonoClassName?: string;
|
|
18
|
+
show?: {
|
|
19
|
+
title?: boolean;
|
|
20
|
+
message?: boolean;
|
|
21
|
+
action?: boolean;
|
|
22
|
+
timestamp?: boolean;
|
|
23
|
+
wallet?: boolean;
|
|
24
|
+
hash?: boolean;
|
|
25
|
+
amount?: boolean;
|
|
26
|
+
amountUSD?: boolean;
|
|
27
|
+
tokenSymbol?: boolean;
|
|
28
|
+
rawAmounts?: boolean;
|
|
29
|
+
timestampTimeAgo?: boolean;
|
|
30
|
+
};
|
|
31
|
+
format?: {
|
|
32
|
+
timestampTimeAgo?: (timestamp: number) => string;
|
|
33
|
+
timestamp?: (timestamp: number) => string;
|
|
34
|
+
hash?: (hash: `0x${string}`) => string;
|
|
35
|
+
wallet?: (wallet: `0x${string}`) => string;
|
|
36
|
+
amount?: (amount: string) => string;
|
|
37
|
+
amountUSD?: (amount: string) => string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export declare function NotificationBox<TAbi extends Abi>({ event, wrapperClassName, headerClassName, titleGroupClassName, titleClassName, badgeClassName, timestampClassName, messageClassName, metaGridClassName, metaItemClassName, metaLabelClassName, metaValueClassName, metaMonoClassName, show, format, ...props }: NotificationBoxProps<TAbi>): import("react/jsx-runtime").JSX.Element | null;
|
|
41
|
+
//# sourceMappingURL=NotificationBox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationBox.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationBox/NotificationBox.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAuB,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,SAAS,CAAC;AA2BnC,MAAM,WAAW,oBAAoB,CACnC,IAAI,SAAS,GAAG,CAChB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACtC,KAAK,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE;QACL,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;IACF,MAAM,CAAC,EAAE;QACP,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;QACjD,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;QAC1C,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,CAAC;QACvC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,CAAC;QAC3C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;QACpC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;KACxC,CAAC;CACH;AAED,wBAAgB,eAAe,CAAC,IAAI,SAAS,GAAG,EAAE,EAChD,KAAK,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,IAKC,EACD,MAAM,EACN,GAAG,KAAK,EACT,EAAE,oBAAoB,CAAC,IAAI,CAAC,kDA0I5B"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import styles from "./NotificationBox.module.css.js";
|
|
4
|
+
import { cn } from "../utils/cn.js";
|
|
5
|
+
const abbreviate = (s) => `${s.slice(0, 6)}...${s.slice(-4)}`, formatNumber = (n) => {
|
|
6
|
+
const x = parseFloat(n);
|
|
7
|
+
return x >= 1e9 ? (x / 1e9).toFixed(2) + "B" : x >= 1e6 ? (x / 1e6).toFixed(2) + "M" : x >= 1e3 ? (x / 1e3).toFixed(2) + "K" : x.toString();
|
|
8
|
+
}, formatTimeAgo = (ts) => {
|
|
9
|
+
const d = Date.now() - ts;
|
|
10
|
+
return d < 6e4 ? "Just now" : d < 36e5 ? `${Math.floor(d / 6e4)}m` : d < 864e5 ? `${Math.floor(d / 36e5)}h` : `${Math.floor(d / 864e5)}d`;
|
|
11
|
+
};
|
|
12
|
+
function NotificationBox({
|
|
13
|
+
event,
|
|
14
|
+
wrapperClassName,
|
|
15
|
+
headerClassName,
|
|
16
|
+
titleGroupClassName,
|
|
17
|
+
titleClassName,
|
|
18
|
+
badgeClassName,
|
|
19
|
+
timestampClassName,
|
|
20
|
+
messageClassName,
|
|
21
|
+
metaGridClassName,
|
|
22
|
+
metaItemClassName,
|
|
23
|
+
metaLabelClassName,
|
|
24
|
+
metaValueClassName,
|
|
25
|
+
metaMonoClassName,
|
|
26
|
+
show = {
|
|
27
|
+
title: !0,
|
|
28
|
+
message: !0,
|
|
29
|
+
action: !0,
|
|
30
|
+
timestampTimeAgo: !0
|
|
31
|
+
},
|
|
32
|
+
format,
|
|
33
|
+
...props
|
|
34
|
+
}) {
|
|
35
|
+
const [displayTime, setDisplayTime] = useState(""), fmt = format?.timestampTimeAgo || formatTimeAgo;
|
|
36
|
+
if (useEffect(() => {
|
|
37
|
+
if (!show.timestampTimeAgo || !event) return;
|
|
38
|
+
setDisplayTime(fmt(event.timestamp));
|
|
39
|
+
const i = setInterval(() => setDisplayTime(fmt(event.timestamp)), 5 * 1e3);
|
|
40
|
+
return () => clearInterval(i);
|
|
41
|
+
}, [event?.timestamp, show.timestampTimeAgo, fmt]), !event) return null;
|
|
42
|
+
const { data } = event, fmtTs = show.timestampTimeAgo ? displayTime : format?.timestamp ? format.timestamp(event.timestamp) : new Date(event.timestamp).toLocaleString();
|
|
43
|
+
return /* @__PURE__ */ jsxs("div", { className: cn(styles.notificationBox, wrapperClassName), ...props, children: [
|
|
44
|
+
/* @__PURE__ */ jsxs("div", { className: cn(styles.header, headerClassName), children: [
|
|
45
|
+
/* @__PURE__ */ jsxs("div", { className: cn(styles.titleGroup, titleGroupClassName), children: [
|
|
46
|
+
show.title && /* @__PURE__ */ jsx("div", { className: cn(styles.title, titleClassName), children: data.title }),
|
|
47
|
+
show.action && /* @__PURE__ */ jsx("div", { className: cn(styles.badge, badgeClassName), children: data.action })
|
|
48
|
+
] }),
|
|
49
|
+
(show.timestamp || show.timestampTimeAgo) && /* @__PURE__ */ jsx("div", { className: cn(styles.timestamp, timestampClassName), children: fmtTs })
|
|
50
|
+
] }),
|
|
51
|
+
show.message && /* @__PURE__ */ jsx("div", { className: cn(styles.message, messageClassName), children: data.message }),
|
|
52
|
+
(show.amount || show.tokenSymbol || show.amountUSD || show.wallet || show.hash) && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaGrid, metaGridClassName), children: [
|
|
53
|
+
show.amount && data.amount && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaItem, metaItemClassName), children: [
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaLabel, metaLabelClassName), children: "Amount" }),
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaValue, metaValueClassName), children: format?.amount ? format.amount(data.amount) : formatNumber(data.amount) })
|
|
56
|
+
] }),
|
|
57
|
+
show.tokenSymbol && data.tokenSymbol && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaItem, metaItemClassName), children: [
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaLabel, metaLabelClassName), children: "Token" }),
|
|
59
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaValue, metaValueClassName), children: data.tokenSymbol })
|
|
60
|
+
] }),
|
|
61
|
+
show.amountUSD && data.amountUSD && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaItem, metaItemClassName), children: [
|
|
62
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaLabel, metaLabelClassName), children: "USD" }),
|
|
63
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaValue, metaValueClassName), children: format?.amountUSD ? format.amountUSD(data.amountUSD) : formatNumber(data.amountUSD) })
|
|
64
|
+
] }),
|
|
65
|
+
show.wallet && data.wallet && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaItem, metaItemClassName), children: [
|
|
66
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaLabel, metaLabelClassName), children: "Wallet" }),
|
|
67
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaMono, metaMonoClassName), children: format?.wallet ? format.wallet(data.wallet) : abbreviate(data.wallet) })
|
|
68
|
+
] }),
|
|
69
|
+
show.hash && data.hash && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaItem, metaItemClassName), children: [
|
|
70
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaLabel, metaLabelClassName), children: "Hash" }),
|
|
71
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaMono, metaMonoClassName), children: format?.hash ? format.hash(data.hash) : abbreviate(data.hash) })
|
|
72
|
+
] }),
|
|
73
|
+
show.rawAmounts && data.amountRaw && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaItem, metaItemClassName), children: [
|
|
74
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaLabel, metaLabelClassName), children: "Amount Raw" }),
|
|
75
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaMono, metaMonoClassName), children: data.amountRaw })
|
|
76
|
+
] }),
|
|
77
|
+
show.rawAmounts && data.amountUSDRaw && /* @__PURE__ */ jsxs("div", { className: cn(styles.metaItem, metaItemClassName), children: [
|
|
78
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaLabel, metaLabelClassName), children: "USD Raw" }),
|
|
79
|
+
/* @__PURE__ */ jsx("span", { className: cn(styles.metaMono, metaMonoClassName), children: data.amountUSDRaw })
|
|
80
|
+
] })
|
|
81
|
+
] })
|
|
82
|
+
] });
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
NotificationBox
|
|
86
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--cv-nb-bg: #f7f7f8;--cv-nb-bg-elevated: #ffffff;--cv-nb-border: #e6e7eb;--cv-nb-text: #0f172a;--cv-nb-muted: #6b7280;--cv-nb-accent: #3b82f6;--cv-nb-badge-bg: #eef2ff;--cv-nb-badge-text: #3730a3;--cv-nb-shadow: 0 10px 30px rgba(15, 23, 42, .08)}@media(prefers-color-scheme:dark){:root{--cv-nb-bg: #0b0f14;--cv-nb-bg-elevated: #121821;--cv-nb-border: #1f2937;--cv-nb-text: #e5e7eb;--cv-nb-muted: #94a3b8;--cv-nb-accent: #60a5fa;--cv-nb-badge-bg: #1e293b;--cv-nb-badge-text: #c7d2fe;--cv-nb-shadow: 0 16px 40px rgba(0, 0, 0, .35)}}[data-theme=light]{--cv-nb-bg: #f7f7f8;--cv-nb-bg-elevated: #ffffff;--cv-nb-border: #e6e7eb;--cv-nb-text: #0f172a;--cv-nb-muted: #6b7280;--cv-nb-accent: #3b82f6;--cv-nb-badge-bg: #eef2ff;--cv-nb-badge-text: #3730a3;--cv-nb-shadow: 0 10px 30px rgba(15, 23, 42, .08)}[data-theme=dark]{--cv-nb-bg: #0b0f14;--cv-nb-bg-elevated: #121821;--cv-nb-border: #1f2937;--cv-nb-text: #e5e7eb;--cv-nb-muted: #94a3b8;--cv-nb-accent: #60a5fa;--cv-nb-badge-bg: #1e293b;--cv-nb-badge-text: #c7d2fe;--cv-nb-shadow: 0 16px 40px rgba(0, 0, 0, .35)}._notificationBox_q03fz_51{background:var(--cv-nb-bg-elevated);border:1px solid var(--cv-nb-border);border-radius:14px;padding:16px 18px;color:var(--cv-nb-text);box-shadow:var(--cv-nb-shadow);display:flex;flex-direction:column;gap:12px;min-width:260px}._header_q03fz_64{display:flex;align-items:center;justify-content:space-between;gap:12px}._titleGroup_q03fz_71{display:flex;align-items:center;gap:10px;flex-wrap:wrap}._title_q03fz_71{font-size:15px;font-weight:600;letter-spacing:.01em}._badge_q03fz_84{font-size:11px;font-weight:600;padding:4px 8px;border-radius:999px;background:var(--cv-nb-badge-bg);color:var(--cv-nb-badge-text);text-transform:uppercase;letter-spacing:.08em}._timestamp_q03fz_95{font-size:12px;color:var(--cv-nb-muted);white-space:nowrap}._message_q03fz_101{font-size:14px;line-height:1.5;color:var(--cv-nb-text)}._metaGrid_q03fz_107{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px 16px;padding-top:8px;border-top:1px solid var(--cv-nb-border)}._metaItem_q03fz_115{display:flex;flex-direction:column;gap:4px}._metaLabel_q03fz_121{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--cv-nb-muted)}._metaValue_q03fz_128{font-size:13px;font-weight:600}._metaMono_q03fz_133{font-size:12px;font-family:SFMono-Regular,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;color:var(--cv-nb-text)}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const notificationBox = "_notificationBox_q03fz_51", header = "_header_q03fz_64", titleGroup = "_titleGroup_q03fz_71", title = "_title_q03fz_71", badge = "_badge_q03fz_84", timestamp = "_timestamp_q03fz_95", message = "_message_q03fz_101", metaGrid = "_metaGrid_q03fz_107", metaItem = "_metaItem_q03fz_115", metaLabel = "_metaLabel_q03fz_121", metaValue = "_metaValue_q03fz_128", metaMono = "_metaMono_q03fz_133", styles = {
|
|
2
|
+
notificationBox,
|
|
3
|
+
header,
|
|
4
|
+
titleGroup,
|
|
5
|
+
title,
|
|
6
|
+
badge,
|
|
7
|
+
timestamp,
|
|
8
|
+
message,
|
|
9
|
+
metaGrid,
|
|
10
|
+
metaItem,
|
|
11
|
+
metaLabel,
|
|
12
|
+
metaValue,
|
|
13
|
+
metaMono
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
badge,
|
|
17
|
+
styles as default,
|
|
18
|
+
header,
|
|
19
|
+
message,
|
|
20
|
+
metaGrid,
|
|
21
|
+
metaItem,
|
|
22
|
+
metaLabel,
|
|
23
|
+
metaMono,
|
|
24
|
+
metaValue,
|
|
25
|
+
notificationBox,
|
|
26
|
+
timestamp,
|
|
27
|
+
title,
|
|
28
|
+
titleGroup
|
|
29
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationBox/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
import { NumberFlowProps } from '@number-flow/react';
|
|
3
|
+
export interface NotificationBoxAmountProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
amount: string | number;
|
|
5
|
+
label?: string;
|
|
6
|
+
prefix?: string;
|
|
7
|
+
wrapperClassName?: string;
|
|
8
|
+
labelClassName?: string;
|
|
9
|
+
valueClassName?: string;
|
|
10
|
+
numberFlowProps?: Partial<NumberFlowProps>;
|
|
11
|
+
}
|
|
12
|
+
export declare function NotificationBoxAmount({ amount, label, prefix, wrapperClassName, labelClassName, valueClassName, numberFlowProps, ...props }: NotificationBoxAmountProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=NotificationBoxAmount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationBoxAmount.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationBoxAmount/NotificationBoxAmount.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAItE,MAAM,WAAW,0BAA2B,SAAQ,cAAc,CAAC,cAAc,CAAC;IAChF,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;CAC5C;AAED,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,KAAyC,EACzC,MAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,EACf,GAAG,KAAK,EACT,EAAE,0BAA0B,2CAuB5B"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import "../../node_modules/number-flow/dist/lite-BtgQ9jUv.js";
|
|
4
|
+
import { N as NumberFlow } from "../../node_modules/@number-flow/react/dist/NumberFlow-client-48rw3j0J.js";
|
|
5
|
+
import styles from "./NotificationBoxAmount.module.css.js";
|
|
6
|
+
import { cn } from "../utils/cn.js";
|
|
7
|
+
function NotificationBoxAmount({
|
|
8
|
+
amount,
|
|
9
|
+
label = "USD moved since opened the page",
|
|
10
|
+
prefix = "$",
|
|
11
|
+
wrapperClassName,
|
|
12
|
+
labelClassName,
|
|
13
|
+
valueClassName,
|
|
14
|
+
numberFlowProps,
|
|
15
|
+
...props
|
|
16
|
+
}) {
|
|
17
|
+
const numericValue = typeof amount == "string" ? parseFloat(amount) || 0 : amount;
|
|
18
|
+
return /* @__PURE__ */ jsxs(
|
|
19
|
+
"div",
|
|
20
|
+
{
|
|
21
|
+
className: cn(styles.notificationBoxAmount, wrapperClassName),
|
|
22
|
+
...props,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsxs("div", { className: cn(styles.value, valueClassName), children: [
|
|
25
|
+
prefix,
|
|
26
|
+
/* @__PURE__ */ jsx(
|
|
27
|
+
NumberFlow,
|
|
28
|
+
{
|
|
29
|
+
value: numericValue,
|
|
30
|
+
format: {
|
|
31
|
+
minimumFractionDigits: 2,
|
|
32
|
+
maximumFractionDigits: 2
|
|
33
|
+
},
|
|
34
|
+
...numberFlowProps
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
] }),
|
|
38
|
+
label && /* @__PURE__ */ jsx("div", { className: cn(styles.label, labelClassName), children: label })
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
NotificationBoxAmount
|
|
45
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--cv-nba-bg: #f7f7f8;--cv-nba-bg-elevated: #ffffff;--cv-nba-border: #e6e7eb;--cv-nba-text: #0f172a;--cv-nba-muted: #6b7280;--cv-nba-accent: #3b82f6;--cv-nba-shadow: 0 10px 30px rgba(15, 23, 42, .08)}@media(prefers-color-scheme:dark){:root{--cv-nba-bg: #0b0f14;--cv-nba-bg-elevated: #121821;--cv-nba-border: #1f2937;--cv-nba-text: #e5e7eb;--cv-nba-muted: #94a3b8;--cv-nba-accent: #60a5fa;--cv-nba-shadow: 0 16px 40px rgba(0, 0, 0, .35)}}[data-theme=light]{--cv-nba-bg: #f7f7f8;--cv-nba-bg-elevated: #ffffff;--cv-nba-border: #e6e7eb;--cv-nba-text: #0f172a;--cv-nba-muted: #6b7280;--cv-nba-accent: #3b82f6;--cv-nba-shadow: 0 10px 30px rgba(15, 23, 42, .08)}[data-theme=dark]{--cv-nba-bg: #0b0f14;--cv-nba-bg-elevated: #121821;--cv-nba-border: #1f2937;--cv-nba-text: #e5e7eb;--cv-nba-muted: #94a3b8;--cv-nba-accent: #60a5fa;--cv-nba-shadow: 0 16px 40px rgba(0, 0, 0, .35)}._notificationBoxAmount_18aq3_43{background:var(--cv-nba-bg-elevated);border:1px solid var(--cv-nba-border);border-radius:14px;padding:20px 24px;color:var(--cv-nba-text);box-shadow:var(--cv-nba-shadow);display:flex;flex-direction:column;gap:8px;min-width:200px;text-align:center}._label_18aq3_57{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--cv-nba-muted)}._value_18aq3_65{font-size:32px;font-weight:700;letter-spacing:-.02em;color:var(--cv-nba-text);font-variant-numeric:tabular-nums;line-height:1.2}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationBoxAmount/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { ToasterProps, ExternalToast } from 'sonner';
|
|
3
|
+
import { ChainVibeEvent } from '../../types/events';
|
|
4
|
+
import { NotificationBoxProps } from '../NotificationBox/NotificationBox';
|
|
5
|
+
import { Abi } from 'abitype';
|
|
6
|
+
export interface NotificationBoxStackProps<TAbi extends Abi> extends React.HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
events?: ChainVibeEvent<TAbi>[];
|
|
8
|
+
itemsCount?: number;
|
|
9
|
+
notificationBoxProps?: Partial<Omit<NotificationBoxProps<TAbi>, "event">>;
|
|
10
|
+
toastOptions?: ExternalToast;
|
|
11
|
+
toasterProps?: ToasterProps;
|
|
12
|
+
}
|
|
13
|
+
export declare function NotificationBoxStack<TAbi extends Abi>({ events, itemsCount, notificationBoxProps, toastOptions, toasterProps, }: NotificationBoxStackProps<TAbi>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=NotificationBoxStack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationBoxStack.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationBoxStack/NotificationBoxStack.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAEL,YAAY,EAEZ,KAAK,aAAa,EACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,mCAAmC,CAAC;AAE3C,MAAM,WAAW,yBAAyB,CACxC,IAAI,SAAS,GAAG,CAChB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5C,MAAM,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,wBAAgB,oBAAoB,CAAC,IAAI,SAAS,GAAG,EAAE,EACrD,MAAW,EACX,UAAc,EACd,oBAAyB,EACzB,YAAY,EACZ,YAAY,GACb,EAAE,yBAAyB,CAAC,IAAI,CAAC,2CA4CjC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect } from "react";
|
|
3
|
+
import { toast, Toaster } from "../../node_modules/sonner/dist/index.js";
|
|
4
|
+
import { NotificationBox } from "../NotificationBox/NotificationBox.js";
|
|
5
|
+
function NotificationBoxStack({
|
|
6
|
+
events = [],
|
|
7
|
+
itemsCount = 5,
|
|
8
|
+
notificationBoxProps = {},
|
|
9
|
+
toastOptions,
|
|
10
|
+
toasterProps
|
|
11
|
+
}) {
|
|
12
|
+
const toastIds = useRef(/* @__PURE__ */ new Map());
|
|
13
|
+
return useEffect(() => {
|
|
14
|
+
const activeKeys = /* @__PURE__ */ new Set();
|
|
15
|
+
events.slice(-itemsCount).forEach((event) => {
|
|
16
|
+
const key = `${event.data.id}`;
|
|
17
|
+
if (activeKeys.add(key), toastIds.current.has(key)) return;
|
|
18
|
+
const id = toast.custom(
|
|
19
|
+
() => /* @__PURE__ */ jsx(NotificationBox, { event, ...notificationBoxProps }),
|
|
20
|
+
{
|
|
21
|
+
id: key,
|
|
22
|
+
duration: 1 / 0,
|
|
23
|
+
dismissible: !1,
|
|
24
|
+
classNames: {
|
|
25
|
+
toast: "cv-sonner-toast"
|
|
26
|
+
},
|
|
27
|
+
...toastOptions
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
toastIds.current.set(key, id);
|
|
31
|
+
}), Array.from(toastIds.current.entries()).forEach(([key, id]) => {
|
|
32
|
+
activeKeys.has(key) || (toast.dismiss(id), toastIds.current.delete(key));
|
|
33
|
+
});
|
|
34
|
+
}, [events, toastOptions, notificationBoxProps]), /* @__PURE__ */ jsx(
|
|
35
|
+
Toaster,
|
|
36
|
+
{
|
|
37
|
+
richColors: !1,
|
|
38
|
+
closeButton: !1,
|
|
39
|
+
duration: 1 / 0,
|
|
40
|
+
visibleToasts: itemsCount,
|
|
41
|
+
...toasterProps
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
NotificationBoxStack
|
|
47
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationBoxStack/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,KAAK,yBAAyB,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../../src/components/utils/cn.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,GAAI,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC,EAAE,WAC1B,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const protocols = ["Aave V3", "Uniswap V3", "Curve", "Balancer", "Lido"], chains = ["Ethereum", "Arbitrum", "Optimism", "Polygon", "Base"], actionsWithContext = [
|
|
2
|
+
{ action: "Supply", verb: "supplied" },
|
|
3
|
+
{ action: "Withdraw", verb: "withdrew" },
|
|
4
|
+
{ action: "Swap", verb: "swapped" },
|
|
5
|
+
{ action: "Stake", verb: "staked" },
|
|
6
|
+
{ action: "Mint", verb: "minted" }
|
|
7
|
+
], tokens = [
|
|
8
|
+
{ symbol: "ETH", decimals: 18, price: 2800 },
|
|
9
|
+
{ symbol: "USDC", decimals: 6, price: 1 },
|
|
10
|
+
{ symbol: "DAI", decimals: 18, price: 1 },
|
|
11
|
+
{ symbol: "USDT", decimals: 6, price: 1 },
|
|
12
|
+
{ symbol: "ARB", decimals: 18, price: 0.85 },
|
|
13
|
+
{ symbol: "OP", decimals: 18, price: 2.1 },
|
|
14
|
+
{ symbol: "MATIC", decimals: 18, price: 0.6 },
|
|
15
|
+
{ symbol: "WBTC", decimals: 8, price: 42e3 }
|
|
16
|
+
], randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min, randomPick = (arr) => arr[randomInt(0, arr.length - 1)], randomHex = (length) => {
|
|
17
|
+
const chars = "0123456789abcdef";
|
|
18
|
+
let out = "";
|
|
19
|
+
for (let i = 0; i < length; i += 1)
|
|
20
|
+
out += chars[randomInt(0, chars.length - 1)];
|
|
21
|
+
return out;
|
|
22
|
+
}, randomAddress = () => `0x${randomHex(40)}`, formatAddress = (address) => `${address.slice(0, 6)}...${address.slice(-4)}`, formatAmount = (rawAmount, decimals) => {
|
|
23
|
+
const num = BigInt(rawAmount), divisor = BigInt(10 ** decimals), integer = num / divisor, trimmed = (num % divisor).toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
24
|
+
return trimmed ? `${integer}.${trimmed}` : integer.toString();
|
|
25
|
+
}, formatDisplayNumber = (numStr, decimals = 2) => {
|
|
26
|
+
const num = parseFloat(numStr);
|
|
27
|
+
return num >= 1e9 ? (num / 1e9).toFixed(decimals) + "B" : num >= 1e6 ? (num / 1e6).toFixed(decimals) + "M" : num >= 1e3 ? (num / 1e3).toFixed(decimals) + "K" : num.toFixed(decimals);
|
|
28
|
+
}, generateRandomEvent = () => {
|
|
29
|
+
const token = randomPick(tokens), action = randomPick(actionsWithContext), protocol = randomPick(protocols), chain = randomPick(chains);
|
|
30
|
+
let amountMin, amountMax;
|
|
31
|
+
token.price > 1e3 ? (amountMin = 0.01, amountMax = 1) : token.price > 1 ? (amountMin = 10, amountMax = 1e4) : (amountMin = 100, amountMax = 1e5);
|
|
32
|
+
const amountWithDecimals = amountMin + Math.random() * (amountMax - amountMin) + Math.random(), amountRaw = BigInt(
|
|
33
|
+
Math.floor(amountWithDecimals * 10 ** token.decimals)
|
|
34
|
+
).toString(), amount = formatAmount(amountRaw, token.decimals), amountDisplay = formatDisplayNumber(amount), amountUSDNumeric = parseFloat(amount) * token.price, amountUSD = `$${formatDisplayNumber(amountUSDNumeric.toString())}`, amountUSDRaw = amountUSDNumeric.toString();
|
|
35
|
+
return {
|
|
36
|
+
clientId: `client_${randomHex(8)}`,
|
|
37
|
+
timestamp: Date.now(),
|
|
38
|
+
data: {
|
|
39
|
+
id: `event_${randomHex(12)}`,
|
|
40
|
+
title: `${protocol} ${chain} ${action.action}`,
|
|
41
|
+
message: `User ${formatAddress(randomAddress())} ${action.verb} ${amountDisplay} ${token.symbol} (${amountUSD})`,
|
|
42
|
+
hash: randomAddress(),
|
|
43
|
+
wallet: randomAddress(),
|
|
44
|
+
tokenSymbol: token.symbol,
|
|
45
|
+
amount,
|
|
46
|
+
amountRaw,
|
|
47
|
+
amountUSD,
|
|
48
|
+
amountUSDRaw,
|
|
49
|
+
action: action.action
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
generateRandomEvent
|
|
55
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { d as distExports } from "../_virtual/index.js";
|
|
2
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
3
|
+
import { generateRandomEvent } from "../dev/utils.js";
|
|
4
|
+
const useChainVibeStream = ({
|
|
5
|
+
id,
|
|
6
|
+
keepLast = 5,
|
|
7
|
+
onNewEvent
|
|
8
|
+
}) => {
|
|
9
|
+
const [usdSinceStart, setUsdSinceStart] = useState("0"), [events, setEvents] = useState([]), wsRef = useRef(null), onNewEventRef = useRef(onNewEvent);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
onNewEventRef.current = onNewEvent;
|
|
12
|
+
}, [onNewEvent]);
|
|
13
|
+
const addRandomEvent = useCallback(() => {
|
|
14
|
+
const newEvent = generateRandomEvent();
|
|
15
|
+
setUsdSinceStart(
|
|
16
|
+
(prev) => (Number(prev) + Number(newEvent.data.amountUSDRaw || "0")).toString()
|
|
17
|
+
), setEvents((prev) => {
|
|
18
|
+
onNewEventRef.current && onNewEventRef.current(newEvent);
|
|
19
|
+
const nextEvents = [...prev, newEvent];
|
|
20
|
+
return keepLast && nextEvents.length > keepLast ? nextEvents.slice(-keepLast) : nextEvents;
|
|
21
|
+
});
|
|
22
|
+
}, [keepLast]);
|
|
23
|
+
return useEffect(() => {
|
|
24
|
+
if (!id)
|
|
25
|
+
return console.log("[ChainVibe] No id provided, skipping WebSocket connection."), () => {
|
|
26
|
+
};
|
|
27
|
+
let didUnmount = !1;
|
|
28
|
+
const ws = new WebSocket(`wss://api.chainvi.be/stream/${id}`);
|
|
29
|
+
return wsRef.current = ws, ws.onopen = () => {
|
|
30
|
+
didUnmount || console.log(`[ChainVibe] WebSocket connected for project ${id}`);
|
|
31
|
+
}, ws.onmessage = (event) => {
|
|
32
|
+
try {
|
|
33
|
+
const payload = distExports.decompress(JSON.parse(event.data));
|
|
34
|
+
if (payload.recentEvents) {
|
|
35
|
+
setEvents(payload.recentEvents);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!payload || !payload.data)
|
|
39
|
+
return;
|
|
40
|
+
setUsdSinceStart(
|
|
41
|
+
(prev) => (Number(prev) + Number(payload.data.amountUSDRaw || "0")).toString()
|
|
42
|
+
), setEvents((prev) => {
|
|
43
|
+
onNewEventRef.current && onNewEventRef.current(payload);
|
|
44
|
+
const newEvents = [...prev, payload];
|
|
45
|
+
return keepLast && newEvents.length > keepLast ? newEvents.slice(-keepLast) : newEvents;
|
|
46
|
+
});
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error("[ChainVibe] Error processing message:", err);
|
|
49
|
+
}
|
|
50
|
+
}, ws.onerror = (error) => {
|
|
51
|
+
!didUnmount && ws.readyState !== WebSocket.CLOSING && console.error(`[ChainVibe] WebSocket error for project ${id}`, error);
|
|
52
|
+
}, ws.onclose = () => {
|
|
53
|
+
}, () => {
|
|
54
|
+
didUnmount = !0, ws.close(), wsRef.current = null;
|
|
55
|
+
};
|
|
56
|
+
}, [id, keepLast]), { events, usdSinceStart, addRandomEvent };
|
|
57
|
+
};
|
|
58
|
+
export {
|
|
59
|
+
useChainVibeStream
|
|
60
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useChainVibeStream } from "./hooks/useChainVibeStream.js";
|
|
2
|
+
import { NotificationBox } from "./components/NotificationBox/NotificationBox.js";
|
|
3
|
+
import { NotificationBoxAmount } from "./components/NotificationBoxAmount/NotificationBoxAmount.js";
|
|
4
|
+
import { NotificationBoxStack } from "./components/NotificationBoxStack/NotificationBoxStack.js";
|
|
5
|
+
export {
|
|
6
|
+
NotificationBox,
|
|
7
|
+
NotificationBoxAmount,
|
|
8
|
+
NotificationBoxStack,
|
|
9
|
+
useChainVibeStream
|
|
10
|
+
};
|