@arcblock/ux 3.4.15 → 3.5.1
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/package.json.js +1 -1
- package/package.json +10 -7
- package/src/ActionButton/ActionButton.stories.jsx +0 -61
- package/src/ActionButton/index.jsx +0 -106
- package/src/ActivityIndicator/ActivityIndicator.stories.jsx +0 -9
- package/src/ActivityIndicator/index.jsx +0 -140
- package/src/Address/Address.stories.jsx +0 -38
- package/src/Address/compact-text.jsx +0 -76
- package/src/Address/did-address.tsx +0 -223
- package/src/Address/index.tsx +0 -21
- package/src/Address/responsive-did-address.tsx +0 -154
- package/src/Alert/Alert.stories.jsx +0 -100
- package/src/Alert/index.jsx +0 -130
- package/src/AnimationWaiter/AnimationWaiter.stories.jsx +0 -35
- package/src/AnimationWaiter/dark-animation.json +0 -1
- package/src/AnimationWaiter/default-animation.json +0 -1
- package/src/AnimationWaiter/index.jsx +0 -296
- package/src/Async/index.tsx +0 -44
- package/src/Avatar/Avatar.stories.jsx +0 -11
- package/src/Avatar/did-motif.jsx +0 -38
- package/src/Avatar/etherscan-blockies.js +0 -81
- package/src/Avatar/index.jsx +0 -195
- package/src/Badge/Badge.stories.jsx +0 -41
- package/src/Badge/index.jsx +0 -101
- package/src/Blocklet/Blocklet.stories.jsx +0 -21
- package/src/Blocklet/blocklet.jsx +0 -276
- package/src/Blocklet/index.js +0 -5
- package/src/Blocklet/utils.jsx +0 -58
- package/src/BlockletContext/index.tsx +0 -72
- package/src/BlockletNFT/BlockletNFT.stories.jsx +0 -21
- package/src/BlockletNFT/index.jsx +0 -378
- package/src/BlockletV2/Blocklet.stories.jsx +0 -34
- package/src/BlockletV2/blocklet.tsx +0 -247
- package/src/BlockletV2/components/icon-text.tsx +0 -47
- package/src/BlockletV2/components/tooltip-icon.tsx +0 -52
- package/src/BlockletV2/index.ts +0 -6
- package/src/BlockletV2/utils.js +0 -75
- package/src/Button/Button.stories.jsx +0 -24
- package/src/Button/index.js +0 -9
- package/src/Button/wrap.jsx +0 -126
- package/src/ButtonGroup/index.js +0 -16
- package/src/CardSelector/index.tsx +0 -136
- package/src/Center/Center.stories.jsx +0 -20
- package/src/Center/index.tsx +0 -33
- package/src/ClickToCopy/ClickToCopy.stories.jsx +0 -24
- package/src/ClickToCopy/copy-button.tsx +0 -43
- package/src/ClickToCopy/hook.ts +0 -42
- package/src/ClickToCopy/index.tsx +0 -96
- package/src/CloseButton/index.tsx +0 -37
- package/src/CodeBlock/CodeBlock.stories.jsx +0 -22
- package/src/CodeBlock/LightBox.tsx +0 -87
- package/src/CodeBlock/index.tsx +0 -217
- package/src/Colors/Colors.stories.jsx +0 -211
- package/src/Colors/index.ts +0 -4
- package/src/Colors/themes/default.ts +0 -8
- package/src/Colors/themes/did-connect.ts +0 -64
- package/src/Colors/themes/temp.ts +0 -52
- package/src/Config/Config.stories.jsx +0 -16
- package/src/Config/config-provider.tsx +0 -62
- package/src/Config/index.ts +0 -2
- package/src/Config/theme-mode-toggle.tsx +0 -38
- package/src/ContactForm/ContactForm.stories.jsx +0 -32
- package/src/ContactForm/index.tsx +0 -264
- package/src/CookieConsent/CookieConsent.stories.jsx +0 -33
- package/src/CookieConsent/index.tsx +0 -104
- package/src/CountDown/CountDown.stories.jsx +0 -15
- package/src/CountDown/index.tsx +0 -170
- package/src/DID/DID.stories.jsx +0 -37
- package/src/DID/index.tsx +0 -393
- package/src/DIDConnect/app-icon.tsx +0 -37
- package/src/DIDConnect/app-info-item.tsx +0 -93
- package/src/DIDConnect/auth-apps/auth-apps-info.tsx +0 -77
- package/src/DIDConnect/auth-apps/index.tsx +0 -278
- package/src/DIDConnect/auth-apps/switch-role.tsx +0 -47
- package/src/DIDConnect/did-connect-container.tsx +0 -326
- package/src/DIDConnect/did-connect-footer.tsx +0 -76
- package/src/DIDConnect/did-connect-logo.tsx +0 -8
- package/src/DIDConnect/icons/did-wallet-logo.tsx +0 -18
- package/src/DIDConnect/icons/github-logo.tsx +0 -17
- package/src/DIDConnect/index.ts +0 -11
- package/src/DIDConnect/landing-page.tsx +0 -218
- package/src/DIDConnect/powered-by.tsx +0 -48
- package/src/DIDConnect/provider-icon.tsx +0 -62
- package/src/DIDConnect/request-storage-access-api-dialog.tsx +0 -304
- package/src/DIDConnect/with-container.tsx +0 -323
- package/src/DIDConnect/with-ux-theme.tsx +0 -22
- package/src/DIDLogo/Logo.stories.jsx +0 -11
- package/src/DIDLogo/index.tsx +0 -168
- package/src/Datatable/CustomToolbar.jsx +0 -415
- package/src/Datatable/Datatable.stories.jsx +0 -92
- package/src/Datatable/DatatableContext.jsx +0 -35
- package/src/Datatable/TableSearch.jsx +0 -166
- package/src/Datatable/index.jsx +0 -652
- package/src/Datatable/utils.js +0 -161
- package/src/Dialog/Dialog.stories.jsx +0 -21
- package/src/Dialog/confirm.jsx +0 -143
- package/src/Dialog/dialog.jsx +0 -199
- package/src/Dialog/index.js +0 -4
- package/src/Dialog/types.d.ts +0 -20
- package/src/Dialog/use-confirm.jsx +0 -188
- package/src/DriftBot/index.tsx +0 -81
- package/src/Earth/Earth.stories.jsx +0 -39
- package/src/Earth/countries.json +0 -8057
- package/src/Earth/index.tsx +0 -515
- package/src/Earth/util.ts +0 -72
- package/src/Empty/Empty.stories.jsx +0 -23
- package/src/Empty/index.jsx +0 -48
- package/src/ErrorBoundary/ErrorBoundary.stories.jsx +0 -13
- package/src/ErrorBoundary/fallback.tsx +0 -85
- package/src/ErrorBoundary/index.ts +0 -1
- package/src/Footer/Footer.stories.jsx +0 -13
- package/src/Footer/index.tsx +0 -130
- package/src/Header/Header.stories.jsx +0 -30
- package/src/Header/addon-button.tsx +0 -41
- package/src/Header/auto-hidden.tsx +0 -31
- package/src/Header/header-addons.tsx +0 -37
- package/src/Header/header.tsx +0 -214
- package/src/Header/index.ts +0 -3
- package/src/Header/responsive-header.tsx +0 -145
- package/src/Icon/Icon.stories.jsx +0 -45
- package/src/Icon/image.tsx +0 -53
- package/src/Icon/index.tsx +0 -63
- package/src/Img/Img.stories.jsx +0 -17
- package/src/Img/index.jsx +0 -258
- package/src/InfoRow/InfoRow.stories.jsx +0 -14
- package/src/InfoRow/index.tsx +0 -91
- package/src/Layout/Layout.stories.jsx +0 -24
- package/src/Layout/dashboard/external-link.tsx +0 -59
- package/src/Layout/dashboard/full-page.tsx +0 -58
- package/src/Layout/dashboard/index.tsx +0 -260
- package/src/Layout/dashboard/sidebar.tsx +0 -198
- package/src/Layout/dashboard-legacy/header.tsx +0 -156
- package/src/Layout/dashboard-legacy/index.tsx +0 -127
- package/src/Layout/dashboard-legacy/sidebar.tsx +0 -129
- package/src/Layout/index.tsx +0 -310
- package/src/LoadingMask/index.tsx +0 -108
- package/src/Locale/LocaleSelector.stories.jsx +0 -44
- package/src/Locale/browser-lang.ts +0 -65
- package/src/Locale/context.tsx +0 -162
- package/src/Locale/languages.ts +0 -58
- package/src/Locale/selector.tsx +0 -174
- package/src/Locale/util.ts +0 -38
- package/src/Logo/Logo.stories.jsx +0 -23
- package/src/Logo/images/logo-dark-text.svg +0 -3
- package/src/Logo/images/logo-dark-top.svg +0 -6
- package/src/Logo/images/logo-light-text.svg +0 -3
- package/src/Logo/images/logo-light-top.svg +0 -6
- package/src/Logo/index.tsx +0 -58
- package/src/Metric/Metric.stories.jsx +0 -29
- package/src/Metric/index.tsx +0 -130
- package/src/MuiWrap/index.tsx +0 -10
- package/src/NFTDisplay/NFTBroken.svg +0 -34
- package/src/NFTDisplay/NFTDisplay.stories.jsx +0 -30
- package/src/NFTDisplay/README.md +0 -59
- package/src/NFTDisplay/aspect-ratio-container.tsx +0 -36
- package/src/NFTDisplay/broken.tsx +0 -51
- package/src/NFTDisplay/displayApi.ts +0 -43
- package/src/NFTDisplay/index.tsx +0 -393
- package/src/NFTDisplay/loading.tsx +0 -16
- package/src/NFTDisplay/preview.tsx +0 -84
- package/src/NFTDisplay/render-svg.tsx +0 -21
- package/src/NFTDisplay/svg-embedder/img.tsx +0 -27
- package/src/NFTDisplay/svg-embedder/inline-svg.tsx +0 -36
- package/src/NavMenu/NavMenu.stories.jsx +0 -17
- package/src/NavMenu/images/OCAP.svg +0 -1
- package/src/NavMenu/images/abt-network.svg +0 -1
- package/src/NavMenu/images/ai-kit.svg +0 -1
- package/src/NavMenu/images/aigne-image-smith.svg +0 -1
- package/src/NavMenu/images/aigne.svg +0 -1
- package/src/NavMenu/images/aistro.png +0 -0
- package/src/NavMenu/images/arcsphere.svg +0 -1
- package/src/NavMenu/images/blocklet-framework.svg +0 -1
- package/src/NavMenu/images/blocklet-launcher.svg +0 -1
- package/src/NavMenu/images/blocklet-server.svg +0 -1
- package/src/NavMenu/images/blocklet-store.svg +0 -1
- package/src/NavMenu/images/creator-studio.svg +0 -1
- package/src/NavMenu/images/did-wallet.svg +0 -1
- package/src/NavMenu/images/did.svg +0 -1
- package/src/NavMenu/images/nft-studio.svg +0 -1
- package/src/NavMenu/images/payment-kit.png +0 -0
- package/src/NavMenu/images/vc.svg +0 -1
- package/src/NavMenu/images/web3-kit.svg +0 -1
- package/src/NavMenu/index.ts +0 -3
- package/src/NavMenu/nav-menu-context.tsx +0 -30
- package/src/NavMenu/nav-menu.tsx +0 -441
- package/src/NavMenu/products.tsx +0 -830
- package/src/NavMenu/style.ts +0 -258
- package/src/NavMenu/sub-container.tsx +0 -125
- package/src/NavMenu/sub-item-group.tsx +0 -42
- package/src/OrgTransfer/index.tsx +0 -53
- package/src/OrgTransfer/locales.ts +0 -25
- package/src/OrgTransfer/selector.tsx +0 -252
- package/src/OrgTransfer/type.ts +0 -31
- package/src/PageScroller/index.tsx +0 -316
- package/src/PageScroller/story/FifthComponent.jsx +0 -7
- package/src/PageScroller/story/FirstComponent.jsx +0 -7
- package/src/PageScroller/story/FourthComponent.jsx +0 -7
- package/src/PageScroller/story/FullPage.jsx +0 -55
- package/src/PageScroller/story/PageContain.jsx +0 -59
- package/src/PageScroller/story/PageScroller.stories.jsx +0 -18
- package/src/PageScroller/story/SecondComponent.jsx +0 -7
- package/src/PageScroller/story/ThirdComponent.jsx +0 -7
- package/src/PageScroller/story/index.css +0 -115
- package/src/PageScroller/usePrevValue.ts +0 -11
- package/src/Passport/index.ts +0 -3
- package/src/Passport/passport.tsx +0 -118
- package/src/PhoneInput/PhoneInput.stories.jsx +0 -12
- package/src/PhoneInput/country-select.tsx +0 -148
- package/src/PhoneInput/index.tsx +0 -269
- package/src/PoweredByArcBlock/index.tsx +0 -27
- package/src/PricingTable/PricingPlan.tsx +0 -120
- package/src/PricingTable/PricingTable.stories.jsx +0 -38
- package/src/PricingTable/index.tsx +0 -59
- package/src/QRCode/QRCode.stories.jsx +0 -13
- package/src/QRCode/index.tsx +0 -66
- package/src/RelativeTime/RelativeTime.stories.jsx +0 -20
- package/src/RelativeTime/index.tsx +0 -334
- package/src/Result/Result.stories.jsx +0 -61
- package/src/Result/common.tsx +0 -119
- package/src/Result/index.tsx +0 -30
- package/src/Result/result.tsx +0 -65
- package/src/Result/translations.ts +0 -57
- package/src/Screenshot/BaseScreenshot/index.tsx +0 -73
- package/src/Screenshot/BaseScreenshot/shells/Macbook.tsx +0 -38
- package/src/Screenshot/BaseScreenshot/shells/Phone.tsx +0 -35
- package/src/Screenshot/Screenshot.stories.jsx +0 -44
- package/src/Screenshot/devices.css +0 -1366
- package/src/Screenshot/index.tsx +0 -300
- package/src/SessionBlocklet/index.tsx +0 -178
- package/src/SessionManager/SessionManager.stories.jsx +0 -9
- package/src/SessionManager/index.tsx +0 -3
- package/src/SessionPermission/index.tsx +0 -26
- package/src/SessionUser/components/did-space.tsx +0 -68
- package/src/SessionUser/components/logged-in.tsx +0 -338
- package/src/SessionUser/components/quick-login-item.tsx +0 -132
- package/src/SessionUser/components/session-user-item.tsx +0 -93
- package/src/SessionUser/components/session-user-switch.tsx +0 -240
- package/src/SessionUser/components/un-login.tsx +0 -257
- package/src/SessionUser/components/user-info.tsx +0 -201
- package/src/SessionUser/index.tsx +0 -68
- package/src/SessionUser/libs/translation.ts +0 -30
- package/src/SessionUser/libs/utils.ts +0 -39
- package/src/SharedBridge/index.tsx +0 -126
- package/src/SocialShare/index.tsx +0 -194
- package/src/Sparkline/Sparkline.stories.jsx +0 -13
- package/src/Sparkline/index.tsx +0 -231
- package/src/Spinner/Spinner.stories.jsx +0 -98
- package/src/Spinner/index.tsx +0 -20
- package/src/SplitButton/SplitButton.stories.jsx +0 -32
- package/src/SplitButton/index.tsx +0 -116
- package/src/SplitButton/useClickAway.tsx +0 -24
- package/src/Success/index.tsx +0 -175
- package/src/Switch/Switch.stories.jsx +0 -16
- package/src/Switch/index.jsx +0 -79
- package/src/Tabs/Tabs.stories.jsx +0 -18
- package/src/Tabs/index.tsx +0 -255
- package/src/Tag/Tag.stories.jsx +0 -15
- package/src/Tag/index.jsx +0 -106
- package/src/TextCollapse/TextCollapse.stories.jsx +0 -73
- package/src/TextCollapse/index.tsx +0 -85
- package/src/Theme/Theme.stories.jsx +0 -11
- package/src/Theme/index.ts +0 -21
- package/src/Theme/theme-provider.tsx +0 -374
- package/src/Theme/theme.ts +0 -229
- package/src/Toast/Toast.stories.jsx +0 -28
- package/src/Toast/index.tsx +0 -80
- package/src/Typography/index.tsx +0 -124
- package/src/UserCard/Cards/avatar-only.tsx +0 -27
- package/src/UserCard/Cards/basic-info.tsx +0 -43
- package/src/UserCard/Cards/index.tsx +0 -16
- package/src/UserCard/Cards/social-actions.tsx +0 -196
- package/src/UserCard/Container/card.tsx +0 -63
- package/src/UserCard/Container/dialog.tsx +0 -37
- package/src/UserCard/Content/basic.tsx +0 -330
- package/src/UserCard/Content/clock.tsx +0 -82
- package/src/UserCard/Content/minimal.tsx +0 -113
- package/src/UserCard/Content/shorten-label.tsx +0 -32
- package/src/UserCard/Content/tooltip-avatar.tsx +0 -80
- package/src/UserCard/UserCard.stories.jsx +0 -19
- package/src/UserCard/components.tsx +0 -81
- package/src/UserCard/index.tsx +0 -132
- package/src/UserCard/types.ts +0 -165
- package/src/UserCard/use-follow.tsx +0 -111
- package/src/UserCard/utils.ts +0 -155
- package/src/Util/WebWalletOpener.stories.jsx +0 -5
- package/src/Util/client.ts +0 -4
- package/src/Util/constant.ts +0 -70
- package/src/Util/deprecate.tsx +0 -29
- package/src/Util/federated.ts +0 -125
- package/src/Util/iframe.ts +0 -19
- package/src/Util/index.ts +0 -760
- package/src/Util/logger.ts +0 -44
- package/src/Util/passport.ts +0 -127
- package/src/Util/security.ts +0 -72
- package/src/Util/style.ts +0 -17
- package/src/Util/wallet.ts +0 -35
- package/src/VerificationCode/index.tsx +0 -83
- package/src/Video/Video.stories.jsx +0 -6
- package/src/Video/index.tsx +0 -70
- package/src/Wallet/Action.stories.jsx +0 -8
- package/src/Wallet/Action.tsx +0 -118
- package/src/Wallet/Download.stories.jsx +0 -9
- package/src/Wallet/Download.tsx +0 -157
- package/src/Wallet/Open.tsx +0 -47
- package/src/Wallet/OpenInWallet.stories.jsx +0 -5
- package/src/Wallet/images/abtwallet.png +0 -0
- package/src/Wallet/images/android_download.svg +0 -22
- package/src/Wallet/images/app-store.svg +0 -30
- package/src/Wallet/images/google-play.svg +0 -69
- package/src/WalletOSIcon/index.tsx +0 -47
- package/src/WebWalletSWKeeper/index.tsx +0 -117
- package/src/WechatPrompt/images/android.png +0 -0
- package/src/WechatPrompt/images/ios.png +0 -0
- package/src/WechatPrompt/index.tsx +0 -75
- package/src/global.d.ts +0 -28
- package/src/hooks/use-blocklet-logo.tsx +0 -32
- package/src/hooks/use-clock.tsx +0 -62
- package/src/hooks/use-location-state.tsx +0 -117
- package/src/hooks/use-mobile.tsx +0 -6
- package/src/index.ts +0 -79
- package/src/type.d.ts +0 -44
- package/src/withTheme/index.tsx +0 -72
- package/src/withTracker/README.md +0 -37
- package/src/withTracker/action/bind-wallet.tsx +0 -17
- package/src/withTracker/action/login.tsx +0 -18
- package/src/withTracker/action/pay.tsx +0 -14
- package/src/withTracker/action/switch-passport.tsx +0 -20
- package/src/withTracker/constant/index.tsx +0 -3
- package/src/withTracker/env.tsx +0 -1
- package/src/withTracker/error_boundary.jsx +0 -34
- package/src/withTracker/index.tsx +0 -50
- package/src/withTracker/libs/utm.ts +0 -46
- package/vite.config.mjs +0 -37
package/src/Util/index.ts
DELETED
|
@@ -1,760 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-bitwise */
|
|
2
|
-
import { lazy } from 'react';
|
|
3
|
-
import padStart from 'lodash/padStart';
|
|
4
|
-
import { getDIDMotifInfo, colors } from '@arcblock/did-motif';
|
|
5
|
-
import { mergeAllThemeOptions } from '@blocklet/theme';
|
|
6
|
-
import isNil from 'lodash/isNil';
|
|
7
|
-
import omitBy from 'lodash/omitBy';
|
|
8
|
-
import mergeWith from 'lodash/mergeWith';
|
|
9
|
-
import pRetry from 'p-retry';
|
|
10
|
-
import Cookies from 'js-cookie';
|
|
11
|
-
import colorConvert from 'color-convert';
|
|
12
|
-
import dayjs from 'dayjs';
|
|
13
|
-
import 'dayjs/locale/zh-cn';
|
|
14
|
-
import utc from 'dayjs/plugin/utc';
|
|
15
|
-
import timezone from 'dayjs/plugin/timezone';
|
|
16
|
-
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
17
|
-
import updateLocale from 'dayjs/plugin/updateLocale';
|
|
18
|
-
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
|
19
|
-
import type { AxiosError } from 'axios';
|
|
20
|
-
import semver from 'semver';
|
|
21
|
-
|
|
22
|
-
import { DID_PREFIX, BLOCKLET_SERVICE_PATH_PREFIX } from './constant';
|
|
23
|
-
import pkg from '../../package.json';
|
|
24
|
-
import type { $TSFixMe, Locale } from '../type';
|
|
25
|
-
import { getFederatedEnabled } from './federated';
|
|
26
|
-
|
|
27
|
-
let dateTool: $TSFixMe | null = null;
|
|
28
|
-
const IP_V4_REGEX = /^(\d{1,3}\.){3}\d{1,3}(:\d+)?$/;
|
|
29
|
-
// 常见顶级域名
|
|
30
|
-
const commonSLDs = new Set(['co', 'com', 'net', 'org', 'gov', 'edu', 'ac']);
|
|
31
|
-
// 常见国家域名
|
|
32
|
-
const commonCcTLDs = new Set(['uk', 'au', 'cn', 'nz', 'za', 'in', 'br', 'mx', 'fr', 'it', 'ca']);
|
|
33
|
-
|
|
34
|
-
/** @deprecated for compatibility, please use `import { mergeAllThemeOptions } from '@blocklet/theme'` instead */
|
|
35
|
-
export { mergeAllThemeOptions as deepmergeAll };
|
|
36
|
-
|
|
37
|
-
/** 是否常见二段式顶级域名 */
|
|
38
|
-
export function isTwoSegmentTLD(domain: string) {
|
|
39
|
-
if (!domain) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const parts = domain.split('.');
|
|
44
|
-
|
|
45
|
-
if (parts.length < 2) return false;
|
|
46
|
-
|
|
47
|
-
const sld = parts[parts.length - 2];
|
|
48
|
-
const tld = parts[parts.length - 1];
|
|
49
|
-
|
|
50
|
-
return commonSLDs.has(sld) && commonCcTLDs.has(tld);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** 获取根域名 */
|
|
54
|
-
export function resolveRootDomain() {
|
|
55
|
-
const { host } = window.location;
|
|
56
|
-
|
|
57
|
-
if (!host) {
|
|
58
|
-
return '';
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (IP_V4_REGEX.test(host)) {
|
|
62
|
-
return '';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 移除可能存在的端口号
|
|
66
|
-
const hostWithoutPort = host.split(':')[0];
|
|
67
|
-
const parts = hostWithoutPort.split('.');
|
|
68
|
-
|
|
69
|
-
if (parts.length === 1) {
|
|
70
|
-
return '';
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// 二段式顶级域名
|
|
74
|
-
if (parts.length > 2) {
|
|
75
|
-
const tld = parts.slice(-2).join('.');
|
|
76
|
-
|
|
77
|
-
if (isTwoSegmentTLD(tld)) {
|
|
78
|
-
return `.${parts.slice(-3).join('.')}`;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return `.${parts.slice(-2).join('.')}`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function parseQuery(str: string) {
|
|
86
|
-
return str
|
|
87
|
-
.replace(/^\?/, '')
|
|
88
|
-
.split('&')
|
|
89
|
-
.map((x) => x.split('='))
|
|
90
|
-
.filter(([key]) => !!key)
|
|
91
|
-
.reduce<Record<string, string | boolean>>((memo, x) => {
|
|
92
|
-
const key = x[0];
|
|
93
|
-
const value = decodeURIComponent(x[1]) || true;
|
|
94
|
-
memo[key] = value;
|
|
95
|
-
return memo;
|
|
96
|
-
}, {});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function stringifyQuery(params = {}) {
|
|
100
|
-
return new URLSearchParams(params).toString();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function getCookieOptions(
|
|
104
|
-
expireInDays:
|
|
105
|
-
| number
|
|
106
|
-
| {
|
|
107
|
-
expireInDays: number;
|
|
108
|
-
path?: string;
|
|
109
|
-
domain?: string;
|
|
110
|
-
returnDomain?: boolean;
|
|
111
|
-
sameSite?: Cookies.CookieAttributes['sameSite'];
|
|
112
|
-
secure?: boolean;
|
|
113
|
-
} = 1
|
|
114
|
-
) {
|
|
115
|
-
let opts = expireInDays;
|
|
116
|
-
|
|
117
|
-
if (typeof opts === 'number') {
|
|
118
|
-
opts = { expireInDays: opts };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (opts.path === undefined) {
|
|
122
|
-
opts.path = '/';
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (!opts.expireInDays) {
|
|
126
|
-
opts.expireInDays = 1;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const options: Cookies.CookieAttributes = {
|
|
130
|
-
expires: opts.expireInDays,
|
|
131
|
-
path: opts.path,
|
|
132
|
-
domain: opts.domain || '',
|
|
133
|
-
sameSite: opts.sameSite || 'Lax',
|
|
134
|
-
// 允许自定义设置为 false,默认是 true
|
|
135
|
-
secure: opts.secure !== false,
|
|
136
|
-
};
|
|
137
|
-
if (typeof window === 'undefined' || opts.domain || opts.returnDomain === false) {
|
|
138
|
-
if (opts.returnDomain === false) {
|
|
139
|
-
delete options.domain;
|
|
140
|
-
}
|
|
141
|
-
return options;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return options;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export const getColor = (props: $TSFixMe) => {
|
|
148
|
-
if (props.color) {
|
|
149
|
-
return props.color;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (props.dark) {
|
|
153
|
-
return props.theme.palette.common.white;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return props.theme.palette.text.primary;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
export const getBackground = (props: $TSFixMe) => {
|
|
160
|
-
if (props.background) {
|
|
161
|
-
return props.background;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (props.dark) {
|
|
165
|
-
return props.theme.palette.common.black;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return props.theme.palette.common.white;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* 1. 将 props 中以 ::prop:: 开头的字符串替换为 component.defaultProps 中的值
|
|
173
|
-
* 2. 将 props 中由 jsonAttrs 指定的 json 字符串转换为对象
|
|
174
|
-
* 3. 最后将 props 中的 ::prop:: 字符串替换为 ''
|
|
175
|
-
*/
|
|
176
|
-
export function mergeProps<P extends object>(
|
|
177
|
-
props: Record<string, any>,
|
|
178
|
-
component: React.ComponentType<P>,
|
|
179
|
-
jsonAttrs: string[] = []
|
|
180
|
-
) {
|
|
181
|
-
const newProps = Object.assign({}, props);
|
|
182
|
-
const defaultProps = (component as any).defaultProps || {};
|
|
183
|
-
Object.keys(defaultProps).forEach((x) => {
|
|
184
|
-
if (typeof newProps[x] === 'string' && newProps[x].indexOf('::prop::') === 0) {
|
|
185
|
-
newProps[x] = defaultProps[x];
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
if (Array.isArray(jsonAttrs)) {
|
|
190
|
-
jsonAttrs.forEach((x) => {
|
|
191
|
-
if (typeof newProps[x] === 'string') {
|
|
192
|
-
try {
|
|
193
|
-
newProps[x] = JSON.parse(newProps[x]);
|
|
194
|
-
} catch (err) {
|
|
195
|
-
// Do nothing
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
Object.keys(newProps).forEach((x) => {
|
|
202
|
-
if (typeof newProps[x] === 'string' && newProps[x].indexOf('::prop::') === 0) {
|
|
203
|
-
newProps[x] = '';
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
return newProps;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export function getCopyright(startYear = 2017) {
|
|
211
|
-
const currentYear = new Date().getFullYear();
|
|
212
|
-
return `${currentYear}` === `${startYear}`
|
|
213
|
-
? `© ArcBlock ${currentYear}`
|
|
214
|
-
: `© ArcBlock ${startYear} - ${currentYear}`;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export const getTimezone = () => {
|
|
218
|
-
if (
|
|
219
|
-
typeof Intl === 'object' &&
|
|
220
|
-
typeof Intl.DateTimeFormat === 'function' &&
|
|
221
|
-
typeof Intl.DateTimeFormat().resolvedOptions === 'function'
|
|
222
|
-
) {
|
|
223
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return '';
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
export const str2color = (str: string) => {
|
|
230
|
-
let hash = 0;
|
|
231
|
-
for (let i = 0; i < str.length; i++) {
|
|
232
|
-
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
233
|
-
}
|
|
234
|
-
let colour = '#';
|
|
235
|
-
for (let j = 0; j < 3; j++) {
|
|
236
|
-
const value = (hash >> (j * 8)) & 0xff;
|
|
237
|
-
colour += `00${value.toString(16)}`.substr(-2);
|
|
238
|
-
}
|
|
239
|
-
return colour;
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
export const formatUptime = (uptime: number) => {
|
|
243
|
-
const total = Math.round(uptime / 1000);
|
|
244
|
-
const hours = Math.floor(total / 3600);
|
|
245
|
-
const minutes = Math.floor((total - hours * 3600) / 60);
|
|
246
|
-
const seconds = total % 60;
|
|
247
|
-
// @ts-expect-error
|
|
248
|
-
return `${padStart(hours, 2, '0')}:${padStart(minutes, 2, '0')}:${padStart(seconds, 2, '0')}`;
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Set the date tool library which support for format() and locale() functions,
|
|
253
|
-
* moment and dayjs are recommended.
|
|
254
|
-
*/
|
|
255
|
-
export function setDateTool(tool: typeof dateTool) {
|
|
256
|
-
dateTool = tool;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
export function getDateTool() {
|
|
260
|
-
return dateTool;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const createDateFormatter =
|
|
264
|
-
(format: string) =>
|
|
265
|
-
(date: string | number | Date, { locale, tz, isUtc }: { locale?: Locale; tz?: string; isUtc?: boolean } = {}) => {
|
|
266
|
-
if (dateTool === null) {
|
|
267
|
-
// 作为默认的 dateTool 使用
|
|
268
|
-
dayjs.extend(localizedFormat);
|
|
269
|
-
dayjs.extend(utc);
|
|
270
|
-
dayjs.extend(timezone);
|
|
271
|
-
dayjs.extend(updateLocale);
|
|
272
|
-
dayjs.extend(relativeTime);
|
|
273
|
-
dayjs.updateLocale('zh-cn', {
|
|
274
|
-
// copy with https://github.com/iamkun/dayjs/blob/dev/src/locale/zh-cn.js
|
|
275
|
-
relativeTime: {
|
|
276
|
-
future: '%s后',
|
|
277
|
-
past: '%s前',
|
|
278
|
-
s: '几秒',
|
|
279
|
-
m: '1 分钟',
|
|
280
|
-
mm: '%d 分钟',
|
|
281
|
-
h: '1 小时',
|
|
282
|
-
hh: '%d 小时',
|
|
283
|
-
d: '1 天',
|
|
284
|
-
dd: '%d 天',
|
|
285
|
-
M: '1 个月',
|
|
286
|
-
MM: '%d 个月',
|
|
287
|
-
y: '1 年',
|
|
288
|
-
yy: '%d 年',
|
|
289
|
-
},
|
|
290
|
-
});
|
|
291
|
-
setDateTool(dayjs);
|
|
292
|
-
// throw new Error('call setDateTool to set the date tool library, such as: setDateTool(dayjs)');
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (isNil(date) || date === '') {
|
|
296
|
-
return '-';
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
let instance = dateTool(date);
|
|
300
|
-
|
|
301
|
-
if (tz) {
|
|
302
|
-
instance = instance.tz(tz);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (isUtc) {
|
|
306
|
-
instance = instance.utc();
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (typeof locale !== 'undefined') {
|
|
310
|
-
instance = instance.locale(locale);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return instance.format(format);
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Format the time string as `ll` format: MMM D, YYYY
|
|
318
|
-
* Ensure that the setDateTool() function is called first to set the time tool library.
|
|
319
|
-
* @returns formatted date string
|
|
320
|
-
*/
|
|
321
|
-
export function formatToDate(
|
|
322
|
-
date: string | number | Date,
|
|
323
|
-
{ locale = 'en', tz }: { locale?: Locale; tz?: string } = {}
|
|
324
|
-
) {
|
|
325
|
-
return createDateFormatter('ll')(date, { locale, tz });
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Format the time string as `lll` format: MMM D, YYYY h:mm A
|
|
330
|
-
* Ensure that the setDateTool() function is called first to set the time tool library.
|
|
331
|
-
* @returns formatted date string
|
|
332
|
-
*/
|
|
333
|
-
export function formatToDatetime(
|
|
334
|
-
date: string | number | Date,
|
|
335
|
-
{
|
|
336
|
-
locale = 'en',
|
|
337
|
-
tz,
|
|
338
|
-
isUtc = false,
|
|
339
|
-
format = 'lll',
|
|
340
|
-
}: { locale?: Locale; tz?: string; isUtc?: boolean; format?: string } = {}
|
|
341
|
-
) {
|
|
342
|
-
return createDateFormatter(format)(date, { locale, tz, isUtc });
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
export function detectWalletExtension() {
|
|
346
|
-
// @ts-expect-error Property 'ABT_DEV' does not exist on type 'Window & typeof globalThis'.
|
|
347
|
-
const extension = window?.ABT_DEV || window.ABT;
|
|
348
|
-
if (extension && typeof extension.open === 'function') {
|
|
349
|
-
return extension;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export function openWebWallet({
|
|
356
|
-
webWalletUrl,
|
|
357
|
-
action = 'login',
|
|
358
|
-
locale = 'en',
|
|
359
|
-
url,
|
|
360
|
-
windowFeatures,
|
|
361
|
-
appInfo,
|
|
362
|
-
memberAppInfo,
|
|
363
|
-
}: {
|
|
364
|
-
webWalletUrl: string;
|
|
365
|
-
action?: string;
|
|
366
|
-
locale?: Locale;
|
|
367
|
-
url: string;
|
|
368
|
-
windowFeatures: $TSFixMe;
|
|
369
|
-
appInfo: $TSFixMe;
|
|
370
|
-
memberAppInfo: $TSFixMe;
|
|
371
|
-
}) {
|
|
372
|
-
// web wallet extension
|
|
373
|
-
const extension = detectWalletExtension();
|
|
374
|
-
if (extension) {
|
|
375
|
-
extension.open({
|
|
376
|
-
action,
|
|
377
|
-
locale,
|
|
378
|
-
url: encodeURIComponent(url),
|
|
379
|
-
appInfo: {
|
|
380
|
-
...appInfo,
|
|
381
|
-
},
|
|
382
|
-
memberAppInfo: {
|
|
383
|
-
...memberAppInfo,
|
|
384
|
-
},
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
return { type: 'extension' };
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const defaultWindowFeatures = {
|
|
391
|
-
toolbar: 'no',
|
|
392
|
-
location: 'no',
|
|
393
|
-
status: 'no',
|
|
394
|
-
menubar: 'no',
|
|
395
|
-
scrollbars: 'yes',
|
|
396
|
-
resizable: 'yes',
|
|
397
|
-
// iphone 8plus size
|
|
398
|
-
width: 414,
|
|
399
|
-
height: 736,
|
|
400
|
-
};
|
|
401
|
-
const windowUrl = `${webWalletUrl}?action=${action}&locale=${locale}&url=${encodeURIComponent(url)}`;
|
|
402
|
-
const mergedWindowFeatures = Object.assign({}, defaultWindowFeatures, windowFeatures);
|
|
403
|
-
const getWindowWidth = (win: Window) => {
|
|
404
|
-
return win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth;
|
|
405
|
-
};
|
|
406
|
-
// 默认在浏览器右上角弹出窗口
|
|
407
|
-
if (!('left' in mergedWindowFeatures)) {
|
|
408
|
-
const winWidth = getWindowWidth(window.top || window);
|
|
409
|
-
const winLeft = window.screenLeft || window.screenX;
|
|
410
|
-
mergedWindowFeatures.left = winWidth + winLeft - mergedWindowFeatures.width;
|
|
411
|
-
}
|
|
412
|
-
if (!('top' in mergedWindowFeatures)) {
|
|
413
|
-
const winTop = window.screenTop || window.screenY;
|
|
414
|
-
mergedWindowFeatures.top = winTop;
|
|
415
|
-
}
|
|
416
|
-
const strWindowFeatures = Object.keys(mergedWindowFeatures)
|
|
417
|
-
.map((key) => `${key}=${mergedWindowFeatures[key]}`)
|
|
418
|
-
.join(',');
|
|
419
|
-
// 这里打开的是钱包的 URL,是安全的
|
|
420
|
-
window.open(windowUrl, 'targetWindow', strWindowFeatures);
|
|
421
|
-
return { type: 'web' };
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
export const getFontSize = (size: string | number) => {
|
|
425
|
-
// 12px 及以上的 size 有效, 否则返回 inherit
|
|
426
|
-
if (size && Number(size) >= 12) {
|
|
427
|
-
return `${Number(size)}px`;
|
|
428
|
-
}
|
|
429
|
-
return 'inherit';
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
// 参考: asset-chain @arcblock/did
|
|
433
|
-
export const isEthereumDid = (did: string) => {
|
|
434
|
-
const address = did.replace(DID_PREFIX, '');
|
|
435
|
-
// check if it has the basic requirements of an address
|
|
436
|
-
if (!/^(0x)?[0-9a-f]{40}$/i.test(address)) {
|
|
437
|
-
return false;
|
|
438
|
-
}
|
|
439
|
-
return true;
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
export const appendParams = (
|
|
443
|
-
url: string,
|
|
444
|
-
params: {
|
|
445
|
-
imageFilter: 'crop' | 'resize';
|
|
446
|
-
w?: number;
|
|
447
|
-
h?: number;
|
|
448
|
-
r?: 0 | 90 | 180 | 270;
|
|
449
|
-
}
|
|
450
|
-
) => {
|
|
451
|
-
if (!params) {
|
|
452
|
-
return url;
|
|
453
|
-
}
|
|
454
|
-
try {
|
|
455
|
-
// HACK: 如果 url 中带有域名,则 urlInstance.origin 为 url 中的域名;否则,借用当前页面的 location.origin 作为域名来拼接一个 url
|
|
456
|
-
const urlInstance = new URL(url, window.location.origin);
|
|
457
|
-
Object.keys(params).forEach((key) => {
|
|
458
|
-
urlInstance.searchParams.set(key, String(params[key as keyof typeof params]));
|
|
459
|
-
});
|
|
460
|
-
// HACK: 如果前后域名一致,代表前面已经借用了 location.origin,这个时候只需要返回 urlInstance.pathname + urlInstance.search 即可
|
|
461
|
-
if (urlInstance.origin === window.location.origin) {
|
|
462
|
-
return urlInstance.pathname + urlInstance.search;
|
|
463
|
-
}
|
|
464
|
-
return urlInstance.href;
|
|
465
|
-
} catch {
|
|
466
|
-
return url;
|
|
467
|
-
}
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
export const getUserAvatar = (avatar: string, size = 48) => {
|
|
471
|
-
if (!avatar) {
|
|
472
|
-
return avatar;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (avatar.indexOf(BLOCKLET_SERVICE_PATH_PREFIX) >= 0) {
|
|
476
|
-
return appendParams(avatar, {
|
|
477
|
-
imageFilter: 'resize',
|
|
478
|
-
w: size,
|
|
479
|
-
h: size,
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
return avatar;
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
export const sleep = (time = 0) => {
|
|
487
|
-
return new Promise<void>((resolve) => {
|
|
488
|
-
setTimeout(() => {
|
|
489
|
-
resolve();
|
|
490
|
-
}, time);
|
|
491
|
-
});
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
export const isUrl = (str: string) => {
|
|
495
|
-
return /^https?:\/\//.test(str);
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
const visitorIdKey = 'vid';
|
|
499
|
-
const visitorIdKeyLegacy = '__visitor_id';
|
|
500
|
-
|
|
501
|
-
export const getVisitorId = () => {
|
|
502
|
-
// FIXME: @zhanghan 短期内做一个兼容,确保在 migrate 前的请求能够携带正确的 vid
|
|
503
|
-
return Cookies.get(visitorIdKey) || localStorage.getItem(visitorIdKeyLegacy);
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
export const setVisitorId = (value: string | null) => {
|
|
507
|
-
if (value === null) {
|
|
508
|
-
Cookies.remove(visitorIdKey, {
|
|
509
|
-
sameSite: 'None',
|
|
510
|
-
secure: true,
|
|
511
|
-
});
|
|
512
|
-
} else {
|
|
513
|
-
Cookies.set(visitorIdKey, value, {
|
|
514
|
-
sameSite: 'None',
|
|
515
|
-
secure: true,
|
|
516
|
-
expires: 365,
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
export const ensureVisitorId = () => {
|
|
522
|
-
let visitorId = localStorage.getItem(visitorIdKeyLegacy);
|
|
523
|
-
if (visitorId) {
|
|
524
|
-
localStorage.removeItem(visitorIdKeyLegacy);
|
|
525
|
-
setVisitorId(visitorId);
|
|
526
|
-
}
|
|
527
|
-
if (getVisitorId()) {
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (!getFederatedEnabled()) {
|
|
532
|
-
try {
|
|
533
|
-
// 在支持 crypto.randomUUID 的环境中使用
|
|
534
|
-
if (window.crypto && typeof window.crypto.randomUUID === 'function') {
|
|
535
|
-
visitorId = window.crypto.randomUUID();
|
|
536
|
-
} else {
|
|
537
|
-
// 在不支持 crypto.randomUUID 的环境中生成随机 ID
|
|
538
|
-
const randomValues = new Uint8Array(16);
|
|
539
|
-
if (window.crypto && typeof window.crypto.getRandomValues === 'function') {
|
|
540
|
-
window.crypto.getRandomValues(randomValues);
|
|
541
|
-
} else {
|
|
542
|
-
// 降级方案:使用 Math.random 生成
|
|
543
|
-
for (let i = 0; i < 16; i++) {
|
|
544
|
-
randomValues[i] = Math.floor(Math.random() * 256);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// 转换为 UUID 格式
|
|
549
|
-
const hexArray = Array.from(randomValues).map((b) => b.toString(16).padStart(2, '0'));
|
|
550
|
-
visitorId = [
|
|
551
|
-
hexArray.slice(0, 4).join(''),
|
|
552
|
-
hexArray.slice(4, 6).join(''),
|
|
553
|
-
hexArray.slice(6, 8).join(''),
|
|
554
|
-
hexArray.slice(8, 10).join(''),
|
|
555
|
-
hexArray.slice(10, 16).join(''),
|
|
556
|
-
].join('-');
|
|
557
|
-
}
|
|
558
|
-
} catch (error) {
|
|
559
|
-
// 如果上述方法都失败,使用时间戳和随机数生成
|
|
560
|
-
visitorId = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
if (visitorId) {
|
|
565
|
-
setVisitorId(visitorId);
|
|
566
|
-
}
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
export const getDIDColor = (did: string) => {
|
|
570
|
-
if (isEthereumDid(did)) {
|
|
571
|
-
const index =
|
|
572
|
-
Uint8Array.from(
|
|
573
|
-
did
|
|
574
|
-
.slice(2)
|
|
575
|
-
.match(/.{1,2}/g)!
|
|
576
|
-
.map((pair) => parseInt(pair, 16))
|
|
577
|
-
)
|
|
578
|
-
.slice(0, 8)
|
|
579
|
-
.reduce((acc, val) => acc + val, 0) % colors.length;
|
|
580
|
-
|
|
581
|
-
return colors[index];
|
|
582
|
-
}
|
|
583
|
-
try {
|
|
584
|
-
const didMotifInfo = getDIDMotifInfo(did);
|
|
585
|
-
return didMotifInfo?.color;
|
|
586
|
-
} catch {
|
|
587
|
-
return null;
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
|
|
591
|
-
type NestedTranslation = {
|
|
592
|
-
[key: string]: string | NestedTranslation;
|
|
593
|
-
};
|
|
594
|
-
|
|
595
|
-
type TranslationsObject = {
|
|
596
|
-
[locale: string]: NestedTranslation;
|
|
597
|
-
};
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* Retrieves the appropriate translation based on the locale, with fallback options.
|
|
601
|
-
* @return {string} The translated string based on the locale, with fallback options if necessary.
|
|
602
|
-
*/
|
|
603
|
-
export const getTranslation = (
|
|
604
|
-
translations: TranslationsObject,
|
|
605
|
-
locale: Locale,
|
|
606
|
-
options: { fallbackLocale?: Locale; defaultValue?: string } = {}
|
|
607
|
-
) => {
|
|
608
|
-
const { fallbackLocale = 'en', defaultValue = 'unknown' } = options;
|
|
609
|
-
|
|
610
|
-
if (typeof translations === 'string') {
|
|
611
|
-
return translations;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
let translation;
|
|
615
|
-
if (locale) {
|
|
616
|
-
translation = translations[locale];
|
|
617
|
-
}
|
|
618
|
-
if (!translation || typeof translation !== 'string') {
|
|
619
|
-
translation = translations[fallbackLocale];
|
|
620
|
-
}
|
|
621
|
-
if (!translation || typeof translation !== 'string') {
|
|
622
|
-
translation = defaultValue;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
return translation;
|
|
626
|
-
};
|
|
627
|
-
|
|
628
|
-
export const lazyRetry = (fn: () => Promise<any>) =>
|
|
629
|
-
lazy(() =>
|
|
630
|
-
pRetry(
|
|
631
|
-
async () => {
|
|
632
|
-
try {
|
|
633
|
-
return await fn();
|
|
634
|
-
} catch (error: unknown) {
|
|
635
|
-
// HACK: pRetry 不会对 TypeError 的错误进行重试,手动放行了部分 network error 的错误,但此处的错误是经过 react-router 包装过的,不适用于上述的判断,所以这里需要特殊逻辑来进行处理
|
|
636
|
-
if (error instanceof TypeError && !error.message.includes('Failed to fetch')) {
|
|
637
|
-
throw error;
|
|
638
|
-
}
|
|
639
|
-
if (error instanceof Error) {
|
|
640
|
-
throw new Error(error.message);
|
|
641
|
-
}
|
|
642
|
-
throw new Error('Unknown error');
|
|
643
|
-
}
|
|
644
|
-
},
|
|
645
|
-
// 只需要重试两次,加上原本的一次,总共三次
|
|
646
|
-
{ retries: 2 }
|
|
647
|
-
)
|
|
648
|
-
);
|
|
649
|
-
|
|
650
|
-
export const cleanedObj = (obj: object) => {
|
|
651
|
-
return omitBy(obj, isNil);
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
/**
|
|
655
|
-
* 将十六进制颜色转换为 RGBA
|
|
656
|
-
* @param hex 十六进制颜色字符串 (例如: "#FF0000" 或 "FF0000")
|
|
657
|
-
* @param alpha 透明度值 (0-1 之间,默认为 1)
|
|
658
|
-
* @returns RGBA 颜色字符串 (例如: "rgba(255, 0, 0, 1)")
|
|
659
|
-
*/
|
|
660
|
-
export function hexToRgba(hex: string, alpha = 1) {
|
|
661
|
-
const [r, g, b] = colorConvert.hex.rgb(hex);
|
|
662
|
-
// 返回 RGBA 格式
|
|
663
|
-
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
// 获取 server 的版本号
|
|
667
|
-
export const getServerVersion = () => {
|
|
668
|
-
return window.blocklet?.serverVersion || window.env?.serverVersion || '';
|
|
669
|
-
};
|
|
670
|
-
|
|
671
|
-
// 获取 UX 包版本号
|
|
672
|
-
export const getUxPackageVersion = () => {
|
|
673
|
-
return pkg.version || '';
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
export const getJsSdkVersion = () => {
|
|
677
|
-
// 从 package.json 的 dependencies 中获取 @blocklet/js-sdk 的版本
|
|
678
|
-
const jsSdkVersion = pkg.dependencies?.['@blocklet/js-sdk'];
|
|
679
|
-
if (!jsSdkVersion) {
|
|
680
|
-
return '';
|
|
681
|
-
}
|
|
682
|
-
// 移除版本前缀符号 (^, ~, >=, 等)
|
|
683
|
-
return jsSdkVersion.replace(/^[\^~>=<]+/, '');
|
|
684
|
-
};
|
|
685
|
-
|
|
686
|
-
/**
|
|
687
|
-
* 比较两个版本号,version1 是否大于等于 version2
|
|
688
|
-
* @param {*} version1
|
|
689
|
-
* @param {*} version2
|
|
690
|
-
* @returns boolean
|
|
691
|
-
*/
|
|
692
|
-
export const compareVersions = (version1: string, version2: string): boolean => {
|
|
693
|
-
const getDateVersion = (version: string) => {
|
|
694
|
-
const match = version.match(/^(\d+\.\d+\.\d+(?:-[^-]+?-\d{8}))/);
|
|
695
|
-
return match ? match[1] : version;
|
|
696
|
-
};
|
|
697
|
-
// 如果版本号为空,返回 false
|
|
698
|
-
if (!version1 || !version2) {
|
|
699
|
-
return false;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
const dateVersion1 = getDateVersion(version1);
|
|
703
|
-
const dateVersion2 = getDateVersion(version2);
|
|
704
|
-
|
|
705
|
-
// 如果基础版本相同,但完整版本不同(意味着有额外部分),返回false
|
|
706
|
-
if (dateVersion1 === dateVersion2 && version1 !== version2) {
|
|
707
|
-
return false;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
try {
|
|
711
|
-
// 其他情况正常比较
|
|
712
|
-
return semver.gte(dateVersion1, dateVersion2);
|
|
713
|
-
} catch {
|
|
714
|
-
return false;
|
|
715
|
-
}
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
/**
|
|
719
|
-
* 是否支持用户的 follow 关系
|
|
720
|
-
* 通过 server 的版本和 ux 的版本共同决定
|
|
721
|
-
*/
|
|
722
|
-
export const isSupportFollow = () => {
|
|
723
|
-
// HACK: 本地开发时,为了测试方便,暂时放开限制
|
|
724
|
-
if (process.env.NODE_ENV === 'development') {
|
|
725
|
-
return true;
|
|
726
|
-
}
|
|
727
|
-
const serverVersion = getServerVersion();
|
|
728
|
-
const uxVersion = getUxPackageVersion();
|
|
729
|
-
const jsSdkVersion = getJsSdkVersion();
|
|
730
|
-
|
|
731
|
-
if (!serverVersion || !uxVersion || !jsSdkVersion) {
|
|
732
|
-
return false;
|
|
733
|
-
}
|
|
734
|
-
// UX 包支持
|
|
735
|
-
const uxVersionSupport = compareVersions(uxVersion, '3.1.29');
|
|
736
|
-
// 服务端接口实现支持
|
|
737
|
-
const serverVersionSupport = compareVersions(serverVersion, '1.16.49-beta-20250822-070545-6d3344cc');
|
|
738
|
-
// SDK 接口实现支持
|
|
739
|
-
const jsSdkVersionSupport = compareVersions(jsSdkVersion, '1.16.49-beta-20250822-070545-6d3344cc');
|
|
740
|
-
return uxVersionSupport && serverVersionSupport && jsSdkVersionSupport;
|
|
741
|
-
};
|
|
742
|
-
|
|
743
|
-
export const formatAxiosError = (err: AxiosError) => {
|
|
744
|
-
const { response } = err;
|
|
745
|
-
|
|
746
|
-
if (response) {
|
|
747
|
-
return `Request failed: ${response.status} ${response.statusText}: ${JSON.stringify(response.data)}`;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
return err.message || 'Unknown error occurred';
|
|
751
|
-
};
|
|
752
|
-
|
|
753
|
-
export const mergeIgnoreEmpty = (...objects: Array<Record<string, any>>) => {
|
|
754
|
-
return mergeWith({}, ...objects, (objValue: any, srcValue: any) => {
|
|
755
|
-
if (srcValue === '' || srcValue === null || srcValue === undefined) {
|
|
756
|
-
return objValue; // 保留前面的值
|
|
757
|
-
}
|
|
758
|
-
return srcValue; // 使用后面的值
|
|
759
|
-
});
|
|
760
|
-
};
|