@arcblock/ux 2.13.13 → 2.13.15
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/Address/responsive-did-address.js +3 -1
- package/lib/Config/theme-mode-toggle.js +1 -1
- package/lib/DIDConnect/app-icon.d.ts +8 -0
- package/lib/DIDConnect/app-icon.js +31 -0
- package/lib/DIDConnect/app-info-item.d.ts +7 -0
- package/lib/DIDConnect/app-info-item.js +73 -0
- package/lib/DIDConnect/did-connect-footer.d.ts +4 -0
- package/lib/DIDConnect/did-connect-footer.js +54 -0
- package/lib/DIDConnect/did-connect-logo.d.ts +1 -0
- package/lib/DIDConnect/did-connect-logo.js +11 -0
- package/lib/DIDConnect/index.d.ts +7 -0
- package/lib/DIDConnect/index.js +7 -0
- package/lib/DIDConnect/powered-by.d.ts +3 -0
- package/lib/DIDConnect/powered-by.js +46 -0
- package/lib/DIDConnect/with-container.d.ts +11 -0
- package/lib/DIDConnect/with-container.js +273 -0
- package/lib/DIDConnect/with-ux-theme.d.ts +1 -0
- package/lib/DIDConnect/with-ux-theme.js +23 -0
- package/lib/Datatable/CustomToolbar.js +0 -3
- package/lib/Datatable/index.d.ts +3 -0
- package/lib/Datatable/index.js +36 -20
- package/lib/Dialog/confirm.d.ts +6 -1
- package/lib/Dialog/confirm.js +7 -3
- package/lib/Dialog/use-confirm.js +6 -0
- package/lib/LoadingMask/index.js +1 -1
- package/lib/Locale/util.d.ts +3 -3
- package/lib/Locale/util.js +6 -1
- package/lib/LoginButton/index.d.ts +12 -0
- package/lib/LoginButton/index.js +74 -0
- package/lib/NavMenu/style.js +0 -1
- package/lib/SessionUser/components/un-login.js +42 -31
- package/lib/SharedBridge/index.d.ts +16 -0
- package/lib/SharedBridge/index.js +109 -0
- package/lib/SharedBridge/need-storage-access-api-dialog.d.ts +7 -0
- package/lib/SharedBridge/need-storage-access-api-dialog.js +212 -0
- package/lib/Theme/index.d.ts +2 -2
- package/lib/Theme/index.js +1 -1
- package/lib/Util/iframe.d.ts +5 -0
- package/lib/Util/iframe.js +24 -0
- package/lib/Util/index.d.ts +10 -1
- package/lib/Util/index.js +67 -4
- package/lib/hooks/use-blocklet-logo.d.ts +8 -0
- package/lib/hooks/use-blocklet-logo.js +31 -0
- package/lib/hooks/use-mobile.d.ts +4 -0
- package/lib/hooks/use-mobile.js +7 -0
- package/package.json +7 -6
- package/src/Address/responsive-did-address.tsx +11 -1
- package/src/Config/theme-mode-toggle.tsx +1 -1
- package/src/DIDConnect/app-icon.tsx +36 -0
- package/src/DIDConnect/app-info-item.tsx +82 -0
- package/src/DIDConnect/did-connect-footer.tsx +51 -0
- package/src/DIDConnect/did-connect-logo.tsx +8 -0
- package/src/DIDConnect/index.ts +7 -0
- package/src/DIDConnect/powered-by.tsx +48 -0
- package/src/DIDConnect/with-container.tsx +307 -0
- package/src/DIDConnect/with-ux-theme.tsx +22 -0
- package/src/Datatable/CustomToolbar.jsx +0 -1
- package/src/Datatable/index.jsx +32 -20
- package/src/Dialog/confirm.jsx +31 -23
- package/src/Dialog/use-confirm.jsx +6 -0
- package/src/LoadingMask/index.tsx +1 -1
- package/src/Locale/util.ts +7 -2
- package/src/LoginButton/index.tsx +73 -0
- package/src/NavMenu/style.ts +0 -1
- package/src/SessionUser/components/un-login.tsx +34 -27
- package/src/SharedBridge/index.tsx +123 -0
- package/src/SharedBridge/need-storage-access-api-dialog.tsx +171 -0
- package/src/Theme/index.ts +2 -2
- package/src/Util/iframe.ts +19 -0
- package/src/Util/index.ts +77 -4
- package/src/hooks/use-blocklet-logo.tsx +32 -0
- package/src/hooks/use-mobile.tsx +6 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import { Box, Typography, Chip, List, ListItem } from '@mui/material';
|
3
|
+
import { Icon } from '@iconify/react';
|
4
|
+
import externalLinkIcon from '@iconify-icons/tabler/external-link';
|
5
|
+
import lockOutlineIcon from '@iconify-icons/material-symbols/lock-outline';
|
6
|
+
import checkCircleIcon from '@iconify-icons/material-symbols/check-circle';
|
7
|
+
import rocketLaunchRoundedIcon from '@iconify-icons/material-symbols/rocket-launch-rounded';
|
8
|
+
import { useCreation, useMemoizedFn } from 'ahooks';
|
9
|
+
import { useEffect } from 'react';
|
10
|
+
import { getDIDMotifInfo } from '@arcblock/did-motif';
|
11
|
+
import { translate } from '../Locale/util';
|
12
|
+
import { getDIDColor, isEthereumDid } from '../Util';
|
13
|
+
import { DIDConnectFooter } from '../DIDConnect';
|
14
|
+
const translations = {
|
15
|
+
en: {
|
16
|
+
allow: 'Allow',
|
17
|
+
dataUsage: 'Your data is only used for identity authentication, and will not be collected or used for any other purpose.',
|
18
|
+
title: 'Cross-site authorization request',
|
19
|
+
clickAllow: ({
|
20
|
+
allowButton
|
21
|
+
}) => {
|
22
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
23
|
+
children: ["You only need to click the ", allowButton, " button above, and you will not see this request again."]
|
24
|
+
});
|
25
|
+
},
|
26
|
+
reason: ({
|
27
|
+
site
|
28
|
+
}) => {
|
29
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
30
|
+
children: ["For a better login experience, we need to apply for the storage permission of the ", site, " site."]
|
31
|
+
});
|
32
|
+
},
|
33
|
+
afterAllow: {
|
34
|
+
title: 'After authorization, you will enjoy:',
|
35
|
+
list1: 'More convenient login experience',
|
36
|
+
list2: 'Faster access speed'
|
37
|
+
}
|
38
|
+
},
|
39
|
+
zh: {
|
40
|
+
allow: '允许',
|
41
|
+
dataUsage: '您的数据仅用于身份认证,不会被收集或用于其他用途。',
|
42
|
+
title: '跨站授权请求',
|
43
|
+
clickAllow: ({
|
44
|
+
allowButton
|
45
|
+
}) => {
|
46
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
47
|
+
children: ["\u60A8\u53EA\u9700\u8981\u70B9\u51FB\u5C4F\u5E55\u4E0A\u65B9\u7684 ", allowButton, " \u6309\u94AE\uFF0C\u540E\u7EED\u5C06\u4E0D\u4F1A\u518D\u770B\u5230\u8FD9\u4E2A\u8BF7\u6C42\u3002"]
|
48
|
+
});
|
49
|
+
},
|
50
|
+
reason: ({
|
51
|
+
site
|
52
|
+
}) => {
|
53
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
54
|
+
children: ["\u4E3A\u4E86\u8BA9\u60A8\u83B7\u5F97\u66F4\u597D\u7684\u767B\u5F55\u4F53\u9A8C\uFF0C\u6211\u4EEC\u9700\u8981\u7533\u8BF7 ", site, " \u7AD9\u70B9\u5B58\u50A8\u6743\u9650\u3002"]
|
55
|
+
});
|
56
|
+
},
|
57
|
+
afterAllow: {
|
58
|
+
title: '授权后,您将享受:',
|
59
|
+
list1: '更便捷的登录体验',
|
60
|
+
list2: '更快的访问速度'
|
61
|
+
}
|
62
|
+
}
|
63
|
+
};
|
64
|
+
export default function NeedStorageAccessApiDialog({
|
65
|
+
locale = 'en',
|
66
|
+
origin,
|
67
|
+
host,
|
68
|
+
setColor
|
69
|
+
}) {
|
70
|
+
const t = useMemoizedFn((key, data = {}) => {
|
71
|
+
return translate(translations, key, locale, 'en', data);
|
72
|
+
});
|
73
|
+
const currentAppColor = useCreation(() => {
|
74
|
+
const did = window.blocklet.appPid;
|
75
|
+
const isEthDid = isEthereumDid(did);
|
76
|
+
const didMotifInfo = isEthDid ? undefined : getDIDMotifInfo(did);
|
77
|
+
if (isEthDid) {
|
78
|
+
return getDIDColor(did);
|
79
|
+
}
|
80
|
+
return didMotifInfo.color;
|
81
|
+
}, []);
|
82
|
+
useEffect(() => {
|
83
|
+
setColor(currentAppColor);
|
84
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
85
|
+
}, [currentAppColor]);
|
86
|
+
return /*#__PURE__*/_jsxs(Box, {
|
87
|
+
sx: {
|
88
|
+
backgroundColor: 'background.default',
|
89
|
+
display: 'flex',
|
90
|
+
flexDirection: 'column',
|
91
|
+
height: '100%',
|
92
|
+
position: 'relative',
|
93
|
+
maxWidth: '100%',
|
94
|
+
transition: 'width 0.2s ease-in-out',
|
95
|
+
margin: 'auto',
|
96
|
+
p: 3,
|
97
|
+
pb: 0,
|
98
|
+
gap: 2
|
99
|
+
},
|
100
|
+
children: [/*#__PURE__*/_jsxs(Typography, {
|
101
|
+
component: "h1",
|
102
|
+
variant: "h4",
|
103
|
+
sx: {
|
104
|
+
fontWeight: 700,
|
105
|
+
fontFamily: 'Lexend',
|
106
|
+
display: 'flex',
|
107
|
+
alignItems: 'center',
|
108
|
+
gap: 1
|
109
|
+
},
|
110
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
111
|
+
component: Icon,
|
112
|
+
icon: lockOutlineIcon,
|
113
|
+
fontSize: 28,
|
114
|
+
sx: {
|
115
|
+
color: 'warning.main'
|
116
|
+
}
|
117
|
+
}), t('title')]
|
118
|
+
}), /*#__PURE__*/_jsxs(Box, {
|
119
|
+
sx: {
|
120
|
+
display: 'flex',
|
121
|
+
flexDirection: 'column',
|
122
|
+
gap: 1
|
123
|
+
},
|
124
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
125
|
+
children: t('reason', {
|
126
|
+
site: /*#__PURE__*/_jsx(Chip, {
|
127
|
+
clickable: true,
|
128
|
+
component: "a",
|
129
|
+
href: origin,
|
130
|
+
label: host,
|
131
|
+
size: "small",
|
132
|
+
deleteIcon: /*#__PURE__*/_jsx(Icon, {
|
133
|
+
icon: externalLinkIcon
|
134
|
+
}),
|
135
|
+
onDelete: () => {},
|
136
|
+
target: "_blank"
|
137
|
+
})
|
138
|
+
})
|
139
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
140
|
+
children: t('clickAllow', {
|
141
|
+
allowButton: /*#__PURE__*/_jsx(Chip, {
|
142
|
+
label: t('allow'),
|
143
|
+
size: "small",
|
144
|
+
color: "success"
|
145
|
+
})
|
146
|
+
})
|
147
|
+
}), /*#__PURE__*/_jsxs(Box, {
|
148
|
+
sx: {
|
149
|
+
mt: 2
|
150
|
+
},
|
151
|
+
children: [/*#__PURE__*/_jsxs(Typography, {
|
152
|
+
sx: {
|
153
|
+
display: 'flex',
|
154
|
+
alignItems: 'center',
|
155
|
+
gap: 1,
|
156
|
+
mb: 0.5
|
157
|
+
},
|
158
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
159
|
+
component: Icon,
|
160
|
+
icon: checkCircleIcon,
|
161
|
+
fontSize: 24,
|
162
|
+
sx: {
|
163
|
+
color: 'success.main'
|
164
|
+
}
|
165
|
+
}), t('afterAllow.title')]
|
166
|
+
}), /*#__PURE__*/_jsxs(List, {
|
167
|
+
dense: true,
|
168
|
+
sx: {
|
169
|
+
py: 0,
|
170
|
+
pl: 2
|
171
|
+
},
|
172
|
+
children: [/*#__PURE__*/_jsxs(ListItem, {
|
173
|
+
sx: {
|
174
|
+
display: 'flex',
|
175
|
+
alignItems: 'center',
|
176
|
+
gap: 0.8
|
177
|
+
},
|
178
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
179
|
+
component: Icon,
|
180
|
+
icon: rocketLaunchRoundedIcon,
|
181
|
+
fontSize: 20,
|
182
|
+
sx: {
|
183
|
+
color: 'success.main'
|
184
|
+
}
|
185
|
+
}), t('afterAllow.list1')]
|
186
|
+
}), /*#__PURE__*/_jsxs(ListItem, {
|
187
|
+
sx: {
|
188
|
+
display: 'flex',
|
189
|
+
alignItems: 'center',
|
190
|
+
gap: 0.8
|
191
|
+
},
|
192
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
193
|
+
component: Icon,
|
194
|
+
icon: rocketLaunchRoundedIcon,
|
195
|
+
fontSize: 20,
|
196
|
+
sx: {
|
197
|
+
color: 'success.main'
|
198
|
+
}
|
199
|
+
}), t('afterAllow.list2')]
|
200
|
+
})]
|
201
|
+
})]
|
202
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
203
|
+
component: "div",
|
204
|
+
variant: "body2",
|
205
|
+
color: "grey.700",
|
206
|
+
children: t('dataUsage')
|
207
|
+
})]
|
208
|
+
}), /*#__PURE__*/_jsx(DIDConnectFooter, {
|
209
|
+
currentAppColor: currentAppColor
|
210
|
+
})]
|
211
|
+
});
|
212
|
+
}
|
package/lib/Theme/index.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { CreateMUIStyled, Theme } from '@mui/material';
|
2
|
-
import { useTheme } from '@mui/material
|
1
|
+
import type { CreateMUIStyled, Theme } from '@mui/material';
|
2
|
+
import { useTheme } from '@mui/material';
|
3
3
|
export * from './theme';
|
4
4
|
export { default as ThemeProvider } from './theme-provider';
|
5
5
|
export { useTheme };
|
package/lib/Theme/index.js
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
export function getCallbackAction(id, action) {
|
2
|
+
return `callback_${action}_${id}`;
|
3
|
+
}
|
4
|
+
|
5
|
+
// eslint-disable-next-line require-await
|
6
|
+
export async function callIframe(iframe, action) {
|
7
|
+
const callbackAction = getCallbackAction(iframe.dataset.id, action);
|
8
|
+
const promise = new Promise(resolve => {
|
9
|
+
const handleMessage = ({
|
10
|
+
data
|
11
|
+
}) => {
|
12
|
+
if (data.action === callbackAction) {
|
13
|
+
window.removeEventListener('message', handleMessage);
|
14
|
+
resolve(data);
|
15
|
+
}
|
16
|
+
};
|
17
|
+
window.addEventListener('message', handleMessage);
|
18
|
+
});
|
19
|
+
iframe?.contentWindow?.postMessage({
|
20
|
+
action,
|
21
|
+
callback: callbackAction
|
22
|
+
}, '*');
|
23
|
+
return promise;
|
24
|
+
}
|
package/lib/Util/index.d.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import Cookies from 'js-cookie';
|
1
2
|
import { type DeepmergeOptions } from '@mui/utils/deepmerge';
|
2
3
|
import type { $TSFixMe, Locale } from '../type';
|
3
4
|
declare let dateTool: $TSFixMe | null;
|
@@ -14,7 +15,7 @@ export declare function getCookieOptions(expireInDays?: number | {
|
|
14
15
|
returnDomain?: boolean;
|
15
16
|
sameSite?: Cookies.CookieAttributes['sameSite'];
|
16
17
|
secure?: boolean;
|
17
|
-
}):
|
18
|
+
}): Cookies.CookieAttributes;
|
18
19
|
export declare const getColor: (props: $TSFixMe) => any;
|
19
20
|
export declare const getBackground: (props: $TSFixMe) => any;
|
20
21
|
/**
|
@@ -76,6 +77,7 @@ export declare const sleep: (time?: number) => Promise<void>;
|
|
76
77
|
export declare const isUrl: (str: string) => boolean;
|
77
78
|
export declare const getVisitorId: () => string | null;
|
78
79
|
export declare const setVisitorId: (value: string | null) => void;
|
80
|
+
export declare const ensureVisitorId: () => void;
|
79
81
|
export declare const getDIDColor: (did: string) => any;
|
80
82
|
type NestedTranslation = {
|
81
83
|
[key: string]: string | NestedTranslation;
|
@@ -93,6 +95,13 @@ export declare const getTranslation: (translations: TranslationsObject, locale:
|
|
93
95
|
}) => string;
|
94
96
|
export declare const lazyRetry: (fn: () => Promise<any>) => import("react").LazyExoticComponent<import("react").ComponentType<any>>;
|
95
97
|
export declare const cleanedObj: (obj: object) => import("lodash").Dictionary<any>;
|
98
|
+
/**
|
99
|
+
* 将十六进制颜色转换为 RGBA
|
100
|
+
* @param hex 十六进制颜色字符串 (例如: "#FF0000" 或 "FF0000")
|
101
|
+
* @param alpha 透明度值 (0-1 之间,默认为 1)
|
102
|
+
* @returns RGBA 颜色字符串 (例如: "rgba(255, 0, 0, 1)")
|
103
|
+
*/
|
104
|
+
export declare function hexToRgba(hex: string, alpha?: number): string;
|
96
105
|
/**
|
97
106
|
* 依次对数组中的对象进行深度合并
|
98
107
|
* @param objects - 需要合并的对象数组
|
package/lib/Util/index.js
CHANGED
@@ -5,8 +5,11 @@ import { getDIDMotifInfo, colors } from '@arcblock/did-motif';
|
|
5
5
|
import isNil from 'lodash/isNil';
|
6
6
|
import omitBy from 'lodash/omitBy';
|
7
7
|
import pRetry from 'p-retry';
|
8
|
+
import Cookies from 'js-cookie';
|
9
|
+
import colorConvert from 'color-convert';
|
8
10
|
import deepmerge from '@mui/utils/deepmerge';
|
9
11
|
import { DID_PREFIX, BLOCKLET_SERVICE_PATH_PREFIX } from './constant';
|
12
|
+
import { getFederatedEnabled } from './federated';
|
10
13
|
let dateTool = null;
|
11
14
|
const IP_V4_REGEX = /^(\d{1,3}\.){3}\d{1,3}(:\d+)?$/;
|
12
15
|
// 常见顶级域名
|
@@ -360,15 +363,63 @@ export const sleep = (time = 0) => {
|
|
360
363
|
export const isUrl = str => {
|
361
364
|
return /^https?:\/\//.test(str);
|
362
365
|
};
|
363
|
-
const visitorIdKey = '
|
366
|
+
const visitorIdKey = 'vid';
|
367
|
+
const visitorIdKeyLegacy = '__visitor_id';
|
364
368
|
export const getVisitorId = () => {
|
365
|
-
|
369
|
+
// FIXME: @zhanghan 短期内做一个兼容,确保在 migrate 前的请求能够携带正确的 vid
|
370
|
+
return Cookies.get(visitorIdKey) || localStorage.getItem(visitorIdKeyLegacy);
|
366
371
|
};
|
367
372
|
export const setVisitorId = value => {
|
368
373
|
if (value === null) {
|
369
|
-
|
374
|
+
Cookies.remove(visitorIdKey, {
|
375
|
+
sameSite: 'None',
|
376
|
+
secure: true
|
377
|
+
});
|
370
378
|
} else {
|
371
|
-
|
379
|
+
Cookies.set(visitorIdKey, value, {
|
380
|
+
sameSite: 'None',
|
381
|
+
secure: true,
|
382
|
+
expires: 365
|
383
|
+
});
|
384
|
+
}
|
385
|
+
};
|
386
|
+
export const ensureVisitorId = () => {
|
387
|
+
let visitorId = localStorage.getItem(visitorIdKeyLegacy);
|
388
|
+
if (visitorId) {
|
389
|
+
localStorage.removeItem(visitorIdKeyLegacy);
|
390
|
+
setVisitorId(visitorId);
|
391
|
+
}
|
392
|
+
if (getVisitorId()) {
|
393
|
+
return;
|
394
|
+
}
|
395
|
+
if (!getFederatedEnabled()) {
|
396
|
+
try {
|
397
|
+
// 在支持 crypto.randomUUID 的环境中使用
|
398
|
+
if (window.crypto && typeof window.crypto.randomUUID === 'function') {
|
399
|
+
visitorId = window.crypto.randomUUID();
|
400
|
+
} else {
|
401
|
+
// 在不支持 crypto.randomUUID 的环境中生成随机 ID
|
402
|
+
const randomValues = new Uint8Array(16);
|
403
|
+
if (window.crypto && typeof window.crypto.getRandomValues === 'function') {
|
404
|
+
window.crypto.getRandomValues(randomValues);
|
405
|
+
} else {
|
406
|
+
// 降级方案:使用 Math.random 生成
|
407
|
+
for (let i = 0; i < 16; i++) {
|
408
|
+
randomValues[i] = Math.floor(Math.random() * 256);
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
// 转换为 UUID 格式
|
413
|
+
const hexArray = Array.from(randomValues).map(b => b.toString(16).padStart(2, '0'));
|
414
|
+
visitorId = [hexArray.slice(0, 4).join(''), hexArray.slice(4, 6).join(''), hexArray.slice(6, 8).join(''), hexArray.slice(8, 10).join(''), hexArray.slice(10, 16).join('')].join('-');
|
415
|
+
}
|
416
|
+
} catch (error) {
|
417
|
+
// 如果上述方法都失败,使用时间戳和随机数生成
|
418
|
+
visitorId = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
419
|
+
}
|
420
|
+
}
|
421
|
+
if (visitorId) {
|
422
|
+
setVisitorId(visitorId);
|
372
423
|
}
|
373
424
|
};
|
374
425
|
export const getDIDColor = did => {
|
@@ -429,6 +480,18 @@ export const cleanedObj = obj => {
|
|
429
480
|
return omitBy(obj, isNil);
|
430
481
|
};
|
431
482
|
|
483
|
+
/**
|
484
|
+
* 将十六进制颜色转换为 RGBA
|
485
|
+
* @param hex 十六进制颜色字符串 (例如: "#FF0000" 或 "FF0000")
|
486
|
+
* @param alpha 透明度值 (0-1 之间,默认为 1)
|
487
|
+
* @returns RGBA 颜色字符串 (例如: "rgba(255, 0, 0, 1)")
|
488
|
+
*/
|
489
|
+
export function hexToRgba(hex, alpha = 1) {
|
490
|
+
const [r, g, b] = colorConvert.hex.rgb(hex);
|
491
|
+
// 返回 RGBA 格式
|
492
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
493
|
+
}
|
494
|
+
|
432
495
|
/**
|
433
496
|
* 依次对数组中的对象进行深度合并
|
434
497
|
* @param objects - 需要合并的对象数组
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { type Breakpoint } from '@mui/material';
|
2
|
+
import { type ThemeOptions } from '@blocklet/theme';
|
3
|
+
export default function useBlockletLogo({ key, meta, theme: themeOverrides, square, }?: {
|
4
|
+
key?: number | Breakpoint;
|
5
|
+
meta?: any;
|
6
|
+
theme?: ThemeOptions;
|
7
|
+
square?: boolean;
|
8
|
+
}): any;
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { useCreation } from 'ahooks';
|
2
|
+
import { useTheme } from '../Theme';
|
3
|
+
import useMobile from './use-mobile';
|
4
|
+
export default function useBlockletLogo({
|
5
|
+
key = 'sm',
|
6
|
+
meta = {},
|
7
|
+
theme: themeOverrides = {},
|
8
|
+
square
|
9
|
+
} = {}) {
|
10
|
+
const isMobileDevice = useMobile({
|
11
|
+
key
|
12
|
+
});
|
13
|
+
const theme = useTheme();
|
14
|
+
const mode = useCreation(() => {
|
15
|
+
return themeOverrides?.palette?.mode || theme.palette.mode;
|
16
|
+
}, [theme, themeOverrides]);
|
17
|
+
const finalAppLogo = useCreation(() => {
|
18
|
+
const {
|
19
|
+
appLogo,
|
20
|
+
appLogoDark,
|
21
|
+
appLogoRect,
|
22
|
+
appLogoRectDark
|
23
|
+
} = Object.assign({}, window.blocklet ?? {}, meta);
|
24
|
+
const isDark = mode === 'dark';
|
25
|
+
const squareLogo = (isDark ? appLogoDark : appLogo) || appLogo;
|
26
|
+
// 深色模式尽可能优先使用深色图标
|
27
|
+
const rectLogo = (isDark ? appLogoRectDark || appLogoDark : appLogoRect) || appLogoRect;
|
28
|
+
return isMobileDevice || square ? squareLogo : rectLogo || squareLogo || '';
|
29
|
+
}, [mode, meta, isMobileDevice, square]);
|
30
|
+
return finalAppLogo;
|
31
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@arcblock/ux",
|
3
|
-
"version": "2.13.
|
3
|
+
"version": "2.13.15",
|
4
4
|
"description": "Common used react components for arcblock products",
|
5
5
|
"keywords": [
|
6
6
|
"react",
|
@@ -71,14 +71,14 @@
|
|
71
71
|
"react": ">=18.2.0",
|
72
72
|
"react-router-dom": ">=6.22.3"
|
73
73
|
},
|
74
|
-
"gitHead": "
|
74
|
+
"gitHead": "94d15cfb22e13272502bb40863c5b059cb13eab5",
|
75
75
|
"dependencies": {
|
76
76
|
"@arcblock/did-motif": "^1.1.13",
|
77
|
-
"@arcblock/icons": "^2.13.
|
78
|
-
"@arcblock/nft-display": "^2.13.
|
79
|
-
"@arcblock/react-hooks": "^2.13.
|
77
|
+
"@arcblock/icons": "^2.13.15",
|
78
|
+
"@arcblock/nft-display": "^2.13.15",
|
79
|
+
"@arcblock/react-hooks": "^2.13.15",
|
80
80
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
81
|
-
"@blocklet/theme": "^2.13.
|
81
|
+
"@blocklet/theme": "^2.13.15",
|
82
82
|
"@fontsource/roboto": "~5.1.1",
|
83
83
|
"@fontsource/ubuntu-mono": "^5.0.18",
|
84
84
|
"@iconify-icons/logos": "^1.2.36",
|
@@ -94,6 +94,7 @@
|
|
94
94
|
"awesome-phonenumber": "^7.4.0",
|
95
95
|
"axios": "^1.7.5",
|
96
96
|
"base64-url": "^2.3.3",
|
97
|
+
"color-convert": "^3.0.1",
|
97
98
|
"copy-to-clipboard": "^3.3.2",
|
98
99
|
"core-js": "^3.25.5",
|
99
100
|
"d3-geo": "^1.12.1",
|
@@ -80,7 +80,17 @@ const ResponsiveDidAddress = forwardRef<HTMLDidAddressElement, IResponsiveDidAdd
|
|
80
80
|
}, [containerWidth, addressFullWidth]);
|
81
81
|
|
82
82
|
return (
|
83
|
-
<Root
|
83
|
+
<Root
|
84
|
+
as={component}
|
85
|
+
ref={containerRef}
|
86
|
+
style={style}
|
87
|
+
className={className}
|
88
|
+
size={size}
|
89
|
+
{...(component === 'span'
|
90
|
+
? {}
|
91
|
+
: {
|
92
|
+
inline: rest.inline,
|
93
|
+
})}>
|
84
94
|
<StyledDidAddress
|
85
95
|
style={{
|
86
96
|
position: loading ? 'absolute' : 'static',
|
@@ -16,7 +16,7 @@ export default function ThemeModeToggle() {
|
|
16
16
|
|
17
17
|
return (
|
18
18
|
<IconButton onClick={toggleMode}>
|
19
|
-
{mode === 'light' ? <
|
19
|
+
{mode === 'light' ? <Brightness2OutlinedIcon /> : <LightModeOutlinedIcon />}
|
20
20
|
</IconButton>
|
21
21
|
);
|
22
22
|
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { useState } from 'react';
|
2
|
+
import { joinURL } from 'ufo';
|
3
|
+
import { SxProps } from '@mui/material';
|
4
|
+
|
5
|
+
import Img from '../Img';
|
6
|
+
import { isUrl } from '../Util';
|
7
|
+
import DidAvatar from '../Avatar';
|
8
|
+
|
9
|
+
type AppIconProps = {
|
10
|
+
appInfo: any;
|
11
|
+
size?: number;
|
12
|
+
sx?: SxProps;
|
13
|
+
};
|
14
|
+
|
15
|
+
export default function AppIcon({ appInfo, size = 32, ...rest }: AppIconProps) {
|
16
|
+
const [error, setError] = useState(false);
|
17
|
+
if (error || !(appInfo.appUrl || appInfo.appLogo)) {
|
18
|
+
return <DidAvatar did={appInfo.appPid} size={size} />;
|
19
|
+
}
|
20
|
+
|
21
|
+
let logoUrl = appInfo.appLogo || '';
|
22
|
+
if (!isUrl(logoUrl)) {
|
23
|
+
logoUrl = joinURL(appInfo.appUrl || '', logoUrl);
|
24
|
+
}
|
25
|
+
|
26
|
+
return (
|
27
|
+
<Img
|
28
|
+
src={logoUrl}
|
29
|
+
alt={appInfo.appName || 'Blocklet Icon'}
|
30
|
+
width={size}
|
31
|
+
height={size}
|
32
|
+
{...rest}
|
33
|
+
onError={() => setError(true)}
|
34
|
+
/>
|
35
|
+
);
|
36
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import { Box, IconButton, SxProps, Tooltip, useMediaQuery } from '@mui/material';
|
2
|
+
import CheckIcon from '@iconify-icons/material-symbols/check';
|
3
|
+
import { Icon } from '@iconify/react';
|
4
|
+
|
5
|
+
import DID from '../DID';
|
6
|
+
import { mergeSx } from '../Util/style';
|
7
|
+
import AppIcon from './app-icon';
|
8
|
+
|
9
|
+
export default function AppInfoItem({
|
10
|
+
appInfo,
|
11
|
+
active = false,
|
12
|
+
appLogo = null,
|
13
|
+
sx,
|
14
|
+
}: {
|
15
|
+
appInfo: any;
|
16
|
+
active?: boolean;
|
17
|
+
appLogo?: React.ReactNode;
|
18
|
+
sx?: SxProps;
|
19
|
+
}) {
|
20
|
+
const isTinyView = useMediaQuery('(max-width:400px)');
|
21
|
+
|
22
|
+
return (
|
23
|
+
<Box
|
24
|
+
sx={mergeSx(
|
25
|
+
{
|
26
|
+
display: 'flex',
|
27
|
+
alignItems: 'center',
|
28
|
+
fontWeight: 600,
|
29
|
+
color: 'text.primary',
|
30
|
+
|
31
|
+
'& .app-info-content': {
|
32
|
+
paddingLeft: '8px',
|
33
|
+
overflow: 'hidden',
|
34
|
+
},
|
35
|
+
|
36
|
+
'& .app-info-name': {
|
37
|
+
maxWidth: '100%',
|
38
|
+
lineHeight: 'normal',
|
39
|
+
whiteSpace: 'nowrap',
|
40
|
+
overflow: 'hidden',
|
41
|
+
textOverflow: 'ellipsis',
|
42
|
+
fontSize: '12px',
|
43
|
+
color: 'text.primary',
|
44
|
+
},
|
45
|
+
},
|
46
|
+
sx
|
47
|
+
)}>
|
48
|
+
{appLogo || (
|
49
|
+
<Box
|
50
|
+
sx={{
|
51
|
+
borderRadius: 1,
|
52
|
+
overflow: 'hidden',
|
53
|
+
fontSize: 0,
|
54
|
+
}}>
|
55
|
+
<AppIcon appInfo={appInfo} />
|
56
|
+
</Box>
|
57
|
+
)}
|
58
|
+
|
59
|
+
<Box className="app-info-content">
|
60
|
+
<Tooltip title={appInfo.appName} placement="top">
|
61
|
+
<Box className="app-info-name">{appInfo.appName}</Box>
|
62
|
+
</Tooltip>
|
63
|
+
{appInfo.appPid && (
|
64
|
+
<DID
|
65
|
+
className="app-info-did"
|
66
|
+
did={appInfo.appPid}
|
67
|
+
sx={{ fontSize: '10px !important' }}
|
68
|
+
copyable={false}
|
69
|
+
startChars={isTinyView ? 6 : 8}
|
70
|
+
endChars={isTinyView ? 6 : 8}
|
71
|
+
size={12}
|
72
|
+
/>
|
73
|
+
)}
|
74
|
+
</Box>
|
75
|
+
{active ? (
|
76
|
+
<IconButton size="small" color="success">
|
77
|
+
<Icon icon={CheckIcon} color="success" />
|
78
|
+
</IconButton>
|
79
|
+
) : null}
|
80
|
+
</Box>
|
81
|
+
);
|
82
|
+
}
|