@arcblock/ux 3.0.33 → 3.0.35

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.
@@ -1,17 +1,17 @@
1
1
  import { jsx as a } from "react/jsx-runtime";
2
- import { Box as l, Avatar as f } from "@mui/material";
3
- import p from "../Avatar/index.js";
4
- import { createNameOnlyAvatar as u } from "./utils.js";
5
- const N = (r, t = 48, n = void 0, e = void 0, c = !1) => {
6
- const o = (i) => {
2
+ import { Box as o, Avatar as f } from "@mui/material";
3
+ import u from "../Avatar/index.js";
4
+ import { createNameOnlyAvatar as x } from "./utils.js";
5
+ const N = (r, t = 48, c = void 0, e = void 0, l = !1) => {
6
+ const n = (i) => {
7
7
  e?.(r, i);
8
8
  };
9
9
  if (!r.avatar) {
10
- const i = u(r), { className: s, style: d, alt: m } = n || {};
10
+ const i = x(r), { className: s, style: d, alt: m } = c || {};
11
11
  return /* @__PURE__ */ a(
12
12
  f,
13
13
  {
14
- onClick: o,
14
+ onClick: n,
15
15
  className: s,
16
16
  style: d,
17
17
  alt: m,
@@ -19,7 +19,7 @@ const N = (r, t = 48, n = void 0, e = void 0, c = !1) => {
19
19
  width: t,
20
20
  height: t,
21
21
  fontSize: t * 0.4,
22
- cursor: c || e ? "pointer" : "default"
22
+ cursor: l || e ? "pointer" : "default"
23
23
  },
24
24
  variant: "circular",
25
25
  children: i
@@ -27,30 +27,31 @@ const N = (r, t = 48, n = void 0, e = void 0, c = !1) => {
27
27
  );
28
28
  }
29
29
  return /* @__PURE__ */ a(
30
- l,
30
+ o,
31
31
  {
32
32
  className: "user-card__avatar",
33
33
  sx: {
34
34
  display: "flex"
35
35
  },
36
36
  children: /* @__PURE__ */ a(
37
- p,
37
+ u,
38
38
  {
39
39
  size: t,
40
40
  did: r.did,
41
41
  variant: "circle",
42
+ useProxyFallback: !0,
42
43
  style: {
43
- cursor: c || e ? "pointer" : "default"
44
+ cursor: l || e ? "pointer" : "default"
44
45
  },
45
- onClick: o,
46
+ onClick: n,
46
47
  src: r.avatar,
47
48
  alt: r.fullName || "",
48
- ...n || {}
49
+ ...c || {}
49
50
  }
50
51
  )
51
52
  }
52
53
  );
53
- }, _ = (r, t = 120) => r ? /* @__PURE__ */ a(l, { sx: { maxWidth: t }, className: "user-card__top-right-content", children: r() }) : null;
54
+ }, _ = (r, t = 120) => r ? /* @__PURE__ */ a(o, { sx: { maxWidth: t }, className: "user-card__top-right-content", children: r() }) : null;
54
55
  export {
55
56
  N as renderAvatar,
56
57
  _ as renderTopRight
@@ -1,34 +1,44 @@
1
1
  import { jsx as t } from "react/jsx-runtime";
2
- import { useRef as c, useState as h, useEffect as C } from "react";
3
- import { CardType as i } from "./types.js";
4
- import v from "./Cards/avatar-only.js";
5
- import f from "./Cards/index.js";
6
- import y from "./Container/dialog.js";
7
- import A from "./Container/card.js";
8
- import D from "../Avatar/index.js";
9
- import { isUserDid as P, getUserByDid as S } from "./utils.js";
2
+ import { useRef as v, useState as C, useEffect as y, useMemo as P } from "react";
3
+ import { CardType as o } from "./types.js";
4
+ import A from "./Cards/avatar-only.js";
5
+ import m from "./Cards/index.js";
6
+ import D from "./Container/dialog.js";
7
+ import S from "./Container/card.js";
8
+ import w from "../Avatar/index.js";
9
+ import { isUserDid as x, getUserByDid as U } from "./utils.js";
10
10
  function L(e) {
11
11
  if (!e) return null;
12
12
  let r = "";
13
13
  return e.fullName ? r = e.fullName.charAt(0).toUpperCase() : e.email ? r = e.email.split("@")[0].charAt(0).toUpperCase() : r = e.did ? e.did.charAt(0).toUpperCase() : "?", r;
14
14
  }
15
- function g(e) {
16
- const { cardType: r = i.Detailed, showHoverCard: d } = e, n = d !== void 0 ? d : r === i.AvatarOnly, m = c(null), [a, o] = h(() => e.user || null);
17
- if (C(() => {
18
- let u = !0;
19
- return e.user ? o(e.user) : e.did && P(e.did) && !e.user && S(e.did).then((s) => {
20
- u && o(s || { fullName: "Anonymous", did: e.did, avatar: "" });
15
+ function B(e) {
16
+ const { cardType: r = o.Detailed, showHoverCard: l } = e, u = l !== void 0 ? l : r === o.AvatarOnly, c = v(null), [i, f] = C(() => e.user || null);
17
+ y(() => {
18
+ let a = !0;
19
+ return e.user ? f(e.user) : e.did && x(e.did) && !e.user && U(e.did).then((d) => {
20
+ a && f(d || { fullName: "Anonymous", did: e.did, avatar: "" });
21
21
  }), () => {
22
- u = !1;
22
+ a = !1;
23
23
  };
24
- }, [e.did, e.user]), !a)
25
- return /* @__PURE__ */ t(D, { did: e.did, size: e.avatarSize, ...e.avatarProps });
26
- const l = () => /* @__PURE__ */ t(y, { sx: e.popupSx, children: /* @__PURE__ */ t(
27
- f,
24
+ }, [e.did, e.user]);
25
+ const n = P(() => {
26
+ if (!i)
27
+ return null;
28
+ const { avatar: a = "", ...d } = i, h = a.split("?")[1];
29
+ return a && !h ? {
30
+ ...d,
31
+ avatar: `${a}?imageFilter=resize&w=48&h=48`
32
+ } : i;
33
+ }, [i]);
34
+ if (!n)
35
+ return /* @__PURE__ */ t(w, { did: e.did, size: e.avatarSize, useProxyFallback: !0, ...e.avatarProps });
36
+ const s = () => /* @__PURE__ */ t(D, { sx: e.popupSx, children: /* @__PURE__ */ t(
37
+ m,
28
38
  {
29
39
  ...e,
30
40
  shouldShowHoverCard: !1,
31
- user: a,
41
+ user: n,
32
42
  avatarProps: e.popupAvatarProps,
33
43
  shortenLabelProps: e.popupShortenLabelProps || e.shortenLabelProps,
34
44
  renderFields: e.popupRenderFields,
@@ -38,25 +48,25 @@ function g(e) {
38
48
  showDid: e.popupShowDid || e.showDid
39
49
  }
40
50
  ) });
41
- return r === i.AvatarOnly ? /* @__PURE__ */ t(
42
- v,
51
+ return r === o.AvatarOnly ? /* @__PURE__ */ t(
52
+ A,
43
53
  {
44
54
  ...e,
45
- shouldShowHoverCard: n,
46
- renderCardContent: l,
47
- user: a
55
+ shouldShowHoverCard: u,
56
+ renderCardContent: s,
57
+ user: n
48
58
  }
49
- ) : /* @__PURE__ */ t(A, { containerRef: m, cardType: r, sx: e.sx, children: /* @__PURE__ */ t(
50
- f,
59
+ ) : /* @__PURE__ */ t(S, { containerRef: c, cardType: r, sx: e.sx, children: /* @__PURE__ */ t(
60
+ m,
51
61
  {
52
62
  ...e,
53
- shouldShowHoverCard: n,
54
- renderCardContent: l,
55
- user: a
63
+ shouldShowHoverCard: u,
64
+ renderCardContent: s,
65
+ user: n
56
66
  }
57
67
  ) });
58
68
  }
59
69
  export {
60
70
  L as createNameOnlyAvatar,
61
- g as default
71
+ B as default
62
72
  };
@@ -23,6 +23,7 @@ export declare const LOGIN_PROVIDER: {
23
23
  WALLET: string;
24
24
  NFT: string;
25
25
  PASSKEY: string;
26
+ TWITTER: string;
26
27
  };
27
28
  export declare const LOGIN_PROVIDER_NAME: {
28
29
  [x: string]: string;
@@ -33,6 +34,7 @@ export declare const OAUTH_PROVIDER: {
33
34
  apple: string;
34
35
  github: string;
35
36
  google: string;
37
+ twitter: string;
36
38
  };
37
39
  export declare const DID_CONNECT_SMALL_WIDTH = 360;
38
40
  export declare const DID_CONNECT_MEDIUM_WIDTH = 576;
@@ -1,4 +1,4 @@
1
- const o = 300, t = 1800, _ = "/.well-known/service", A = "login_token", I = "refresh_token", T = "/.well-known/service", e = "/api/did", n = `${_}/admin`, s = `${_}/user`, O = `${_}/user/did-spaces`, D = `${_}/admin/navigation`, L = "did:abt:", R = {
1
+ const T = 300, _ = 1800, t = "/.well-known/service", o = "login_token", I = "refresh_token", e = "/.well-known/service", A = "/api/did", n = `${t}/admin`, s = `${t}/user`, O = `${t}/user/did-spaces`, R = `${t}/admin/navigation`, D = "did:abt:", L = {
2
2
  VALID: "valid",
3
3
  REVOKED: "revoked"
4
4
  }, E = {
@@ -9,8 +9,9 @@ const o = 300, t = 1800, _ = "/.well-known/service", A = "login_token", I = "ref
9
9
  GOOGLE: "google",
10
10
  WALLET: "wallet",
11
11
  NFT: "nft",
12
- PASSKEY: "passkey"
13
- }, l = {
12
+ PASSKEY: "passkey",
13
+ TWITTER: "twitter"
14
+ }, i = {
14
15
  [E.EMAIL]: "Email",
15
16
  [E.AUTH0]: "Auth0",
16
17
  [E.APPLE]: "Apple",
@@ -18,31 +19,33 @@ const o = 300, t = 1800, _ = "/.well-known/service", A = "login_token", I = "ref
18
19
  [E.GOOGLE]: "Google",
19
20
  [E.WALLET]: "DID Wallet",
20
21
  [E.NFT]: "NFT",
21
- [E.PASSKEY]: "Passkey"
22
- }, c = {
22
+ [E.PASSKEY]: "Passkey",
23
+ [E.TWITTER]: "X"
24
+ }, l = {
23
25
  email: "Email",
24
26
  auth0: "Auth0",
25
27
  apple: "Apple",
26
28
  github: "Github",
27
- google: "Google"
28
- }, a = 360, i = 576;
29
+ google: "Google",
30
+ twitter: "X"
31
+ }, c = 360, a = 576;
29
32
  export {
30
- e as API_DID_PREFIX,
31
- _ as BLOCKLET_SERVICE_PATH_PREFIX,
33
+ A as API_DID_PREFIX,
34
+ t as BLOCKLET_SERVICE_PATH_PREFIX,
32
35
  n as DASHBOARD_URL,
33
- o as DEFAULT_TIMEOUT,
34
- t as DEFAULT_WINDOW_TIMEOUT,
35
- i as DID_CONNECT_MEDIUM_WIDTH,
36
- a as DID_CONNECT_SMALL_WIDTH,
37
- L as DID_PREFIX,
36
+ T as DEFAULT_TIMEOUT,
37
+ _ as DEFAULT_WINDOW_TIMEOUT,
38
+ a as DID_CONNECT_MEDIUM_WIDTH,
39
+ c as DID_CONNECT_SMALL_WIDTH,
40
+ D as DID_PREFIX,
38
41
  O as DID_SPACE_URL,
39
42
  E as LOGIN_PROVIDER,
40
- l as LOGIN_PROVIDER_NAME,
41
- D as NAVIGATION_URL,
42
- c as OAUTH_PROVIDER,
43
- R as PASSPORT_STATUS,
43
+ i as LOGIN_PROVIDER_NAME,
44
+ R as NAVIGATION_URL,
45
+ l as OAUTH_PROVIDER,
46
+ L as PASSPORT_STATUS,
44
47
  s as PROFILE_URL,
45
48
  I as REFRESH_TOKEN_STORAGE_KEY,
46
- T as RELAY_SOCKET_PREFIX,
47
- A as SESSION_TOKEN_STORAGE_KEY
49
+ e as RELAY_SOCKET_PREFIX,
50
+ o as SESSION_TOKEN_STORAGE_KEY
48
51
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "3.0.33",
3
+ "version": "3.0.35",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -60,16 +60,16 @@
60
60
  "react": "^19.0.0",
61
61
  "react-router-dom": "^6.22.3"
62
62
  },
63
- "gitHead": "4b6fbddbcafd122684b82a0b452ca34fc6d1a6ab",
63
+ "gitHead": "96e21256a13c640548c59ccd807a61e6faae35f8",
64
64
  "dependencies": {
65
- "@arcblock/bridge": "3.0.33",
65
+ "@arcblock/bridge": "3.0.35",
66
66
  "@arcblock/did": "^1.21.0",
67
67
  "@arcblock/did-motif": "^1.1.14",
68
- "@arcblock/icons": "3.0.33",
69
- "@arcblock/nft-display": "3.0.33",
70
- "@arcblock/react-hooks": "3.0.33",
68
+ "@arcblock/icons": "3.0.35",
69
+ "@arcblock/nft-display": "3.0.35",
70
+ "@arcblock/react-hooks": "3.0.35",
71
71
  "@blocklet/js-sdk": "^1.16.46",
72
- "@blocklet/theme": "3.0.33",
72
+ "@blocklet/theme": "3.0.35",
73
73
  "@fontsource/roboto": "~5.1.1",
74
74
  "@fontsource/ubuntu-mono": "^5.2.6",
75
75
  "@iconify-icons/logos": "^1.2.36",
@@ -23,6 +23,7 @@ import { DID_PREFIX } from '../Util/constant';
23
23
  * shape?: '' | 'rectangle' | 'square' | 'hexagon' | 'circle';
24
24
  * blockiesPadding?: true | false;
25
25
  * responsive?: false | true;
26
+ * useProxyFallback?: boolean;
26
27
  * } & Omit<import('../Img').ImgProps, 'size' | 'src'>} AvatarProps
27
28
  */
28
29
 
@@ -84,6 +85,7 @@ function Avatar({ ...rawProps }) {
84
85
  {...rest}
85
86
  // HACK: 这个 className 是传递给子元素的,所以下面的 sx 需要通过子元素选择器来写样式
86
87
  className={`avatar-img--${variant} ${rest?.className || ''}`}
88
+ useProxyFallback
87
89
  sx={{
88
90
  '& .avatar-img--rounded': {
89
91
  borderRadius: '4px',
@@ -159,6 +161,7 @@ Avatar.propTypes = {
159
161
  shape: PropTypes.oneOf(['', 'rectangle', 'square', 'hexagon', 'circle']),
160
162
  blockiesPadding: PropTypes.bool,
161
163
  responsive: PropTypes.bool,
164
+ useProxyFallback: PropTypes.bool,
162
165
  };
163
166
 
164
167
  /**
@@ -1,28 +1,5 @@
1
1
  import { Box, Typography } from '@mui/material';
2
2
  import Img from '../../Img';
3
- import { BLOCKLET_SERVICE_PATH_PREFIX } from '../../Util/constant';
4
-
5
- const getProxyImageUrl = (url: string) => {
6
- if (!url) return '';
7
-
8
- try {
9
- // 检查是否是一个有效的URL
10
- const urlObj = new URL(url);
11
-
12
- // 检查协议是否是https
13
- if (urlObj.protocol !== 'https:') {
14
- console.warn('Image URL must use HTTPS protocol:', url);
15
- return '';
16
- }
17
-
18
- // 返回代理URL
19
- return `${BLOCKLET_SERVICE_PATH_PREFIX}/proxy?url=${url}`;
20
- } catch (error) {
21
- // URL construction failed, indicating invalid URL format
22
- console.warn('Invalid image URL format:', url, error);
23
- return '';
24
- }
25
- };
26
3
 
27
4
  export type RequestAppInfo = {
28
5
  appLogo: string;
@@ -59,13 +36,7 @@ export default function AuthAppsInfo({
59
36
  justifyContent: 'center',
60
37
  }}>
61
38
  {/* FIXME: @zhanghan 增加 hover 的效果 */}
62
- <Img
63
- src={currentAppInfo.appLogo}
64
- alt="Server"
65
- width={48}
66
- height={48}
67
- fallback={getProxyImageUrl(currentAppInfo.appLogo)}
68
- />
39
+ <Img src={currentAppInfo.appLogo} alt="Server" width={48} height={48} useProxyFallback />
69
40
 
70
41
  <Box
71
42
  sx={{
@@ -86,13 +57,7 @@ export default function AuthAppsInfo({
86
57
  </Box>
87
58
 
88
59
  {/* FIXME: @zhanghan 增加 hover 的效果 */}
89
- <Img
90
- src={requestAppInfo.appLogo}
91
- alt={requestAppInfo.appName}
92
- width={48}
93
- height={48}
94
- fallback={getProxyImageUrl(requestAppInfo.appLogo)}
95
- />
60
+ <Img src={requestAppInfo.appLogo} alt={requestAppInfo.appName} width={48} height={48} useProxyFallback />
96
61
  </Box>
97
62
 
98
63
  <Typography
@@ -0,0 +1,18 @@
1
+ import { Box } from '@mui/material';
2
+
3
+ type LogoSize = number | string;
4
+
5
+ export default function DIDWalletLogo({
6
+ width = '100%',
7
+ height = '100%',
8
+ ...rest
9
+ }: {
10
+ width?: LogoSize;
11
+ height?: LogoSize;
12
+ [key: string]: any;
13
+ }) {
14
+ const didWalletLogo =
15
+ 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI3ByZWZpeF9fY2xpcDApIj48cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHJ4PSI2IiBmaWxsPSJ1cmwoI3ByZWZpeF9fcGFpbnQwX2xpbmVhcikiLz48ZyBmaWx0ZXI9InVybCgjcHJlZml4X19maWx0ZXIwX2kpIj48cGF0aCBkPSJNMy41MiA3LjM2QTIuNTYgMi41NiAwIDAxNi4wOCA0LjhoMTkuODRhMi41NiAyLjU2IDAgMDEyLjU2IDIuNTZ2MTIuMTZhMi41NiAyLjU2IDAgMDEtMi41NiAyLjU2SDYuMDhhMi41NiAyLjU2IDAgMDEtMi41Ni0yLjU2VjcuMzZ6IiBmaWxsPSIjOUZDQkZGIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNwcmVmaXhfX2ZpbHRlcjFfZCkiPjxwYXRoIGQ9Ik0yLjU2IDkuMjhhMi41NiAyLjU2IDAgMDEyLjU2LTIuNTZoMjEuNzZhMi41NiAyLjU2IDAgMDEyLjU2IDIuNTZ2MTMuNmEyLjU2IDIuNTYgMCAwMS0yLjU2IDIuNTZINS4xMmEyLjU2IDIuNTYgMCAwMS0yLjU2LTIuNTZWOS4yOHoiIGZpbGw9InVybCgjcHJlZml4X19wYWludDFfbGluZWFyKSIvPjwvZz48ZyBmaWx0ZXI9InVybCgjcHJlZml4X19maWx0ZXIyX2QpIj48cGF0aCBkPSJNMCAyMi4zMmwzMi02LjE2VjMySDB2LTkuNjh6IiBmaWxsPSJ1cmwoI3ByZWZpeF9fcGFpbnQyX2xpbmVhcikiLz48L2c+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01LjUzNiA5LjI0OGg4LjI4OGMuNDA4IDAgLjc0LjMuNzQuNjcydjQuNjRjMCAuMzcxLS4zMzIuNjcyLS43NC42NzJINS41MzZjLS40MDggMC0uNzQtLjMtLjc0LS42NzJ2LS4wNGEuMTU4LjE1OCAwIDEwLS4zMTYgMHYuMDRjMCAuNTMuNDczLjk2IDEuMDU2Ljk2aDguMjg4Yy41ODMgMCAxLjA1Ni0uNDMgMS4wNTYtLjk2VjkuOTJjMC0uNTMtLjQ3My0uOTYtMS4wNTYtLjk2SDUuNTM2Yy0uNTgzIDAtMS4wNTYuNDMtMS4wNTYuOTZ2LjA0YS4xNTguMTU4IDAgMDAuMzE3IDB2LS4wNGMwLS4zNzEuMzMtLjY3Mi43MzktLjY3MnptLTEuMDIzIDQuNjM4YS4xMjcuMTI3IDAgMDAuMDg3LjAzNGgxLjI2N2MuNDcyIDAgLjgzLS4xMDcgMS4wNzYtLjMyMi4yNS0uMjE3LjM4MS0uNTQ4LjM5Ny0uOTkzYTExLjI4MSAxMS4yODEgMCAwMDAtLjczNGMtLjAxMi0uNDI2LS4xNDgtLjc1MS0uNDA2LS45NzUtLjI1OC0uMjI0LS42MjItLjMzNi0xLjA5LS4zMzZINC42YS4xMjcuMTI3IDAgMDAtLjA4Ny4wMzQuMTE3LjExNyAwIDAwLS4wMzMuMDg2djMuMTJjMCAuMDMyLjAxMS4wNi4wMzMuMDg2em0xLjc5NC0uODA2Yy0uMDk5LjEtLjI1My4xNDktLjQ2NC4xNDloLS41MDJWMTEuMjVoLjQ3OGMuMjEgMCAuMzY5LjA1MS40NzQuMTU0LjEwOC4xMDIuMTY2LjI2LjE3Mi40NzUuMDA2LjA5LjAxLjIwOC4wMS4zNTVzLS4wMDQuMjY3LS4wMS4zNmMtLjAwNi4yMjEtLjA1OS4zODMtLjE1OC40ODV6bTEuNjMuODA2YS4xMjcuMTI3IDAgMDAuMDg3LjAzNGguNjRhLjExNi4xMTYgMCAwMC4wODctLjAzNC4xMS4xMSAwIDAwLjAzOC0uMDg2di0zLjEyYS4xMS4xMSAwIDAwLS4wMzgtLjA4Ni4xMTYuMTE2IDAgMDAtLjA4Ni0uMDM0aC0uNjQxYS4xMjcuMTI3IDAgMDAtLjA4Ny4wMzQuMTE3LjExNyAwIDAwLS4wMzMuMDg2djMuMTJjMCAuMDMyLjAxMS4wNi4wMzMuMDg2em0xLjYzNy4wMzRhLjEyNy4xMjcgMCAwMS0uMDg2LS4wMzQuMTI4LjEyOCAwIDAxLS4wMzMtLjA4NnYtMy4xMmMwLS4wMzUuMDEtLjA2NC4wMzMtLjA4NmEuMTI3LjEyNyAwIDAxLjA4Ni0uMDM0aDEuMjQ0Yy40NjkgMCAuODMyLjExMiAxLjA5LjMzNi4yNTkuMjI0LjM5NC41NDkuNDA3Ljk3NGExMS4yNDQgMTEuMjQ0IDAgMDEwIC43MzVjLS4wMTYuNDQ1LS4xNDguNzc2LS4zOTcuOTkzLS4yNDUuMjE1LS42MDQuMzIyLTEuMDc2LjMyMkg5LjU3NHptMS4yNDQtLjY5MWMuMjEgMCAuMzY1LS4wNS40NjQtLjE0OS4wOTktLjEwMi4xNTItLjI2NC4xNTgtLjQ4NWE1LjUyIDUuNTIgMCAwMC4wMS0uMzZjMC0uMTQ3LS4wMDQtLjI2NS0uMDEtLjM1NS0uMDA2LS4yMTQtLjA2NC0uMzczLS4xNzItLjQ3NS0uMTA2LS4xMDMtLjI2My0uMTU0LS40NzQtLjE1NGgtLjQ3OHYxLjk3OGguNTAyem0yLjQ2OC0xLjM4MmEuMjg4LjI4OCAwIDAxLS4yODgtLjI4Ni4yODguMjg4IDAgMDEuNTc2IDBjMCAuMTU4LS4xMy4yODYtLjI4OC4yODZ6bTAgMS40OTVhLjI4OC4yODggMCAwMS0uMjg4LS4yODYuMjg4LjI4OCAwIDAxLjU3NiAwYzAgLjE1OC0uMTMuMjg3LS4yODguMjg3eiIgZmlsbD0iIzQ1OThGQSIvPjwvZz48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9InByZWZpeF9fcGFpbnQwX2xpbmVhciIgeDE9IjE2IiB5MT0iMCIgeDI9IjE2IiB5Mj0iMzIiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNEY5REY2Ii8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMEE3OUY4Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9InByZWZpeF9fcGFpbnQxX2xpbmVhciIgeDE9IjE2IiB5MT0iNi43MiIgeDI9IjE2IiB5Mj0iMjUuNDQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjRUNFRkZGIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9InByZWZpeF9fcGFpbnQyX2xpbmVhciIgeDE9IjE2IiB5MT0iMTkuMiIgeDI9IjE4LjQ4IiB5Mj0iMzIiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9Ii4wMDciIHN0b3AtY29sb3I9IiM3N0IyRjYiLz48c3RvcCBvZmZzZXQ9Ii4wNTUiIHN0b3AtY29sb3I9IiM0RjlERjYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM0NTk4RkEiLz48L2xpbmVhckdyYWRpZW50PjxmaWx0ZXIgaWQ9InByZWZpeF9fZmlsdGVyMF9pIiB4PSIzLjUyIiB5PSIxLjgiIHdpZHRoPSIyNC45NiIgaGVpZ2h0PSIyMC4yOCIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9InNoYXBlIi8+PGZlQ29sb3JNYXRyaXggaW49IlNvdXJjZUFscGhhIiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIiByZXN1bHQ9ImhhcmRBbHBoYSIvPjxmZU9mZnNldCBkeT0iLTMiLz48ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyIi8+PGZlQ29tcG9zaXRlIGluMj0iaGFyZEFscGhhIiBvcGVyYXRvcj0iYXJpdGhtZXRpYyIgazI9Ii0xIiBrMz0iMSIvPjxmZUNvbG9yTWF0cml4IHZhbHVlcz0iMCAwIDAgMCAxIDAgMCAwIDAgMSAwIDAgMCAwIDEgMCAwIDAgMC4yIDAiLz48ZmVCbGVuZCBpbjI9InNoYXBlIiByZXN1bHQ9ImVmZmVjdDFfaW5uZXJTaGFkb3ciLz48L2ZpbHRlcj48ZmlsdGVyIGlkPSJwcmVmaXhfX2ZpbHRlcjFfZCIgeD0iLTEuNDQiIHk9IjEuNzIiIHdpZHRoPSIzNC44OCIgaGVpZ2h0PSIyNi43MiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQ29sb3JNYXRyaXggaW49IlNvdXJjZUFscGhhIiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIiByZXN1bHQ9ImhhcmRBbHBoYSIvPjxmZU9mZnNldCBkeT0iLTEiLz48ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAuMjIwNzY3IDAgMCAwIDAgMC40NzA4MDMgMCAwIDAgMCAwLjcwMTYwNSAwIDAgMCAwLjE4IDAiLz48ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3ciLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3ciIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48ZmlsdGVyIGlkPSJwcmVmaXhfX2ZpbHRlcjJfZCIgeD0iLTUiIHk9IjExLjE2IiB3aWR0aD0iNDIiIGhlaWdodD0iMjUuODQiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPjxmZUNvbG9yTWF0cml4IGluPSJTb3VyY2VBbHBoYSIgdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAxMjcgMCIgcmVzdWx0PSJoYXJkQWxwaGEiLz48ZmVPZmZzZXQvPjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIuNSIvPjxmZUNvbG9yTWF0cml4IHZhbHVlcz0iMCAwIDAgMCAwLjE0MzgyIDAgMCAwIDAgMC4yMDUwNjUgMCAwIDAgMCAwLjUyMjYzNCAwIDAgMCAwLjI1IDAiLz48ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3ciLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3ciIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48Y2xpcFBhdGggaWQ9InByZWZpeF9fY2xpcDAiPjxyZWN0IHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgcng9IjYiIGZpbGw9IiNmZmYiLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4=';
16
+
17
+ return <Box component="img" width={width} height={height} alt="did-wallet-logo" {...rest} src={didWalletLogo} />;
18
+ }
@@ -0,0 +1,17 @@
1
+ type LogoSize = number | string;
2
+
3
+ export default function GithubLogo({
4
+ width = 24,
5
+ height = 24,
6
+ ...props
7
+ }: {
8
+ width?: LogoSize;
9
+ height?: LogoSize;
10
+ [key: string]: any;
11
+ }) {
12
+ return (
13
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 250" width={width} height={height} {...props}>
14
+ <path d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46c6.397 1.185 8.746-2.777 8.746-6.158c0-3.052-.12-13.135-.174-23.83c-35.61 7.742-43.124-15.103-43.124-15.103c-5.823-14.795-14.213-18.73-14.213-18.73c-11.613-7.944.876-7.78.876-7.78c12.853.902 19.621 13.19 19.621 13.19c11.417 19.568 29.945 13.911 37.249 10.64c1.149-8.272 4.466-13.92 8.127-17.116c-28.431-3.236-58.318-14.212-58.318-63.258c0-13.975 5-25.394 13.188-34.358c-1.329-3.224-5.71-16.242 1.24-33.874c0 0 10.749-3.44 35.21 13.121c10.21-2.836 21.16-4.258 32.038-4.307c10.878.049 21.837 1.47 32.066 4.307c24.431-16.56 35.165-13.12 35.165-13.12c6.967 17.63 2.584 30.65 1.255 33.873c8.207 8.964 13.173 20.383 13.173 34.358c0 49.163-29.944 59.988-58.447 63.157c4.591 3.972 8.682 11.762 8.682 23.704c0 17.126-.148 30.91-.148 35.126c0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002C256 57.307 198.691 0 128.001 0m-80.06 182.34c-.282.636-1.283.827-2.194.39c-.929-.417-1.45-1.284-1.15-1.922c.276-.655 1.279-.838 2.205-.399c.93.418 1.46 1.293 1.139 1.931m6.296 5.618c-.61.566-1.804.303-2.614-.591c-.837-.892-.994-2.086-.375-2.66c.63-.566 1.787-.301 2.626.591c.838.903 1 2.088.363 2.66m4.32 7.188c-.785.545-2.067.034-2.86-1.104c-.784-1.138-.784-2.503.017-3.05c.795-.547 2.058-.055 2.861 1.075c.782 1.157.782 2.522-.019 3.08m7.304 8.325c-.701.774-2.196.566-3.29-.49c-1.119-1.032-1.43-2.496-.726-3.27c.71-.776 2.213-.558 3.315.49c1.11 1.03 1.45 2.505.701 3.27m9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033c-1.448-.439-2.395-1.613-2.103-2.626c.301-1.01 1.747-1.484 3.207-1.028c1.446.436 2.396 1.602 2.095 2.622m10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95c-1.53.034-2.769-.82-2.786-1.86c0-1.065 1.202-1.932 2.733-1.958c1.522-.03 2.768.818 2.768 1.868m10.555-.405c.182 1.03-.875 2.088-2.387 2.37c-1.485.271-2.861-.365-3.05-1.386c-.184-1.056.893-2.114 2.376-2.387c1.514-.263 2.868.356 3.061 1.403" />
15
+ </svg>
16
+ );
17
+ }
@@ -0,0 +1,62 @@
1
+ import { memo } from 'react';
2
+ import mailOutlineRoundedIcon from '@iconify-icons/material-symbols/mail-outline-rounded';
3
+ import appleIcon from '@iconify-icons/logos/apple';
4
+ import googleIcon from '@iconify-icons/logos/google-icon';
5
+ import auth0Icon from '@iconify-icons/logos/auth0-icon';
6
+ import passKeyRoundedIcon from '@iconify-icons/material-symbols/passkey-rounded';
7
+ import { Icon } from '@iconify/react';
8
+ import { Box, BoxProps, SxProps } from '@mui/material';
9
+
10
+ import { LOGIN_PROVIDER } from '../Util/constant';
11
+ import { mergeSx } from '../Util/style';
12
+ import DIDWalletLogo from './icons/did-wallet-logo';
13
+ import GithubLogo from './icons/github-logo';
14
+
15
+ function ProviderIcon({
16
+ provider = 'wallet',
17
+ ...rest
18
+ }: {
19
+ provider?: (typeof LOGIN_PROVIDER)[keyof typeof LOGIN_PROVIDER] | 'wallet-web';
20
+ } & BoxProps) {
21
+ if (['wallet', 'wallet-web'].includes(provider)) {
22
+ // @ts-ignore
23
+ return <DIDWalletLogo {...rest} />;
24
+ }
25
+
26
+ if (provider === LOGIN_PROVIDER.GITHUB) {
27
+ return (
28
+ <Box component="span" {...rest} sx={mergeSx({ display: 'inline-block' }, rest.sx as SxProps)}>
29
+ <GithubLogo width="100%" height="100%" fill="currentColor" />
30
+ </Box>
31
+ );
32
+ }
33
+
34
+ const iconMap = {
35
+ [LOGIN_PROVIDER.AUTH0]: auth0Icon,
36
+ [LOGIN_PROVIDER.EMAIL]: mailOutlineRoundedIcon,
37
+ [LOGIN_PROVIDER.APPLE]: appleIcon,
38
+ [LOGIN_PROVIDER.GOOGLE]: googleIcon,
39
+ [LOGIN_PROVIDER.PASSKEY]: passKeyRoundedIcon,
40
+ [LOGIN_PROVIDER.TWITTER]: {
41
+ body: '<path fill="currentColor" d="M149.079 108.399L242.33 0h-22.098l-80.97 94.12L74.59 0H0l97.796 142.328L0 256h22.1l85.507-99.395L175.905 256h74.59L149.073 108.399zM118.81 143.58l-9.909-14.172l-78.84-112.773h33.943l63.625 91.011l9.909 14.173l82.705 118.3H186.3l-67.49-96.533z"/>',
42
+ width: 251,
43
+ height: 251,
44
+ },
45
+ };
46
+
47
+ return iconMap[provider] ? (
48
+ <Box
49
+ component={Icon}
50
+ icon={iconMap[provider]}
51
+ fill="currentColor"
52
+ {...rest}
53
+ sx={mergeSx(
54
+ { width: '100%', height: '100%' },
55
+ provider === LOGIN_PROVIDER.TWITTER ? { scale: '0.8' } : {},
56
+ rest.sx as SxProps
57
+ )}
58
+ />
59
+ ) : null;
60
+ }
61
+
62
+ export default memo(ProviderIcon);
package/src/Img/index.jsx CHANGED
@@ -7,6 +7,29 @@ import { Icon } from '@iconify/react';
7
7
  import { Box } from '@mui/material';
8
8
  import noop from 'lodash/noop';
9
9
  import { mergeSx } from '../Util/style';
10
+ import { BLOCKLET_SERVICE_PATH_PREFIX } from '../Util/constant';
11
+
12
+ const getProxyImageUrl = (url) => {
13
+ if (!url) return '';
14
+
15
+ try {
16
+ // 检查是否是一个有效的URL
17
+ const urlObj = new URL(url);
18
+
19
+ // 检查协议是否是https
20
+ if (urlObj.protocol !== 'https:') {
21
+ console.warn('Image URL must use HTTPS protocol:', url);
22
+ return '';
23
+ }
24
+
25
+ // 返回代理URL
26
+ return `${BLOCKLET_SERVICE_PATH_PREFIX}/proxy?url=${encodeURIComponent(url)}`;
27
+ } catch (error) {
28
+ // URL construction failed, indicating invalid URL format
29
+ console.warn('Invalid image URL format:', url, error);
30
+ return '';
31
+ }
32
+ };
10
33
 
11
34
  /**
12
35
  * @typedef {Object} ImgExProps
@@ -22,6 +45,7 @@ import { mergeSx } from '../Util/style';
22
45
  * @property {boolean} [lazy=true]
23
46
  * @property {string} [placeholder]
24
47
  * @property {string} [fallback]
48
+ * @property {boolean} [useProxyFallback=false] - 是否使用代理 fallback, 用于解决 CSP 的问题
25
49
  * @property {string} [className='']
26
50
  * @property {function} [onError=() => {}]
27
51
  * @property {function} [onSuccess=() => {}]
@@ -52,6 +76,7 @@ function Img({
52
76
  size = 'cover',
53
77
  position = 'top center',
54
78
  src,
79
+ useProxyFallback = false, // 是否使用代理 fallback, 用于解决 CSP 的问题
55
80
  placeholder = null,
56
81
  fallback = null,
57
82
  style = null,
@@ -66,19 +91,29 @@ function Img({
66
91
  const [imgState, setImgState] = useState('init');
67
92
  const [fallbackError, setFallbackError] = useState(false);
68
93
 
94
+ const fallbackSrc = useMemo(() => {
95
+ if (fallback) {
96
+ return fallback;
97
+ }
98
+ if (useProxyFallback && src) {
99
+ return getProxyImageUrl(src);
100
+ }
101
+ return fallback;
102
+ }, [src, useProxyFallback, fallback]);
103
+
69
104
  const actualSrc = useMemo(() => {
70
105
  switch (imgState) {
71
106
  case 'init':
72
107
  case 'loading':
73
108
  return placeholder;
74
109
  case 'error':
75
- return fallbackError ? null : fallback;
110
+ return fallbackError ? null : fallbackSrc;
76
111
  case 'loaded':
77
112
  return src;
78
113
  default:
79
114
  return null;
80
115
  }
81
- }, [placeholder, fallback, src, imgState, fallbackError]);
116
+ }, [placeholder, fallbackSrc, src, imgState, fallbackError]);
82
117
 
83
118
  const actualRatio = width && height ? (100 * height) / width : ratio * 100;
84
119
 
@@ -112,9 +147,8 @@ function Img({
112
147
  setImgState('loaded');
113
148
  onSuccess();
114
149
  };
115
- img.onerror = (err) => {
150
+ img.onerror = () => {
116
151
  setImgState('error');
117
- onError(err);
118
152
  };
119
153
  }
120
154
 
@@ -125,18 +159,21 @@ function Img({
125
159
 
126
160
  // 处理 fallback 加载
127
161
  useEffect(() => {
128
- if (imgState === 'error' && fallback && !fallbackError) {
162
+ if (imgState === 'error' && fallbackSrc && !fallbackError) {
129
163
  const fallbackImg = new Image();
130
- fallbackImg.src = fallback;
164
+ fallbackImg.src = fallbackSrc;
131
165
  fallbackImg.onload = () => {
132
166
  // fallback 加载成功,保持在 error 状态但显示 fallback
133
167
  };
134
- fallbackImg.onerror = () => {
168
+ fallbackImg.onerror = (err) => {
135
169
  // fallback 也加载失败
136
170
  setFallbackError(true);
171
+ if (imgState === 'error') {
172
+ onError(err);
173
+ }
137
174
  };
138
175
  }
139
- }, [imgState, fallback, fallbackError]);
176
+ }, [imgState, fallbackSrc, fallbackError, onError]);
140
177
 
141
178
  return (
142
179
  // paddingTop 要求元素本身的宽度为 100%,所以只能加一个外层元素去限制宽度
@@ -183,7 +220,7 @@ function Img({
183
220
  rest.sx
184
221
  )}>
185
222
  <div className={`image ${className} ${classes.root}`} style={mergedStyle}>
186
- {(fallbackError || (!fallback && imgState === 'error')) && (
223
+ {(fallbackError || (!fallbackSrc && imgState === 'error')) && (
187
224
  <div className="image--state" title="Image load error">
188
225
  <Icon icon={WarningRoundedIcon} className="image--icon" />
189
226
  </div>
@@ -215,6 +252,7 @@ Img.propTypes = {
215
252
  className: PropTypes.string,
216
253
  onError: PropTypes.func,
217
254
  onSuccess: PropTypes.func,
255
+ useProxyFallback: PropTypes.bool,
218
256
  };
219
257
 
220
258
  export default Img;
@@ -51,6 +51,7 @@ export const renderAvatar = (
51
51
  size={avatarSize}
52
52
  did={user.did}
53
53
  variant="circle"
54
+ useProxyFallback
54
55
  style={{
55
56
  cursor: shouldShowHoverCard || onAvatarClick ? 'pointer' : 'default',
56
57
  }}