@blocklet/ui-react 3.0.20 → 3.0.22
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/lib/UserCenter/components/nft-preview.d.ts +11 -0
- package/lib/UserCenter/components/nft-preview.js +60 -0
- package/lib/UserCenter/components/nft.js +174 -61
- package/lib/UserCenter/components/user-info/link-preview-input.js +61 -60
- package/lib/UserCenter/components/user-info/utils.d.ts +1 -1
- package/lib/UserCenter/components/user-info/utils.js +46 -44
- package/lib/UserCenter/libs/locales.d.ts +2 -0
- package/lib/UserCenter/libs/locales.js +4 -2
- package/package.json +5 -5
- package/src/UserCenter/components/nft-preview.tsx +84 -0
- package/src/UserCenter/components/nft.tsx +131 -10
- package/src/UserCenter/components/user-info/link-preview-input.tsx +8 -2
- package/src/UserCenter/components/user-info/utils.ts +3 -3
- package/src/UserCenter/libs/locales.ts +2 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface NftInfo {
|
|
2
|
+
address: string;
|
|
3
|
+
data: Record<string, any>;
|
|
4
|
+
display: Record<string, any>;
|
|
5
|
+
issuer: string;
|
|
6
|
+
}
|
|
7
|
+
export default function NftPreview({ visible, onClose, nft, }: {
|
|
8
|
+
visible: boolean;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
nft: NftInfo | null;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import n from "@mui/material/Modal";
|
|
3
|
+
import r from "@emotion/styled";
|
|
4
|
+
import a, { getNFTData as s } from "@arcblock/ux/lib/NFTDisplay";
|
|
5
|
+
function f({
|
|
6
|
+
visible: e,
|
|
7
|
+
onClose: o,
|
|
8
|
+
nft: i
|
|
9
|
+
}) {
|
|
10
|
+
return !e || !i ? null : /* @__PURE__ */ t(d, { children: /* @__PURE__ */ t(n, { open: e, onClose: o, children: /* @__PURE__ */ t(h, { onClick: o, children: /* @__PURE__ */ t(a, { data: s(i), address: i.address, inset: !0 }) }) }) });
|
|
11
|
+
}
|
|
12
|
+
const d = r.div`
|
|
13
|
+
position: relative;
|
|
14
|
+
width: 100%;
|
|
15
|
+
height: 100%;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
|
|
18
|
+
&:hover {
|
|
19
|
+
.mask {
|
|
20
|
+
opacity: 1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.mask {
|
|
25
|
+
position: absolute;
|
|
26
|
+
top: 0;
|
|
27
|
+
left: 0;
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
width: 100%;
|
|
32
|
+
height: 100%;
|
|
33
|
+
background: rgba(0, 0, 0, 0.6);
|
|
34
|
+
opacity: 0;
|
|
35
|
+
transition: opacity 0.2s;
|
|
36
|
+
}
|
|
37
|
+
`, h = r.div`
|
|
38
|
+
display: flex;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
align-items: center;
|
|
41
|
+
height: 100vh;
|
|
42
|
+
width: 100vw;
|
|
43
|
+
|
|
44
|
+
img,
|
|
45
|
+
object {
|
|
46
|
+
max-width: 90vw;
|
|
47
|
+
max-height: 75vh;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.nft-display--inset {
|
|
51
|
+
> .MuiBox-root,
|
|
52
|
+
.nft-display__loading {
|
|
53
|
+
width: 75vmin;
|
|
54
|
+
height: 75vmin;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
export {
|
|
59
|
+
f as default
|
|
60
|
+
};
|
|
@@ -1,35 +1,84 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { jsxs as l, jsx as o, Fragment as R } from "react/jsx-runtime";
|
|
2
|
+
import { useState as y } from "react";
|
|
3
|
+
import { Box as s, Skeleton as w, Typography as F, alpha as C, Stack as j, IconButton as f, Pagination as T } from "@mui/material";
|
|
4
|
+
import { useMemoizedFn as L, useReactive as _, useRequest as A, useCreation as D } from "ahooks";
|
|
5
|
+
import H from "axios";
|
|
6
|
+
import { Icon as h } from "@iconify/react";
|
|
7
|
+
import W, { getNFTData as O } from "@arcblock/ux/lib/NFTDisplay";
|
|
8
|
+
import U from "@arcblock/ux/lib/Empty";
|
|
9
|
+
import { WELLKNOWN_SERVICE_PATH_PREFIX as B } from "@abtnode/constant";
|
|
10
|
+
import { translate as M } from "@arcblock/ux/lib/Locale/util";
|
|
11
|
+
import { useLocaleContext as V } from "@arcblock/ux/lib/Locale/context";
|
|
12
|
+
import { joinURL as v } from "ufo";
|
|
13
|
+
import X from "@arcblock/ux/lib/SocialShare";
|
|
14
|
+
import { translations as $ } from "../libs/locales.js";
|
|
15
|
+
import q from "./nft-preview.js";
|
|
16
|
+
const J = (a) => ({
|
|
17
|
+
position: "absolute",
|
|
18
|
+
top: 0,
|
|
19
|
+
left: 0,
|
|
20
|
+
right: 0,
|
|
21
|
+
bottom: 0,
|
|
22
|
+
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
23
|
+
opacity: 0,
|
|
24
|
+
transition: "opacity 0.3s ease-in-out",
|
|
25
|
+
display: "flex",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
justifyContent: "center",
|
|
28
|
+
zIndex: 1,
|
|
29
|
+
"& .mask-item": {
|
|
30
|
+
backgroundColor: C(a.palette.background.paper, 0.9),
|
|
31
|
+
color: "text.primary",
|
|
32
|
+
"&:hover": {
|
|
33
|
+
backgroundColor: C(a.palette.background.paper, 1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}), P = "https://main.abtnetwork.io/explorer";
|
|
37
|
+
function ce({ user: a }) {
|
|
38
|
+
const { locale: N } = V(), u = L((t, e = {}) => M($, t, N, "en", e)), [n, g] = y({
|
|
39
|
+
visible: !1,
|
|
40
|
+
nft: null
|
|
41
|
+
}), [p, x] = y({
|
|
42
|
+
anchorEl: null,
|
|
43
|
+
props: null
|
|
44
|
+
}), S = (t) => {
|
|
45
|
+
const e = v(P, "assets", t);
|
|
46
|
+
window.open(e, "_blank");
|
|
47
|
+
}, z = (t, e) => {
|
|
48
|
+
let i = "";
|
|
49
|
+
typeof e.data?.value == "string" ? i = JSON.parse(e.data?.value)?.domain : i = e.data?.value?.domain, x({
|
|
50
|
+
anchorEl: t,
|
|
51
|
+
props: {
|
|
52
|
+
title: i ? `Hey, I just won an NFT at the ${i} event!` : "Hey, I just won an NFT!",
|
|
53
|
+
url: v(P, "assets", e.address)
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}, E = (t) => {
|
|
57
|
+
g({
|
|
58
|
+
visible: !0,
|
|
59
|
+
nft: t
|
|
60
|
+
});
|
|
61
|
+
}, r = _({
|
|
13
62
|
page: 1,
|
|
14
63
|
size: 20
|
|
15
|
-
}),
|
|
16
|
-
async (
|
|
64
|
+
}), k = A(
|
|
65
|
+
async (t = r) => (await H.get(`${B}/ocap/listAssets`, {
|
|
17
66
|
params: {
|
|
18
|
-
ownerAddress:
|
|
19
|
-
...
|
|
67
|
+
ownerAddress: a.did,
|
|
68
|
+
...t
|
|
20
69
|
}
|
|
21
70
|
})).data,
|
|
22
71
|
{
|
|
23
|
-
defaultParams: [
|
|
24
|
-
refreshDeps: [
|
|
72
|
+
defaultParams: [r],
|
|
73
|
+
refreshDeps: [a.did, r]
|
|
25
74
|
}
|
|
26
|
-
), { loading:
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
if (
|
|
30
|
-
const
|
|
31
|
-
return /* @__PURE__ */
|
|
32
|
-
|
|
75
|
+
), { loading: c, data: d } = k, m = d?.page ?? { cursor: 0, next: !1, total: 0 }, b = (t, e) => {
|
|
76
|
+
r.page = e, k.run(r);
|
|
77
|
+
}, I = D(() => {
|
|
78
|
+
if (c) {
|
|
79
|
+
const t = ["skeleton-1", "skeleton-2", "skeleton-3", "skeleton-4", "skeleton-5"].map((e) => /* @__PURE__ */ o(w, { variant: "rectangular", width: "15%", height: 166, sx: { borderRadius: 1, flexShrink: 0 } }, e));
|
|
80
|
+
return /* @__PURE__ */ l(
|
|
81
|
+
s,
|
|
33
82
|
{
|
|
34
83
|
sx: {
|
|
35
84
|
display: "flex",
|
|
@@ -37,9 +86,9 @@ function q({ user: l }) {
|
|
|
37
86
|
gap: 2
|
|
38
87
|
},
|
|
39
88
|
children: [
|
|
40
|
-
/* @__PURE__ */
|
|
41
|
-
/* @__PURE__ */
|
|
42
|
-
|
|
89
|
+
/* @__PURE__ */ o(w, { width: "20%" }),
|
|
90
|
+
/* @__PURE__ */ o(
|
|
91
|
+
s,
|
|
43
92
|
{
|
|
44
93
|
sx: {
|
|
45
94
|
display: "flex",
|
|
@@ -47,28 +96,28 @@ function q({ user: l }) {
|
|
|
47
96
|
gap: 2,
|
|
48
97
|
flexWrap: "nowrap"
|
|
49
98
|
},
|
|
50
|
-
children:
|
|
99
|
+
children: t
|
|
51
100
|
}
|
|
52
101
|
)
|
|
53
102
|
]
|
|
54
103
|
}
|
|
55
104
|
);
|
|
56
105
|
}
|
|
57
|
-
return /* @__PURE__ */
|
|
58
|
-
/* @__PURE__ */
|
|
59
|
-
|
|
106
|
+
return /* @__PURE__ */ l(R, { children: [
|
|
107
|
+
/* @__PURE__ */ o(
|
|
108
|
+
F,
|
|
60
109
|
{
|
|
61
110
|
sx: {
|
|
62
111
|
color: "grey.A700",
|
|
63
112
|
fontWeight: 600,
|
|
64
113
|
mb: 2.5
|
|
65
114
|
},
|
|
66
|
-
children:
|
|
115
|
+
children: u("common.nft")
|
|
67
116
|
}
|
|
68
117
|
),
|
|
69
|
-
|
|
70
|
-
/* @__PURE__ */
|
|
71
|
-
|
|
118
|
+
d?.assets?.length === 0 && !c && /* @__PURE__ */ o(s, { sx: { display: "flex", justifyContent: "center", alignItems: "center", width: "100%", height: "100%" }, children: /* @__PURE__ */ o(U, { children: u("common.noNFT") }) }),
|
|
119
|
+
/* @__PURE__ */ o(
|
|
120
|
+
s,
|
|
72
121
|
{
|
|
73
122
|
className: "nft-list-wrapper",
|
|
74
123
|
sx: {
|
|
@@ -82,50 +131,114 @@ function q({ user: l }) {
|
|
|
82
131
|
},
|
|
83
132
|
gap: 2.5
|
|
84
133
|
},
|
|
85
|
-
children:
|
|
86
|
-
|
|
134
|
+
children: d?.assets?.map((t) => /* @__PURE__ */ l(
|
|
135
|
+
s,
|
|
87
136
|
{
|
|
88
137
|
sx: {
|
|
89
138
|
flexShrink: 0,
|
|
90
139
|
width: { xs: 120, sm: 120, md: 120, lg: 166 },
|
|
91
|
-
height: { xs: 120, sm: 120, md: 120, lg: 166 }
|
|
140
|
+
height: { xs: 120, sm: 120, md: 120, lg: 166 },
|
|
141
|
+
position: "relative",
|
|
142
|
+
borderRadius: 1,
|
|
143
|
+
overflow: "hidden",
|
|
144
|
+
cursor: "pointer",
|
|
145
|
+
"&:hover .mask": {
|
|
146
|
+
opacity: 1
|
|
147
|
+
}
|
|
92
148
|
},
|
|
93
|
-
children:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
imageFilter:
|
|
101
|
-
|
|
102
|
-
|
|
149
|
+
children: [
|
|
150
|
+
/* @__PURE__ */ o(
|
|
151
|
+
W,
|
|
152
|
+
{
|
|
153
|
+
data: O(t),
|
|
154
|
+
address: t.address,
|
|
155
|
+
inset: !0,
|
|
156
|
+
imageFilter: {
|
|
157
|
+
imageFilter: "resize",
|
|
158
|
+
w: "500",
|
|
159
|
+
f: "webp"
|
|
160
|
+
}
|
|
103
161
|
}
|
|
104
|
-
|
|
105
|
-
|
|
162
|
+
),
|
|
163
|
+
/* @__PURE__ */ o(s, { className: "mask", sx: J, children: /* @__PURE__ */ l(j, { direction: "row", spacing: 1, children: [
|
|
164
|
+
/* @__PURE__ */ o(
|
|
165
|
+
f,
|
|
166
|
+
{
|
|
167
|
+
size: "small",
|
|
168
|
+
className: "mask-item",
|
|
169
|
+
onClick: (e) => {
|
|
170
|
+
e.stopPropagation(), S(t.address);
|
|
171
|
+
},
|
|
172
|
+
children: /* @__PURE__ */ o(h, { icon: "tabler:link", fontSize: 18 })
|
|
173
|
+
}
|
|
174
|
+
),
|
|
175
|
+
/* @__PURE__ */ o(
|
|
176
|
+
f,
|
|
177
|
+
{
|
|
178
|
+
size: "small",
|
|
179
|
+
onClick: (e) => {
|
|
180
|
+
e.stopPropagation(), z(e.currentTarget, t);
|
|
181
|
+
},
|
|
182
|
+
className: "mask-item",
|
|
183
|
+
children: /* @__PURE__ */ o(h, { icon: "tabler:share-2", fontSize: 18 })
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
/* @__PURE__ */ o(
|
|
187
|
+
f,
|
|
188
|
+
{
|
|
189
|
+
size: "small",
|
|
190
|
+
onClick: (e) => {
|
|
191
|
+
e.stopPropagation(), E(t);
|
|
192
|
+
},
|
|
193
|
+
className: "mask-item",
|
|
194
|
+
children: /* @__PURE__ */ o(h, { icon: "tabler:eye", fontSize: 18 })
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
] }) })
|
|
198
|
+
]
|
|
106
199
|
},
|
|
107
|
-
|
|
200
|
+
t.address
|
|
108
201
|
))
|
|
109
202
|
}
|
|
110
203
|
),
|
|
111
|
-
|
|
112
|
-
|
|
204
|
+
m.next || r.page > 1 ? /* @__PURE__ */ o(
|
|
205
|
+
T,
|
|
113
206
|
{
|
|
114
207
|
sx: {
|
|
115
208
|
display: "flex",
|
|
116
209
|
justifyContent: "center",
|
|
117
210
|
mt: 2
|
|
118
211
|
},
|
|
119
|
-
page:
|
|
120
|
-
onChange:
|
|
121
|
-
count: Math.ceil(
|
|
212
|
+
page: r.page,
|
|
213
|
+
onChange: b,
|
|
214
|
+
count: Math.ceil(m.total / r.size),
|
|
122
215
|
size: "small"
|
|
123
216
|
}
|
|
124
|
-
) : null
|
|
217
|
+
) : null,
|
|
218
|
+
/* @__PURE__ */ o(
|
|
219
|
+
q,
|
|
220
|
+
{
|
|
221
|
+
visible: n.visible && !!n.nft,
|
|
222
|
+
nft: n.nft,
|
|
223
|
+
onClose: () => {
|
|
224
|
+
g({ visible: !1, nft: null });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
),
|
|
228
|
+
/* @__PURE__ */ o(
|
|
229
|
+
X,
|
|
230
|
+
{
|
|
231
|
+
anchorEl: p.anchorEl,
|
|
232
|
+
onClose: () => {
|
|
233
|
+
x({ anchorEl: null, props: null });
|
|
234
|
+
},
|
|
235
|
+
sharedProps: p.props || { title: "", url: "" }
|
|
236
|
+
}
|
|
237
|
+
)
|
|
125
238
|
] });
|
|
126
|
-
}, [
|
|
127
|
-
return /* @__PURE__ */
|
|
239
|
+
}, [c, m, r.page, r.size, b, p, n]);
|
|
240
|
+
return /* @__PURE__ */ o(s, { sx: { border: "1px solid", borderColor: "divider", borderRadius: 1, p: 2, mb: 5 }, children: I });
|
|
128
241
|
}
|
|
129
242
|
export {
|
|
130
|
-
|
|
243
|
+
ce as default
|
|
131
244
|
};
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import { jsx as t, jsxs as
|
|
2
|
-
import { useState as
|
|
3
|
-
import { styled as
|
|
4
|
-
import { Remove as
|
|
5
|
-
import { translate as
|
|
6
|
-
import { useMemoizedFn as
|
|
7
|
-
import { useLocaleContext as
|
|
8
|
-
import
|
|
9
|
-
import { mergeSx as
|
|
10
|
-
import { withoutProtocol as
|
|
11
|
-
import { isValidUrl as
|
|
12
|
-
import { translations as
|
|
13
|
-
import { inputFieldStyle as
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { jsx as t, jsxs as p } from "react/jsx-runtime";
|
|
2
|
+
import { useState as L, useMemo as w } from "react";
|
|
3
|
+
import { styled as C, Box as d, Typography as x, IconButton as I, Button as k, useTheme as S, FormControl as D, TextField as F } from "@mui/material";
|
|
4
|
+
import { Remove as B, Add as T } from "@mui/icons-material";
|
|
5
|
+
import { translate as U } from "@arcblock/ux/lib/Locale/util";
|
|
6
|
+
import { useMemoizedFn as _ } from "ahooks";
|
|
7
|
+
import { useLocaleContext as z } from "@arcblock/ux/lib/Locale/context";
|
|
8
|
+
import E from "@arcblock/icons/lib/Link";
|
|
9
|
+
import { mergeSx as M } from "@arcblock/ux/lib/Util/style";
|
|
10
|
+
import { withoutProtocol as j } from "ufo";
|
|
11
|
+
import { isValidUrl as g } from "./utils.js";
|
|
12
|
+
import { translations as A } from "../../libs/locales.js";
|
|
13
|
+
import { inputFieldStyle as P, commonInputStyle as R } from "../editable-field.js";
|
|
14
|
+
const h = 10;
|
|
15
|
+
function W(e) {
|
|
16
|
+
return j(e);
|
|
16
17
|
}
|
|
17
|
-
function
|
|
18
|
+
function N({
|
|
18
19
|
value: e,
|
|
19
|
-
onChange:
|
|
20
|
-
errorMsg:
|
|
20
|
+
onChange: i,
|
|
21
|
+
errorMsg: l
|
|
21
22
|
}) {
|
|
22
23
|
return /* @__PURE__ */ t(D, { fullWidth: !0, children: /* @__PURE__ */ t(
|
|
23
24
|
F,
|
|
@@ -26,31 +27,31 @@ function A({
|
|
|
26
27
|
value: e,
|
|
27
28
|
onChange: (a) => {
|
|
28
29
|
const c = a.target.value;
|
|
29
|
-
|
|
30
|
+
i(c);
|
|
30
31
|
},
|
|
31
32
|
fullWidth: !0,
|
|
32
|
-
error: !!
|
|
33
|
-
helperText:
|
|
34
|
-
sx:
|
|
33
|
+
error: !!l,
|
|
34
|
+
helperText: l,
|
|
35
|
+
sx: M(P, l ? {} : R)
|
|
35
36
|
}
|
|
36
37
|
) });
|
|
37
38
|
}
|
|
38
|
-
function V({ links: e = [], onChange:
|
|
39
|
-
const { locale:
|
|
39
|
+
function V({ links: e = [], onChange: i }) {
|
|
40
|
+
const { locale: l } = z(), n = _((o, r = {}) => U(A, o, l, "en", r)), [a, c] = L([!1]), f = w(() => {
|
|
40
41
|
const o = e[e.length - 1];
|
|
41
|
-
return !
|
|
42
|
-
}, [a, e]),
|
|
43
|
-
(e.length <
|
|
44
|
-
},
|
|
45
|
-
const r = e.filter((
|
|
46
|
-
c(s),
|
|
47
|
-
},
|
|
42
|
+
return !g(o) || a.length > 0 && a[a.length - 1];
|
|
43
|
+
}, [a, e]), y = () => {
|
|
44
|
+
(e.length < h || !f) && i([...e, ""]);
|
|
45
|
+
}, b = (o) => {
|
|
46
|
+
const r = e.filter((m, u) => u !== o), s = a.filter((m, u) => u !== o);
|
|
47
|
+
c(s), i(r);
|
|
48
|
+
}, v = (o, r) => {
|
|
48
49
|
const s = [...e];
|
|
49
50
|
s[o] = r;
|
|
50
|
-
const
|
|
51
|
-
|
|
51
|
+
const m = [...a];
|
|
52
|
+
m[o] = !!(r && !g(r)), c(m), i(s);
|
|
52
53
|
};
|
|
53
|
-
return /* @__PURE__ */
|
|
54
|
+
return /* @__PURE__ */ p(
|
|
54
55
|
d,
|
|
55
56
|
{
|
|
56
57
|
sx: {
|
|
@@ -66,10 +67,10 @@ function V({ links: e = [], onChange: n }) {
|
|
|
66
67
|
alignItems: "center",
|
|
67
68
|
gap: 1
|
|
68
69
|
},
|
|
69
|
-
children: /* @__PURE__ */ t(
|
|
70
|
+
children: /* @__PURE__ */ t(x, { variant: "subtitle1", gutterBottom: !0, sx: { mb: 0, fontSize: "12px", color: "text.primary" }, children: n("profile.socialMedia") })
|
|
70
71
|
}
|
|
71
72
|
),
|
|
72
|
-
e.map((o, r) => /* @__PURE__ */
|
|
73
|
+
e.map((o, r) => /* @__PURE__ */ p(
|
|
73
74
|
d,
|
|
74
75
|
{
|
|
75
76
|
sx: {
|
|
@@ -79,25 +80,25 @@ function V({ links: e = [], onChange: n }) {
|
|
|
79
80
|
},
|
|
80
81
|
children: [
|
|
81
82
|
/* @__PURE__ */ t(
|
|
82
|
-
|
|
83
|
+
N,
|
|
83
84
|
{
|
|
84
85
|
value: o,
|
|
85
|
-
onChange: (s) =>
|
|
86
|
-
errorMsg: a[r] ?
|
|
86
|
+
onChange: (s) => v(r, s),
|
|
87
|
+
errorMsg: a[r] ? n("profile.invalidURL") : ""
|
|
87
88
|
}
|
|
88
89
|
),
|
|
89
|
-
/* @__PURE__ */ t(
|
|
90
|
+
/* @__PURE__ */ t(I, { onClick: () => b(r), children: /* @__PURE__ */ t(B, { sx: { color: "text.secondary" } }) })
|
|
90
91
|
]
|
|
91
92
|
},
|
|
92
93
|
r
|
|
93
94
|
)),
|
|
94
|
-
e.length <
|
|
95
|
-
|
|
95
|
+
e.length < h ? /* @__PURE__ */ p(
|
|
96
|
+
k,
|
|
96
97
|
{
|
|
97
98
|
fullWidth: !0,
|
|
98
99
|
variant: "outlined",
|
|
99
|
-
disabled:
|
|
100
|
-
onClick:
|
|
100
|
+
disabled: f,
|
|
101
|
+
onClick: y,
|
|
101
102
|
size: "small",
|
|
102
103
|
sx: {
|
|
103
104
|
height: "40px",
|
|
@@ -113,26 +114,26 @@ function V({ links: e = [], onChange: n }) {
|
|
|
113
114
|
}
|
|
114
115
|
},
|
|
115
116
|
children: [
|
|
116
|
-
/* @__PURE__ */ t(
|
|
117
|
+
/* @__PURE__ */ t(T, {}),
|
|
117
118
|
" ",
|
|
118
|
-
/* @__PURE__ */ t("span", { children:
|
|
119
|
+
/* @__PURE__ */ t("span", { children: n("profile.addLink") })
|
|
119
120
|
]
|
|
120
121
|
}
|
|
121
|
-
)
|
|
122
|
+
) : /* @__PURE__ */ t(x, { variant: "subtitle1", gutterBottom: !0, sx: { mb: 0, fontSize: "12px", color: "text.secondary" }, children: n("profile.maxLinkCount", { count: h }) })
|
|
122
123
|
]
|
|
123
124
|
}
|
|
124
125
|
);
|
|
125
126
|
}
|
|
126
|
-
function
|
|
127
|
-
const
|
|
128
|
-
return e ? /* @__PURE__ */ t(
|
|
127
|
+
function K({ link: e }) {
|
|
128
|
+
const l = S().palette.mode === "dark";
|
|
129
|
+
return e ? /* @__PURE__ */ t(E, { width: 20, height: 20, style: { filter: l ? "brightness(0) saturate(100%) invert(1)" : "none" } }) : null;
|
|
129
130
|
}
|
|
130
|
-
function
|
|
131
|
+
function ne({
|
|
131
132
|
editable: e = !1,
|
|
132
|
-
links:
|
|
133
|
-
onChange:
|
|
133
|
+
links: i = [],
|
|
134
|
+
onChange: l
|
|
134
135
|
}) {
|
|
135
|
-
return e ? /* @__PURE__ */ t(V, { links:
|
|
136
|
+
return e ? /* @__PURE__ */ t(V, { links: i, onChange: l }) : /* @__PURE__ */ t(
|
|
136
137
|
d,
|
|
137
138
|
{
|
|
138
139
|
sx: {
|
|
@@ -141,7 +142,7 @@ function oe({
|
|
|
141
142
|
flexDirection: "column",
|
|
142
143
|
gap: 2
|
|
143
144
|
},
|
|
144
|
-
children:
|
|
145
|
+
children: i.map((n) => /* @__PURE__ */ p(
|
|
145
146
|
d,
|
|
146
147
|
{
|
|
147
148
|
sx: {
|
|
@@ -152,16 +153,16 @@ function oe({
|
|
|
152
153
|
width: "100%"
|
|
153
154
|
},
|
|
154
155
|
children: [
|
|
155
|
-
/* @__PURE__ */ t(
|
|
156
|
-
/* @__PURE__ */ t(
|
|
156
|
+
/* @__PURE__ */ t(K, { link: n }),
|
|
157
|
+
/* @__PURE__ */ t(O, { children: /* @__PURE__ */ t(d, { component: "a", href: n, style: { textDecoration: "none" }, target: "_blank", rel: "noopener noreferrer", children: W(n) }) })
|
|
157
158
|
]
|
|
158
159
|
},
|
|
159
|
-
|
|
160
|
+
n
|
|
160
161
|
))
|
|
161
162
|
}
|
|
162
163
|
);
|
|
163
164
|
}
|
|
164
|
-
const
|
|
165
|
+
const O = C("span")`
|
|
165
166
|
flex: 1;
|
|
166
167
|
white-space: nowrap;
|
|
167
168
|
overflow: hidden;
|
|
@@ -180,5 +181,5 @@ const q = L("span")`
|
|
|
180
181
|
}
|
|
181
182
|
`;
|
|
182
183
|
export {
|
|
183
|
-
|
|
184
|
+
ne as LinkPreviewInput
|
|
184
185
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import g from "is-url";
|
|
2
|
+
import { withHttps as A } from "ufo";
|
|
1
3
|
import n from "dayjs";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { DurationEnum as
|
|
5
|
-
n.extend(
|
|
6
|
-
n.extend(
|
|
7
|
-
const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1,
|
|
4
|
+
import h from "dayjs/plugin/timezone";
|
|
5
|
+
import k from "dayjs/plugin/utc";
|
|
6
|
+
import { DurationEnum as i } from "../../../@types/index.js";
|
|
7
|
+
n.extend(k);
|
|
8
|
+
n.extend(h);
|
|
9
|
+
const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, v = n.tz.guess(), b = [
|
|
8
10
|
"America/New_York",
|
|
9
11
|
"America/Chicago",
|
|
10
12
|
"America/Denver",
|
|
@@ -26,7 +28,7 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, M = n.tz.guess(), A =
|
|
|
26
28
|
"America/Mexico_City",
|
|
27
29
|
"Africa/Cairo",
|
|
28
30
|
"UTC"
|
|
29
|
-
],
|
|
31
|
+
], C = () => {
|
|
30
32
|
if (typeof Intl < "u" && Intl.supportedValuesOf)
|
|
31
33
|
try {
|
|
32
34
|
return Intl.supportedValuesOf("timeZone");
|
|
@@ -36,58 +38,58 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, M = n.tz.guess(), A =
|
|
|
36
38
|
if (typeof Intl < "u" && Intl.DateTimeFormat)
|
|
37
39
|
try {
|
|
38
40
|
if (new Intl.DateTimeFormat("en", { timeZone: "UTC" }).resolvedOptions().timeZone)
|
|
39
|
-
return
|
|
41
|
+
return b;
|
|
40
42
|
} catch {
|
|
41
43
|
console.warn("Intl.DateTimeFormat timezone support limited");
|
|
42
44
|
}
|
|
43
|
-
return
|
|
44
|
-
},
|
|
45
|
+
return b;
|
|
46
|
+
}, w = () => C().map((e) => {
|
|
45
47
|
try {
|
|
46
|
-
const
|
|
47
|
-
return { label: `GMT${a >= 0 ? "+" : ""}${a}:${
|
|
48
|
+
const o = n.tz(n(), e).utcOffset() / 60, a = Math.floor(o), s = o % 1 * 60;
|
|
49
|
+
return { label: `GMT${a >= 0 ? "+" : ""}${a}:${s === 30 ? "30" : "00"}`, value: e };
|
|
48
50
|
} catch {
|
|
49
51
|
return console.warn(`Timezone ${e} not supported, skipping`), null;
|
|
50
52
|
}
|
|
51
|
-
}).filter((e) => e !== null).sort((e,
|
|
52
|
-
const [a,
|
|
53
|
-
return c * 60 +
|
|
53
|
+
}).filter((e) => e !== null).sort((e, o) => {
|
|
54
|
+
const [a, s] = e.label.replace("GMT", "").split(":").map(Number), [c, y] = o.label.replace("GMT", "").split(":").map(Number), T = a * 60 + s;
|
|
55
|
+
return c * 60 + y - T;
|
|
54
56
|
}).map((e) => ({
|
|
55
57
|
label: `(${e.label}) ${e.value}`,
|
|
56
58
|
value: e.value
|
|
57
|
-
})),
|
|
58
|
-
let r =
|
|
59
|
+
})), z = (t) => g(A(t)), U = (t) => {
|
|
60
|
+
let r = t?.dateRange?.map((o) => n(o)) ?? [];
|
|
59
61
|
const e = n();
|
|
60
|
-
switch (
|
|
61
|
-
case
|
|
62
|
+
switch (t?.duration) {
|
|
63
|
+
case i.ThirtyMinutes:
|
|
62
64
|
r = [e, e.add(30, "minutes")];
|
|
63
65
|
break;
|
|
64
|
-
case
|
|
66
|
+
case i.OneHour:
|
|
65
67
|
r = [e, e.add(1, "hour")];
|
|
66
68
|
break;
|
|
67
|
-
case
|
|
69
|
+
case i.FourHours:
|
|
68
70
|
r = [e, e.add(4, "hours")];
|
|
69
71
|
break;
|
|
70
|
-
case
|
|
72
|
+
case i.Today:
|
|
71
73
|
r = [e, e.endOf("day")];
|
|
72
74
|
break;
|
|
73
|
-
case
|
|
75
|
+
case i.ThisWeek:
|
|
74
76
|
r = [e, e.endOf("week")];
|
|
75
77
|
break;
|
|
76
|
-
case
|
|
78
|
+
case i.NoClear:
|
|
77
79
|
r = [e, e];
|
|
78
80
|
break;
|
|
79
81
|
}
|
|
80
|
-
return r.map((
|
|
81
|
-
},
|
|
82
|
+
return r.map((o) => o.toDate());
|
|
83
|
+
}, B = (t) => {
|
|
82
84
|
const r = n();
|
|
83
|
-
return r.isAfter(n(
|
|
84
|
-
},
|
|
85
|
-
const { duration: r, dateRange: e } =
|
|
86
|
-
return !r || !e ? !1 : r ===
|
|
87
|
-
},
|
|
88
|
-
const r = n(),
|
|
89
|
-
return
|
|
90
|
-
},
|
|
85
|
+
return r.isAfter(n(t[0])) && r.isBefore(n(t[1]));
|
|
86
|
+
}, D = (t) => {
|
|
87
|
+
const { duration: r, dateRange: e } = t ?? {};
|
|
88
|
+
return !r || !e ? !1 : r === i.NoClear || n(e?.[0]).isSame(n(e?.[1]));
|
|
89
|
+
}, R = (t) => {
|
|
90
|
+
const r = n(), o = n(t).diff(r, "seconds"), a = (s) => s * 1e3;
|
|
91
|
+
return o >= u ? a(u) : o >= l ? a(l) : o >= m ? a(m) : o >= d ? a(d) : o >= f ? a(f) : o >= p ? a(p) : 0;
|
|
92
|
+
}, x = {
|
|
91
93
|
color: "text.primary",
|
|
92
94
|
borderColor: "grey.100",
|
|
93
95
|
backgroundColor: "background.default",
|
|
@@ -97,7 +99,7 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, M = n.tz.guess(), A =
|
|
|
97
99
|
},
|
|
98
100
|
py: 0.5,
|
|
99
101
|
borderRadius: 1
|
|
100
|
-
},
|
|
102
|
+
}, $ = {
|
|
101
103
|
color: "primary.contrastText",
|
|
102
104
|
borderColor: "primary.main",
|
|
103
105
|
backgroundColor: "primary.main",
|
|
@@ -109,13 +111,13 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, M = n.tz.guess(), A =
|
|
|
109
111
|
borderRadius: 1
|
|
110
112
|
};
|
|
111
113
|
export {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
v as currentTimezone,
|
|
115
|
+
x as defaultButtonStyle,
|
|
116
|
+
U as getStatusDuration,
|
|
117
|
+
R as getTimeRemaining,
|
|
118
|
+
w as getTimezones,
|
|
119
|
+
D as isNotClear,
|
|
120
|
+
z as isValidUrl,
|
|
121
|
+
B as isWithinTimeRange,
|
|
122
|
+
$ as primaryButtonStyle
|
|
121
123
|
};
|
|
@@ -158,6 +158,7 @@ export declare const translations: {
|
|
|
158
158
|
postalCode: string;
|
|
159
159
|
invalidPostalCode: string;
|
|
160
160
|
};
|
|
161
|
+
maxLinkCount: string;
|
|
161
162
|
};
|
|
162
163
|
destroyMyself: {
|
|
163
164
|
title: string;
|
|
@@ -330,6 +331,7 @@ export declare const translations: {
|
|
|
330
331
|
postalCode: string;
|
|
331
332
|
invalidPostalCode: string;
|
|
332
333
|
};
|
|
334
|
+
maxLinkCount: string;
|
|
333
335
|
};
|
|
334
336
|
destroyMyself: {
|
|
335
337
|
title: string;
|
|
@@ -157,7 +157,8 @@ const e = {
|
|
|
157
157
|
detailedAddress: "详细地址",
|
|
158
158
|
postalCode: "邮政编码",
|
|
159
159
|
invalidPostalCode: "邮政编码格式不正确"
|
|
160
|
-
}
|
|
160
|
+
},
|
|
161
|
+
maxLinkCount: "最多可添加 {count} 个社交链接"
|
|
161
162
|
},
|
|
162
163
|
destroyMyself: {
|
|
163
164
|
title: "删除账户",
|
|
@@ -329,7 +330,8 @@ const e = {
|
|
|
329
330
|
detailedAddress: "Detailed Address",
|
|
330
331
|
postalCode: "Postal Code",
|
|
331
332
|
invalidPostalCode: "Postal code is invalid"
|
|
332
|
-
}
|
|
333
|
+
},
|
|
334
|
+
maxLinkCount: "Up to {count} social links can be added"
|
|
333
335
|
},
|
|
334
336
|
destroyMyself: {
|
|
335
337
|
title: "Delete Account",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/ui-react",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.22",
|
|
4
4
|
"description": "Some useful front-end web components that can be used in Blocklets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@abtnode/constant": "^1.16.45",
|
|
37
37
|
"@abtnode/util": "^1.16.45",
|
|
38
|
-
"@arcblock/bridge": "3.0.
|
|
39
|
-
"@arcblock/icons": "3.0.
|
|
40
|
-
"@arcblock/react-hooks": "3.0.
|
|
38
|
+
"@arcblock/bridge": "3.0.22",
|
|
39
|
+
"@arcblock/icons": "3.0.22",
|
|
40
|
+
"@arcblock/react-hooks": "3.0.22",
|
|
41
41
|
"@arcblock/ws": "^1.20.15",
|
|
42
42
|
"@blocklet/constant": "^1.16.45",
|
|
43
43
|
"@blocklet/did-space-react": "^1.1.1",
|
|
@@ -90,5 +90,5 @@
|
|
|
90
90
|
"jest": "^29.7.0",
|
|
91
91
|
"unbuild": "^2.0.0"
|
|
92
92
|
},
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "21018768a5b825c02861281925afb54efdf0aa4c"
|
|
94
94
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import Modal from '@mui/material/Modal';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
import NFTDisplay, { getNFTData } from '@arcblock/ux/lib/NFTDisplay';
|
|
4
|
+
|
|
5
|
+
export interface NftInfo {
|
|
6
|
+
address: string;
|
|
7
|
+
data: Record<string, any>;
|
|
8
|
+
display: Record<string, any>;
|
|
9
|
+
issuer: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function NftPreview({
|
|
13
|
+
visible,
|
|
14
|
+
onClose,
|
|
15
|
+
nft,
|
|
16
|
+
}: {
|
|
17
|
+
visible: boolean;
|
|
18
|
+
onClose: () => void;
|
|
19
|
+
nft: NftInfo | null;
|
|
20
|
+
}) {
|
|
21
|
+
if (!visible || !nft) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<NftPreviewRoot>
|
|
27
|
+
{/* Preview Modal */}
|
|
28
|
+
<Modal open={visible} onClose={onClose}>
|
|
29
|
+
<ModalRoot onClick={onClose}>
|
|
30
|
+
<NFTDisplay data={getNFTData(nft)} address={nft.address} inset />
|
|
31
|
+
</ModalRoot>
|
|
32
|
+
</Modal>
|
|
33
|
+
</NftPreviewRoot>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const NftPreviewRoot = styled.div`
|
|
38
|
+
position: relative;
|
|
39
|
+
width: 100%;
|
|
40
|
+
height: 100%;
|
|
41
|
+
cursor: pointer;
|
|
42
|
+
|
|
43
|
+
&:hover {
|
|
44
|
+
.mask {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.mask {
|
|
50
|
+
position: absolute;
|
|
51
|
+
top: 0;
|
|
52
|
+
left: 0;
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
width: 100%;
|
|
57
|
+
height: 100%;
|
|
58
|
+
background: rgba(0, 0, 0, 0.6);
|
|
59
|
+
opacity: 0;
|
|
60
|
+
transition: opacity 0.2s;
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
const ModalRoot = styled.div`
|
|
65
|
+
display: flex;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
align-items: center;
|
|
68
|
+
height: 100vh;
|
|
69
|
+
width: 100vw;
|
|
70
|
+
|
|
71
|
+
img,
|
|
72
|
+
object {
|
|
73
|
+
max-width: 90vw;
|
|
74
|
+
max-height: 75vh;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.nft-display--inset {
|
|
78
|
+
> .MuiBox-root,
|
|
79
|
+
.nft-display__loading {
|
|
80
|
+
width: 75vmin;
|
|
81
|
+
height: 75vmin;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
@@ -1,21 +1,49 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Box, Pagination, Skeleton, Typography, IconButton, Stack, alpha } from '@mui/material';
|
|
2
3
|
import { useCreation, useMemoizedFn, useReactive, useRequest } from 'ahooks';
|
|
3
4
|
import axios from 'axios';
|
|
4
|
-
import
|
|
5
|
+
import { Icon } from '@iconify/react';
|
|
6
|
+
import NFTDisplay, { getNFTData } from '@arcblock/ux/lib/NFTDisplay';
|
|
5
7
|
import Empty from '@arcblock/ux/lib/Empty';
|
|
6
8
|
import { WELLKNOWN_SERVICE_PATH_PREFIX } from '@abtnode/constant';
|
|
7
9
|
import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
8
10
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
9
|
-
import {
|
|
11
|
+
import { joinURL } from 'ufo';
|
|
12
|
+
import SocialShare from '@arcblock/ux/lib/SocialShare';
|
|
10
13
|
import { User } from '../../@types';
|
|
14
|
+
import { translations } from '../libs/locales';
|
|
15
|
+
import NftPreview, { NftInfo } from './nft-preview';
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
issuer: string;
|
|
17
|
+
// 直接定义 SharedProps 类型
|
|
18
|
+
interface SharedProps {
|
|
19
|
+
title: string;
|
|
20
|
+
url: string;
|
|
17
21
|
}
|
|
18
22
|
|
|
23
|
+
const maskStyle = (theme: any) => ({
|
|
24
|
+
position: 'absolute',
|
|
25
|
+
top: 0,
|
|
26
|
+
left: 0,
|
|
27
|
+
right: 0,
|
|
28
|
+
bottom: 0,
|
|
29
|
+
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
30
|
+
opacity: 0,
|
|
31
|
+
transition: 'opacity 0.3s ease-in-out',
|
|
32
|
+
display: 'flex',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
zIndex: 1,
|
|
36
|
+
'& .mask-item': {
|
|
37
|
+
backgroundColor: alpha(theme.palette.background.paper, 0.9),
|
|
38
|
+
color: 'text.primary',
|
|
39
|
+
'&:hover': {
|
|
40
|
+
backgroundColor: alpha(theme.palette.background.paper, 1),
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const CHAIN_EXPLORER_URL = 'https://main.abtnetwork.io/explorer';
|
|
46
|
+
|
|
19
47
|
interface ResponseData {
|
|
20
48
|
assets: NftInfo[];
|
|
21
49
|
code: string;
|
|
@@ -32,6 +60,45 @@ export default function Nft({ user }: { user: User }) {
|
|
|
32
60
|
const t = useMemoizedFn((key, data = {}) => {
|
|
33
61
|
return translate(translations, key, locale, 'en', data);
|
|
34
62
|
});
|
|
63
|
+
|
|
64
|
+
const [previewProps, setPreviewProps] = useState<{ visible: boolean; nft: NftInfo | null }>({
|
|
65
|
+
visible: false,
|
|
66
|
+
nft: null,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const [shareProps, setShareProps] = useState<{ anchorEl: HTMLElement | null; props: SharedProps | null }>({
|
|
70
|
+
anchorEl: null,
|
|
71
|
+
props: null,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const handleLinkClick = (nftAddress: string) => {
|
|
75
|
+
const targetURL = joinURL(CHAIN_EXPLORER_URL, 'assets', nftAddress);
|
|
76
|
+
window.open(targetURL, '_blank');
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const handleShareClick = (element: HTMLElement, nft: NftInfo) => {
|
|
80
|
+
let domain = '';
|
|
81
|
+
if (typeof nft.data?.value === 'string') {
|
|
82
|
+
domain = JSON.parse(nft.data?.value)?.domain;
|
|
83
|
+
} else {
|
|
84
|
+
domain = nft.data?.value?.domain;
|
|
85
|
+
}
|
|
86
|
+
setShareProps({
|
|
87
|
+
anchorEl: element,
|
|
88
|
+
props: {
|
|
89
|
+
title: domain ? `Hey, I just won an NFT at the ${domain} event!` : 'Hey, I just won an NFT!',
|
|
90
|
+
url: joinURL(CHAIN_EXPLORER_URL, 'assets', nft.address),
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const handleViewClick = (nft: NftInfo) => {
|
|
96
|
+
setPreviewProps({
|
|
97
|
+
visible: true,
|
|
98
|
+
nft,
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
35
102
|
const paging = useReactive<PaginationProps>({
|
|
36
103
|
page: 1,
|
|
37
104
|
size: 20,
|
|
@@ -123,9 +190,16 @@ export default function Nft({ user }: { user: User }) {
|
|
|
123
190
|
flexShrink: 0,
|
|
124
191
|
width: { xs: 120, sm: 120, md: 120, lg: 166 },
|
|
125
192
|
height: { xs: 120, sm: 120, md: 120, lg: 166 },
|
|
193
|
+
position: 'relative',
|
|
194
|
+
borderRadius: 1,
|
|
195
|
+
overflow: 'hidden',
|
|
196
|
+
cursor: 'pointer',
|
|
197
|
+
'&:hover .mask': {
|
|
198
|
+
opacity: 1,
|
|
199
|
+
},
|
|
126
200
|
}}>
|
|
127
201
|
<NFTDisplay
|
|
128
|
-
data={item
|
|
202
|
+
data={getNFTData(item)}
|
|
129
203
|
address={item.address}
|
|
130
204
|
inset
|
|
131
205
|
imageFilter={{
|
|
@@ -134,6 +208,37 @@ export default function Nft({ user }: { user: User }) {
|
|
|
134
208
|
f: 'webp',
|
|
135
209
|
}}
|
|
136
210
|
/>
|
|
211
|
+
<Box className="mask" sx={maskStyle}>
|
|
212
|
+
<Stack direction="row" spacing={1}>
|
|
213
|
+
<IconButton
|
|
214
|
+
size="small"
|
|
215
|
+
className="mask-item"
|
|
216
|
+
onClick={(e) => {
|
|
217
|
+
e.stopPropagation();
|
|
218
|
+
handleLinkClick(item.address);
|
|
219
|
+
}}>
|
|
220
|
+
<Icon icon="tabler:link" fontSize={18} />
|
|
221
|
+
</IconButton>
|
|
222
|
+
<IconButton
|
|
223
|
+
size="small"
|
|
224
|
+
onClick={(e) => {
|
|
225
|
+
e.stopPropagation();
|
|
226
|
+
handleShareClick(e.currentTarget, item);
|
|
227
|
+
}}
|
|
228
|
+
className="mask-item">
|
|
229
|
+
<Icon icon="tabler:share-2" fontSize={18} />
|
|
230
|
+
</IconButton>
|
|
231
|
+
<IconButton
|
|
232
|
+
size="small"
|
|
233
|
+
onClick={(e) => {
|
|
234
|
+
e.stopPropagation();
|
|
235
|
+
handleViewClick(item);
|
|
236
|
+
}}
|
|
237
|
+
className="mask-item">
|
|
238
|
+
<Icon icon="tabler:eye" fontSize={18} />
|
|
239
|
+
</IconButton>
|
|
240
|
+
</Stack>
|
|
241
|
+
</Box>
|
|
137
242
|
</Box>
|
|
138
243
|
))}
|
|
139
244
|
</Box>
|
|
@@ -150,9 +255,25 @@ export default function Nft({ user }: { user: User }) {
|
|
|
150
255
|
size="small"
|
|
151
256
|
/>
|
|
152
257
|
) : null}
|
|
258
|
+
|
|
259
|
+
<NftPreview
|
|
260
|
+
visible={previewProps.visible && !!previewProps.nft}
|
|
261
|
+
nft={previewProps.nft}
|
|
262
|
+
onClose={() => {
|
|
263
|
+
setPreviewProps({ visible: false, nft: null });
|
|
264
|
+
}}
|
|
265
|
+
/>
|
|
266
|
+
|
|
267
|
+
<SocialShare
|
|
268
|
+
anchorEl={shareProps.anchorEl}
|
|
269
|
+
onClose={() => {
|
|
270
|
+
setShareProps({ anchorEl: null, props: null });
|
|
271
|
+
}}
|
|
272
|
+
sharedProps={shareProps.props || { title: '', url: '' }}
|
|
273
|
+
/>
|
|
153
274
|
</>
|
|
154
275
|
);
|
|
155
|
-
}, [loading, dataPage, paging.page, paging.size, handlePageChange]);
|
|
276
|
+
}, [loading, dataPage, paging.page, paging.size, handlePageChange, shareProps, previewProps]);
|
|
156
277
|
|
|
157
278
|
return <Box sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 1, p: 2, mb: 5 }}>{content}</Box>;
|
|
158
279
|
}
|
|
@@ -11,6 +11,8 @@ import { isValidUrl } from './utils';
|
|
|
11
11
|
import { translations } from '../../libs/locales';
|
|
12
12
|
import { commonInputStyle, inputFieldStyle } from '../editable-field';
|
|
13
13
|
|
|
14
|
+
const MAX_LINK_COUNT = 10;
|
|
15
|
+
|
|
14
16
|
/**
|
|
15
17
|
* 格式化链接显示
|
|
16
18
|
* 对于 http/https 协议只显示域名,其他协议显示完整链接
|
|
@@ -67,7 +69,7 @@ function DynamicLinkForm({ links = [], onChange }: { links?: string[]; onChange:
|
|
|
67
69
|
}, [errors, links]);
|
|
68
70
|
|
|
69
71
|
const handleAddLink = () => {
|
|
70
|
-
if (links.length <
|
|
72
|
+
if (links.length < MAX_LINK_COUNT || !isLastError) {
|
|
71
73
|
onChange([...links, '']);
|
|
72
74
|
}
|
|
73
75
|
};
|
|
@@ -127,7 +129,7 @@ function DynamicLinkForm({ links = [], onChange }: { links?: string[]; onChange:
|
|
|
127
129
|
</IconButton>
|
|
128
130
|
</Box>
|
|
129
131
|
))}
|
|
130
|
-
{links.length <
|
|
132
|
+
{links.length < MAX_LINK_COUNT ? (
|
|
131
133
|
<Button
|
|
132
134
|
fullWidth
|
|
133
135
|
variant="outlined"
|
|
@@ -149,6 +151,10 @@ function DynamicLinkForm({ links = [], onChange }: { links?: string[]; onChange:
|
|
|
149
151
|
}}>
|
|
150
152
|
<AddIcon /> <span>{t('profile.addLink')}</span>
|
|
151
153
|
</Button>
|
|
154
|
+
) : (
|
|
155
|
+
<Typography variant="subtitle1" gutterBottom sx={{ mb: 0, fontSize: '12px', color: 'text.secondary' }}>
|
|
156
|
+
{t('profile.maxLinkCount', { count: MAX_LINK_COUNT })}
|
|
157
|
+
</Typography>
|
|
152
158
|
)}
|
|
153
159
|
</Box>
|
|
154
160
|
);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import isUrl from 'is-url';
|
|
2
|
+
import { withHttps } from 'ufo';
|
|
1
3
|
import dayjs from 'dayjs';
|
|
2
4
|
import timezone from 'dayjs/plugin/timezone';
|
|
3
5
|
import utc from 'dayjs/plugin/utc';
|
|
@@ -104,9 +106,7 @@ export const getTimezones = () => {
|
|
|
104
106
|
};
|
|
105
107
|
|
|
106
108
|
export const isValidUrl = (url: string) => {
|
|
107
|
-
|
|
108
|
-
/^(https?:\/\/)?((([a-zA-Z\d]([a-zA-Z\d-]*[a-zA-Z\d])*)\.)+[a-zA-Z]{2,}|((\d{1,3}\.){3}\d{1,3}))(:\d+)?(\/[-a-zA-Z\d%_.~+]*)*(\?[;&a-zA-Z\d%_.~+=-]*)?(#[a-zA-Z\d_]*)?$/;
|
|
109
|
-
return urlPattern.test(url);
|
|
109
|
+
return isUrl(withHttps(url)); // 补充协议后在进行验证是否是合法的url
|
|
110
110
|
};
|
|
111
111
|
|
|
112
112
|
/**
|
|
@@ -160,6 +160,7 @@ export const translations = {
|
|
|
160
160
|
postalCode: '邮政编码',
|
|
161
161
|
invalidPostalCode: '邮政编码格式不正确',
|
|
162
162
|
},
|
|
163
|
+
maxLinkCount: '最多可添加 {count} 个社交链接',
|
|
163
164
|
},
|
|
164
165
|
destroyMyself: {
|
|
165
166
|
title: '删除账户',
|
|
@@ -335,6 +336,7 @@ export const translations = {
|
|
|
335
336
|
postalCode: 'Postal Code',
|
|
336
337
|
invalidPostalCode: 'Postal code is invalid',
|
|
337
338
|
},
|
|
339
|
+
maxLinkCount: 'Up to {count} social links can be added',
|
|
338
340
|
},
|
|
339
341
|
destroyMyself: {
|
|
340
342
|
title: 'Delete Account',
|