@blocklet/ui-react 3.4.15 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/org-switch/use-org.d.ts +4 -4
- package/package.json +9 -6
- package/.aigne/doc-smith/.local/afs-storage.sqlite3 +0 -0
- package/.aigne/doc-smith/config.yaml +0 -78
- package/.aigne/doc-smith/history.yaml +0 -14
- package/.aigne/doc-smith/media-description.yaml +0 -11
- package/.aigne/doc-smith/output/structure-plan.json +0 -255
- package/.aigne/doc-smith/translation-cache.yaml +0 -11
- package/.aigne/doc-smith/upload-cache.yaml +0 -528
- package/build.config.ts +0 -24
- package/docs/_sidebar.md +0 -19
- package/docs/assets/diagram/component-installer-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/component-installer-diagram-0.jpg +0 -0
- package/docs/assets/diagram/component-installer-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/component-installer-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/component-management-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/component-management-diagram-0.jpg +0 -0
- package/docs/assets/diagram/component-management-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/component-management-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/core-concepts-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/core-concepts-diagram-0.jpg +0 -0
- package/docs/assets/diagram/core-concepts-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/core-concepts-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/dashboard-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/dashboard-diagram-0.jpg +0 -0
- package/docs/assets/diagram/dashboard-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/dashboard-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/header-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/header-diagram-0.jpg +0 -0
- package/docs/assets/diagram/header-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/header-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/layout-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/layout-diagram-0.jpg +0 -0
- package/docs/assets/diagram/layout-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/layout-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/notifications-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/notifications-diagram-0.jpg +0 -0
- package/docs/assets/diagram/notifications-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/notifications-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/overview-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/overview-diagram-0.jpg +0 -0
- package/docs/assets/diagram/overview-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/overview-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/user-center-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/user-center-diagram-0.jpg +0 -0
- package/docs/assets/diagram/user-center-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/user-center-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/user-management-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/user-management-diagram-0.jpg +0 -0
- package/docs/assets/diagram/user-management-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/user-management-diagram-0.zh.jpg +0 -0
- package/docs/assets/diagram/user-sessions-diagram-0.ja.jpg +0 -0
- package/docs/assets/diagram/user-sessions-diagram-0.jpg +0 -0
- package/docs/assets/diagram/user-sessions-diagram-0.zh-TW.jpg +0 -0
- package/docs/assets/diagram/user-sessions-diagram-0.zh.jpg +0 -0
- package/docs/components-component-management-blocklet-studio.ja.md +0 -194
- package/docs/components-component-management-blocklet-studio.md +0 -194
- package/docs/components-component-management-blocklet-studio.zh-TW.md +0 -194
- package/docs/components-component-management-blocklet-studio.zh.md +0 -194
- package/docs/components-component-management-component-installer.ja.md +0 -182
- package/docs/components-component-management-component-installer.md +0 -182
- package/docs/components-component-management-component-installer.zh-TW.md +0 -182
- package/docs/components-component-management-component-installer.zh.md +0 -182
- package/docs/components-component-management.ja.md +0 -30
- package/docs/components-component-management.md +0 -30
- package/docs/components-component-management.zh-TW.md +0 -30
- package/docs/components-component-management.zh.md +0 -30
- package/docs/components-layout-dashboard.ja.md +0 -185
- package/docs/components-layout-dashboard.md +0 -187
- package/docs/components-layout-dashboard.zh-TW.md +0 -185
- package/docs/components-layout-dashboard.zh.md +0 -185
- package/docs/components-layout-footer.ja.md +0 -165
- package/docs/components-layout-footer.md +0 -165
- package/docs/components-layout-footer.zh-TW.md +0 -165
- package/docs/components-layout-footer.zh.md +0 -165
- package/docs/components-layout-header.ja.md +0 -183
- package/docs/components-layout-header.md +0 -183
- package/docs/components-layout-header.zh-TW.md +0 -183
- package/docs/components-layout-header.zh.md +0 -183
- package/docs/components-layout.ja.md +0 -31
- package/docs/components-layout.md +0 -31
- package/docs/components-layout.zh-TW.md +0 -31
- package/docs/components-layout.zh.md +0 -31
- package/docs/components-notifications.ja.md +0 -125
- package/docs/components-notifications.md +0 -125
- package/docs/components-notifications.zh-TW.md +0 -125
- package/docs/components-notifications.zh.md +0 -125
- package/docs/components-user-management-user-center.ja.md +0 -148
- package/docs/components-user-management-user-center.md +0 -147
- package/docs/components-user-management-user-center.zh-TW.md +0 -148
- package/docs/components-user-management-user-center.zh.md +0 -148
- package/docs/components-user-management-user-sessions.ja.md +0 -121
- package/docs/components-user-management-user-sessions.md +0 -123
- package/docs/components-user-management-user-sessions.zh-TW.md +0 -121
- package/docs/components-user-management-user-sessions.zh.md +0 -121
- package/docs/components-user-management.ja.md +0 -49
- package/docs/components-user-management.md +0 -51
- package/docs/components-user-management.zh-TW.md +0 -49
- package/docs/components-user-management.zh.md +0 -49
- package/docs/components-utilities-icon.ja.md +0 -106
- package/docs/components-utilities-icon.md +0 -106
- package/docs/components-utilities-icon.zh-TW.md +0 -106
- package/docs/components-utilities-icon.zh.md +0 -106
- package/docs/components-utilities.ja.md +0 -136
- package/docs/components-utilities.md +0 -136
- package/docs/components-utilities.zh-TW.md +0 -136
- package/docs/components-utilities.zh.md +0 -136
- package/docs/components.ja.md +0 -27
- package/docs/components.md +0 -27
- package/docs/components.zh-TW.md +0 -27
- package/docs/components.zh.md +0 -27
- package/docs/core-concepts.ja.md +0 -134
- package/docs/core-concepts.md +0 -135
- package/docs/core-concepts.zh-TW.md +0 -134
- package/docs/core-concepts.zh.md +0 -134
- package/docs/getting-started.ja.md +0 -132
- package/docs/getting-started.md +0 -132
- package/docs/getting-started.zh-TW.md +0 -132
- package/docs/getting-started.zh.md +0 -132
- package/docs/hooks-api.ja.md +0 -214
- package/docs/hooks-api.md +0 -214
- package/docs/hooks-api.zh-TW.md +0 -214
- package/docs/hooks-api.zh.md +0 -214
- package/docs/how-to-guides.ja.md +0 -413
- package/docs/how-to-guides.md +0 -413
- package/docs/how-to-guides.zh-TW.md +0 -413
- package/docs/how-to-guides.zh.md +0 -413
- package/docs/overview.ja.md +0 -51
- package/docs/overview.md +0 -51
- package/docs/overview.zh-TW.md +0 -51
- package/docs/overview.zh.md +0 -51
- package/glossary.md +0 -12
- package/src/@types/index.ts +0 -230
- package/src/@types/shims.d.ts +0 -18
- package/src/BlockletStudio/README.md +0 -116
- package/src/BlockletStudio/index.tsx +0 -145
- package/src/ComponentInstaller/ComponentInstaller.stories.jsx +0 -16
- package/src/ComponentInstaller/index.jsx +0 -207
- package/src/ComponentInstaller/installer-item.jsx +0 -129
- package/src/ComponentInstaller/locales.js +0 -22
- package/src/ComponentInstaller/use-component-installed.js +0 -88
- package/src/ComponentManager/components/add-component.tsx +0 -136
- package/src/ComponentManager/components/check-component.tsx +0 -3
- package/src/ComponentManager/components/publish-component.tsx +0 -90
- package/src/ComponentManager/components/resource-dialog.tsx +0 -91
- package/src/ComponentManager/index.tsx +0 -3
- package/src/ComponentManager/libs/locales.ts +0 -15
- package/src/Dashboard/Dashboard.stories.jsx +0 -20
- package/src/Dashboard/app-shell/app-badge.stories.tsx +0 -64
- package/src/Dashboard/app-shell/app-badge.tsx +0 -94
- package/src/Dashboard/app-shell/app-header.tsx +0 -104
- package/src/Dashboard/app-shell/app-info-context.tsx +0 -182
- package/src/Dashboard/app-shell/badges/app-badge-default.tsx +0 -130
- package/src/Dashboard/app-shell/badges/app-badge-did.tsx +0 -28
- package/src/Dashboard/app-shell/badges/app-badge-state.tsx +0 -40
- package/src/Dashboard/app-shell/badges/app-badge-switch.tsx +0 -72
- package/src/Dashboard/app-shell/badges/app-badge-version.tsx +0 -60
- package/src/Dashboard/app-shell/index.ts +0 -5
- package/src/Dashboard/index.jsx +0 -184
- package/src/Footer/Footer.stories.jsx +0 -33
- package/src/Footer/brand.jsx +0 -81
- package/src/Footer/copyright.jsx +0 -22
- package/src/Footer/index.jsx +0 -111
- package/src/Footer/internal-footer.jsx +0 -139
- package/src/Footer/layout/plain.jsx +0 -55
- package/src/Footer/layout/row.jsx +0 -43
- package/src/Footer/layout/standard.jsx +0 -114
- package/src/Footer/links.jsx +0 -321
- package/src/Footer/social-media.jsx +0 -55
- package/src/Header/Header.stories.jsx +0 -30
- package/src/Header/index.tsx +0 -259
- package/src/Icon/Icon.stories.jsx +0 -12
- package/src/Icon/index.tsx +0 -87
- package/src/Notifications/Snackbar.tsx +0 -261
- package/src/Notifications/hooks/use-title.tsx +0 -254
- package/src/Notifications/hooks/use-width.tsx +0 -16
- package/src/Notifications/utils.ts +0 -246
- package/src/UserCenter/assets/banner.png +0 -0
- package/src/UserCenter/components/config-inviter.tsx +0 -48
- package/src/UserCenter/components/config-profile.tsx +0 -99
- package/src/UserCenter/components/danger-zone.tsx +0 -82
- package/src/UserCenter/components/editable-field.tsx +0 -273
- package/src/UserCenter/components/fallback.tsx +0 -57
- package/src/UserCenter/components/nft-preview.tsx +0 -84
- package/src/UserCenter/components/nft.tsx +0 -279
- package/src/UserCenter/components/notification.tsx +0 -319
- package/src/UserCenter/components/passport.tsx +0 -107
- package/src/UserCenter/components/privacy.tsx +0 -120
- package/src/UserCenter/components/settings.tsx +0 -170
- package/src/UserCenter/components/status-dialog/date-picker.tsx +0 -77
- package/src/UserCenter/components/status-dialog/index.tsx +0 -293
- package/src/UserCenter/components/status-selector/duration-menu.tsx +0 -90
- package/src/UserCenter/components/status-selector/index.tsx +0 -58
- package/src/UserCenter/components/status-selector/menu-item.tsx +0 -56
- package/src/UserCenter/components/storage/action.tsx +0 -49
- package/src/UserCenter/components/storage/connected.tsx +0 -61
- package/src/UserCenter/components/storage/delete.tsx +0 -72
- package/src/UserCenter/components/storage/disconnect.tsx +0 -40
- package/src/UserCenter/components/storage/icons/empty-spaces-nft.svg +0 -1
- package/src/UserCenter/components/storage/icons/long-arrow.svg +0 -5
- package/src/UserCenter/components/storage/icons/space-connected.svg +0 -3
- package/src/UserCenter/components/storage/icons/space-disconnect.svg +0 -3
- package/src/UserCenter/components/storage/index.tsx +0 -41
- package/src/UserCenter/components/storage/preview-nft.tsx +0 -72
- package/src/UserCenter/components/third-party-login/index.tsx +0 -199
- package/src/UserCenter/components/third-party-login/third-party-item.tsx +0 -296
- package/src/UserCenter/components/user-center.tsx +0 -787
- package/src/UserCenter/components/user-info/address.tsx +0 -143
- package/src/UserCenter/components/user-info/index.tsx +0 -4
- package/src/UserCenter/components/user-info/link-preview-input.tsx +0 -274
- package/src/UserCenter/components/user-info/metadata.tsx +0 -658
- package/src/UserCenter/components/user-info/social-actions/chat.tsx +0 -43
- package/src/UserCenter/components/user-info/social-actions/follow.tsx +0 -23
- package/src/UserCenter/components/user-info/social-actions/index.tsx +0 -17
- package/src/UserCenter/components/user-info/switch-role.tsx +0 -42
- package/src/UserCenter/components/user-info/timezone-select.tsx +0 -119
- package/src/UserCenter/components/user-info/user-basic-info.tsx +0 -292
- package/src/UserCenter/components/user-info/user-info-item.tsx +0 -54
- package/src/UserCenter/components/user-info/user-info.tsx +0 -91
- package/src/UserCenter/components/user-info/user-status.tsx +0 -234
- package/src/UserCenter/components/user-info/utils.ts +0 -320
- package/src/UserCenter/components/webhook-item.tsx +0 -248
- package/src/UserCenter/index.tsx +0 -1
- package/src/UserCenter/libs/locales.ts +0 -378
- package/src/UserCenter/libs/utils.ts +0 -30
- package/src/UserSessions/components/user-session-info.tsx +0 -78
- package/src/UserSessions/components/user-sessions.tsx +0 -545
- package/src/UserSessions/index.tsx +0 -1
- package/src/UserSessions/libs/locales.ts +0 -60
- package/src/UserSessions/libs/utils.ts +0 -82
- package/src/blocklets.js +0 -195
- package/src/common/domain-warning.jsx +0 -178
- package/src/common/header-addons.jsx +0 -119
- package/src/common/link-blocker.jsx +0 -20
- package/src/common/notification-addon.jsx +0 -135
- package/src/common/org-switch/avatar-uploader.jsx +0 -271
- package/src/common/org-switch/create.jsx +0 -267
- package/src/common/org-switch/index.jsx +0 -407
- package/src/common/org-switch/locales.js +0 -52
- package/src/common/org-switch/use-org.jsx +0 -79
- package/src/common/overridable-theme-provider.jsx +0 -17
- package/src/common/wallet-hidden-topbar.js +0 -14
- package/src/common/wizard-modal.jsx +0 -200
- package/src/common/ws.js +0 -68
- package/src/contexts/config-user-space.tsx +0 -88
- package/src/contexts/user-followers.tsx +0 -54
- package/src/hooks/use-follow.tsx +0 -75
- package/src/hooks/use-mobile.tsx +0 -6
- package/src/index.ts +0 -16
- package/src/libs/constant.ts +0 -1
- package/src/libs/spaces.tsx +0 -18
- package/src/libs/with-hide-when-embed.tsx +0 -24
- package/src/types.js +0 -45
- package/src/utils.js +0 -161
- package/vite.config.mjs +0 -34
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
const RESERVED_IP = 'Reserved IP';
|
|
2
|
-
const IP_REGION_CACHE = 'ip-region-cache';
|
|
3
|
-
|
|
4
|
-
async function getIpRegionFromIpApi(ip: string): Promise<string> {
|
|
5
|
-
const url = `https://ipapi.co/${ip}/json/`;
|
|
6
|
-
const result = await fetch(url);
|
|
7
|
-
const data = await result.json();
|
|
8
|
-
|
|
9
|
-
let region = '';
|
|
10
|
-
if (data.error) {
|
|
11
|
-
if (data.reserved) {
|
|
12
|
-
region = RESERVED_IP;
|
|
13
|
-
}
|
|
14
|
-
} else {
|
|
15
|
-
region = [data.country_name, data.region, data.city].filter(Boolean).join('/');
|
|
16
|
-
}
|
|
17
|
-
return region;
|
|
18
|
-
}
|
|
19
|
-
async function getIpRegionFromIpSb(ip: string): Promise<string> {
|
|
20
|
-
const url = `https://api.ip.sb/geoip/${ip}`;
|
|
21
|
-
const result = await fetch(url);
|
|
22
|
-
const data = await result.json();
|
|
23
|
-
|
|
24
|
-
let region = '';
|
|
25
|
-
if (data.error) {
|
|
26
|
-
if (data.reserved) {
|
|
27
|
-
region = RESERVED_IP;
|
|
28
|
-
}
|
|
29
|
-
} else {
|
|
30
|
-
region = [data.country, data.region, data.city].filter(Boolean).join('/');
|
|
31
|
-
}
|
|
32
|
-
return region;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function ip2Region(ip: string): Promise<string> {
|
|
36
|
-
let region = '';
|
|
37
|
-
let ipRegionCache: Record<string, string> = {};
|
|
38
|
-
try {
|
|
39
|
-
const tmpCache = localStorage.getItem(IP_REGION_CACHE);
|
|
40
|
-
if (tmpCache) {
|
|
41
|
-
ipRegionCache = JSON.parse(tmpCache);
|
|
42
|
-
}
|
|
43
|
-
} catch {
|
|
44
|
-
ipRegionCache = {};
|
|
45
|
-
}
|
|
46
|
-
if (ipRegionCache[ip]) {
|
|
47
|
-
region = ipRegionCache[ip];
|
|
48
|
-
} else {
|
|
49
|
-
try {
|
|
50
|
-
region = await getIpRegionFromIpSb(ip);
|
|
51
|
-
} catch {
|
|
52
|
-
console.warn('Fail to get ip region from ip.sb');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (!region) {
|
|
56
|
-
try {
|
|
57
|
-
region = await getIpRegionFromIpApi(ip);
|
|
58
|
-
} catch {
|
|
59
|
-
console.warn('Fail to get ip region from ip-api.co');
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (region) {
|
|
65
|
-
// NOTICE: 为了防止 cache 过大,将在 size 超过 100 时,删除最旧的数据
|
|
66
|
-
const ipList = Object.keys(ipRegionCache);
|
|
67
|
-
if (ipList.length > 100) {
|
|
68
|
-
delete ipRegionCache[ipList[0]];
|
|
69
|
-
}
|
|
70
|
-
if (ipRegionCache[ip]) {
|
|
71
|
-
delete ipRegionCache[ip];
|
|
72
|
-
}
|
|
73
|
-
ipRegionCache[ip] = region;
|
|
74
|
-
localStorage.setItem(IP_REGION_CACHE, JSON.stringify(ipRegionCache));
|
|
75
|
-
}
|
|
76
|
-
return region;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// eslint-disable-next-line require-await
|
|
80
|
-
export async function batchIp2Region(ips: string[]): Promise<string[]> {
|
|
81
|
-
return Promise.all(ips.map((ip) => ip2Region(ip)));
|
|
82
|
-
}
|
package/src/blocklets.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { getUTMUrl } from '@arcblock/ux/lib/withTracker/libs/utm';
|
|
2
|
-
import { mapRecursive, filterRecursive, isUrl, isMailProtocol } from './utils';
|
|
3
|
-
|
|
4
|
-
export const publicPath = window?.blocklet?.groupPrefix || window?.blocklet?.prefix || '/';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 格式化 theme (目前仅考虑 background)
|
|
8
|
-
*/
|
|
9
|
-
export const formatTheme = (theme) => {
|
|
10
|
-
const formatted = { ...theme };
|
|
11
|
-
const background = theme?.background;
|
|
12
|
-
if (typeof background === 'string') {
|
|
13
|
-
formatted.background = { header: background, footer: background, default: background };
|
|
14
|
-
} else if (background && typeof background === 'object') {
|
|
15
|
-
formatted.background = {
|
|
16
|
-
header: background.header || background.default,
|
|
17
|
-
footer: background.footer || background.default,
|
|
18
|
-
default: background.default,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
return formatted;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const getLink = (link, locale = 'en', defaultLocale = 'en') => {
|
|
25
|
-
if (typeof link === 'string') {
|
|
26
|
-
// http[s] 开头的 url
|
|
27
|
-
if (isUrl(link)) {
|
|
28
|
-
const url = new URL(link);
|
|
29
|
-
url.searchParams.set('locale', locale);
|
|
30
|
-
return url.href;
|
|
31
|
-
}
|
|
32
|
-
// 如果是 mailto 协议, 直接返回
|
|
33
|
-
if (isMailProtocol(link)) {
|
|
34
|
-
return link;
|
|
35
|
-
}
|
|
36
|
-
const url = new URL(link, window.location.origin);
|
|
37
|
-
url.searchParams.set('locale', locale);
|
|
38
|
-
return url.pathname + url.search;
|
|
39
|
-
}
|
|
40
|
-
if (typeof link === 'object') {
|
|
41
|
-
return link[locale] || link[defaultLocale] || link.en;
|
|
42
|
-
}
|
|
43
|
-
return link;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 获取本地化后的导航菜单
|
|
48
|
-
*
|
|
49
|
-
* @param {Object} params
|
|
50
|
-
* @param {Array<{
|
|
51
|
-
* title?: string | Record<string, string>,
|
|
52
|
-
* description?: string | Record<string, string>,
|
|
53
|
-
* link?: string | Record<string, string>,
|
|
54
|
-
* items?: any[],
|
|
55
|
-
* [key: string]: any
|
|
56
|
-
* }>} params.navigation - 导航菜单数据
|
|
57
|
-
* @param {string} params.locale - 当前语言
|
|
58
|
-
* @param {string} params.defaultLocale - 默认语言
|
|
59
|
-
* @param {'header' | 'footer'} [params.section='header'] - 导航区域,可选
|
|
60
|
-
* @returns {Array} 本地化处理后的导航数据
|
|
61
|
-
*/
|
|
62
|
-
export const getLocalizedNavigation = ({ navigation, locale, defaultLocale, section = 'header' }) => {
|
|
63
|
-
if (!navigation?.length) {
|
|
64
|
-
return navigation;
|
|
65
|
-
}
|
|
66
|
-
const trans = (text, _locale) => {
|
|
67
|
-
if (text && typeof text === 'object') {
|
|
68
|
-
return text[_locale] || text[defaultLocale] || text.en;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return text;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
return mapRecursive(
|
|
75
|
-
navigation,
|
|
76
|
-
(item) => {
|
|
77
|
-
return {
|
|
78
|
-
...item,
|
|
79
|
-
title: trans(item.title, locale),
|
|
80
|
-
description: trans(item.description, locale),
|
|
81
|
-
// 仅对叶结点进行处理
|
|
82
|
-
link: getUTMUrl(!item.items?.length ? getLink(item.link, locale, defaultLocale) : item.link, section),
|
|
83
|
-
_rawLink: item.link,
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
'items'
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 格式化 navigation
|
|
92
|
-
*
|
|
93
|
-
* - role 统一为数组形式
|
|
94
|
-
*/
|
|
95
|
-
export const formatNavigation = (navigation) => {
|
|
96
|
-
return mapRecursive(
|
|
97
|
-
navigation,
|
|
98
|
-
(item) => {
|
|
99
|
-
if (item.role) {
|
|
100
|
-
return {
|
|
101
|
-
...item,
|
|
102
|
-
role: Array.isArray(item.role) ? item.role : [item.role],
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
return item;
|
|
106
|
-
},
|
|
107
|
-
'items'
|
|
108
|
-
);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export const parseNavigation = (navigation) => {
|
|
112
|
-
if (!navigation?.length) {
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const formattedNav = formatNavigation(navigation);
|
|
117
|
-
|
|
118
|
-
const sections = {
|
|
119
|
-
header: [],
|
|
120
|
-
footer: [],
|
|
121
|
-
// 对应 footer social media
|
|
122
|
-
social: [],
|
|
123
|
-
// 对应 footer 底部 links
|
|
124
|
-
bottom: [],
|
|
125
|
-
// 对应 dashboard#sidenav 导航
|
|
126
|
-
dashboard: [],
|
|
127
|
-
// session manager menus
|
|
128
|
-
sessionManager: [],
|
|
129
|
-
userCenter: [],
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// 对 navigation 顶层元素按 section 分组
|
|
133
|
-
formattedNav.forEach((item) => {
|
|
134
|
-
// item#section 为空时, 表示只存在于 header
|
|
135
|
-
if (!item.section) {
|
|
136
|
-
sections.header.push(item);
|
|
137
|
-
// item 出现在指定几个 section 中 (array)
|
|
138
|
-
} else if (Array.isArray(item.section)) {
|
|
139
|
-
item.section.forEach((sectionKey) => {
|
|
140
|
-
sections[sectionKey]?.push(item);
|
|
141
|
-
});
|
|
142
|
-
// item 出现在指定的一个 section 中 (string)
|
|
143
|
-
} else if (typeof item.section === 'string') {
|
|
144
|
-
sections[item.section]?.push(item);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
return sections;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* 格式化 blocklet info 数据
|
|
153
|
-
*/
|
|
154
|
-
export const formatBlockletInfo = (blockletInfo) => {
|
|
155
|
-
if (!blockletInfo) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
const formatted = { ...blockletInfo };
|
|
159
|
-
// theme
|
|
160
|
-
formatted.theme = formatTheme(formatted.theme);
|
|
161
|
-
// navigation
|
|
162
|
-
formatted.navigation = parseNavigation(filterValidNavItems(formatted.navigation));
|
|
163
|
-
return formatted;
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* 过滤掉无效结点 (无 link 且子元素为空)
|
|
168
|
-
*/
|
|
169
|
-
export const filterValidNavItems = (navigation = []) => {
|
|
170
|
-
return filterRecursive(navigation, (item, context) => !!item.link || context.filteredChildren?.length, 'items');
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* 根据 role 筛选 nav, 规则:
|
|
175
|
-
* - 如果是枝结点, 必须至少存在一个符合条件的子结点
|
|
176
|
-
* - role 未定义, 符合条件
|
|
177
|
-
* - role 定义且包括当前的 userRole, 符合条件
|
|
178
|
-
*
|
|
179
|
-
* @param {object[]} nav 导航菜单数据
|
|
180
|
-
* @param {string} userRole 当前用户 role
|
|
181
|
-
* @returns 符合 role 权限的导航菜单数据
|
|
182
|
-
*/
|
|
183
|
-
export const filterNavByRole = (nav, userRole) => {
|
|
184
|
-
return filterRecursive(
|
|
185
|
-
nav,
|
|
186
|
-
(item, context) => {
|
|
187
|
-
const isRoleMatched = !item.role || (userRole && (item.role.includes(userRole) || item.role.includes('guest')));
|
|
188
|
-
if (!context.isLeaf) {
|
|
189
|
-
return isRoleMatched && context.filteredChildren?.length;
|
|
190
|
-
}
|
|
191
|
-
return isRoleMatched;
|
|
192
|
-
},
|
|
193
|
-
'items'
|
|
194
|
-
);
|
|
195
|
-
};
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { useMemo, useState, useCallback } from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import { Box, Typography, Button, Dialog, DialogActions, DialogContent } from '@mui/material';
|
|
4
|
-
import { useMemoizedFn } from 'ahooks';
|
|
5
|
-
import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
6
|
-
import { joinURL } from 'ufo';
|
|
7
|
-
|
|
8
|
-
import useMobile from '../hooks/use-mobile';
|
|
9
|
-
|
|
10
|
-
const isAdmin = ['admin', 'owner'];
|
|
11
|
-
|
|
12
|
-
const isIpEcho = (hostname) => {
|
|
13
|
-
return hostname.endsWith('.ip.abtnet.io');
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const isDidDomain = (hostname) => {
|
|
17
|
-
return hostname.endsWith('.did.abtnet.io');
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const translations = {
|
|
21
|
-
en: {
|
|
22
|
-
guest: {
|
|
23
|
-
title: 'Notice: You are using a temporary domain',
|
|
24
|
-
description:
|
|
25
|
-
'You are accessing this site through a temporary domain. For a better experience, please contact the site administrator to configure a custom domain. Using a custom domain not only makes access more convenient but also ensures your access is more secure.',
|
|
26
|
-
},
|
|
27
|
-
owner: {
|
|
28
|
-
title: 'Enhance Your Website Security',
|
|
29
|
-
description: 'Dear administrator, we recommend configuring your custom domain immediately, which will:',
|
|
30
|
-
benefits1: 'Automatically obtain HTTPS certificates to ensure secure data transmission',
|
|
31
|
-
benefits2: 'Create an exclusive brand image and increase website credibility',
|
|
32
|
-
benefits3: 'Get a shorter, more memorable access address',
|
|
33
|
-
benefits4: 'Provide visitors with a more professional experience',
|
|
34
|
-
benefits5: 'Domain configuration takes just minutes to complete, taking your website to the next level!',
|
|
35
|
-
},
|
|
36
|
-
skip: 'Remind Me Later',
|
|
37
|
-
bindDomain: 'Configure Domain',
|
|
38
|
-
},
|
|
39
|
-
zh: {
|
|
40
|
-
guest: {
|
|
41
|
-
title: '温馨提示:当前使用的是临时域名',
|
|
42
|
-
description:
|
|
43
|
-
'您正在通过临时域名访问本站点。为了获得更好的访问体验,请联系站点管理员配置自定义域名。使用自定义域名不仅访问更便捷,还能确保您的访问更加安全。',
|
|
44
|
-
},
|
|
45
|
-
owner: {
|
|
46
|
-
title: '提升网站安全性与专业度',
|
|
47
|
-
description: '尊敬的管理员,我们建议您尽快配置自定义域名,这样可以:',
|
|
48
|
-
benefits1: '自动获取 HTTPS 证书,确保数据传输安全',
|
|
49
|
-
benefits2: '打造专属品牌形象,提升网站可信度',
|
|
50
|
-
benefits3: '获得更简短、易记的访问地址',
|
|
51
|
-
benefits4: '为访客提供更专业的访问体验',
|
|
52
|
-
benefits5: '只需几分钟即可完成域名配置,全面提升您的网站品质!',
|
|
53
|
-
},
|
|
54
|
-
skip: '稍后提醒',
|
|
55
|
-
bindDomain: '配置域名',
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const ONE_MONTH = 1000 * 60 * 60 * 24 * 30;
|
|
60
|
-
|
|
61
|
-
const DASHBOARD_DOMAIN = '.well-known/service/admin/domains';
|
|
62
|
-
|
|
63
|
-
export default function DomainWarning({ locale = 'en', session = {} }) {
|
|
64
|
-
const user = session?.user;
|
|
65
|
-
const isMobile = useMobile();
|
|
66
|
-
|
|
67
|
-
const [open, setOpen] = useState(() => {
|
|
68
|
-
const skip = window.localStorage.getItem('domain-warning-skip');
|
|
69
|
-
if (!skip) return true;
|
|
70
|
-
|
|
71
|
-
const now = +new Date();
|
|
72
|
-
const skipTime = +new Date(skip);
|
|
73
|
-
return now - skipTime > ONE_MONTH;
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const t = useMemoizedFn((key, data = {}) => {
|
|
77
|
-
return translate(translations, key, locale, 'en', data);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const host = useMemo(() => {
|
|
81
|
-
try {
|
|
82
|
-
const { hostname } = new URL(window.location.href);
|
|
83
|
-
return hostname;
|
|
84
|
-
} catch (error) {
|
|
85
|
-
return '';
|
|
86
|
-
}
|
|
87
|
-
}, []);
|
|
88
|
-
|
|
89
|
-
const benefits = useMemo(
|
|
90
|
-
() => [
|
|
91
|
-
t('owner.benefits1'),
|
|
92
|
-
t('owner.benefits2'),
|
|
93
|
-
t('owner.benefits3'),
|
|
94
|
-
t('owner.benefits4'),
|
|
95
|
-
t('owner.benefits5'),
|
|
96
|
-
],
|
|
97
|
-
[t]
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const handleSkip = useCallback(() => {
|
|
101
|
-
window.localStorage.setItem('domain-warning-skip', new Date().toISOString());
|
|
102
|
-
setOpen(false);
|
|
103
|
-
}, []);
|
|
104
|
-
|
|
105
|
-
const handleDomainConfig = useCallback(() => {
|
|
106
|
-
const adminUrl = joinURL(window.location.origin, DASHBOARD_DOMAIN);
|
|
107
|
-
if (adminUrl.startsWith('http')) {
|
|
108
|
-
window.open(adminUrl, '_blank');
|
|
109
|
-
}
|
|
110
|
-
setOpen(false);
|
|
111
|
-
}, []);
|
|
112
|
-
|
|
113
|
-
const isOwner = user?.role && isAdmin.includes(user.role);
|
|
114
|
-
|
|
115
|
-
if (window.location.href.includes(DASHBOARD_DOMAIN)) {
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (isMobile) {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!isIpEcho(host) && !isDidDomain(host)) {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return (
|
|
128
|
-
<Dialog open={open} disableEscapeKeyDown fullWidth maxWidth="sm" onClose={() => setOpen(false)}>
|
|
129
|
-
<DialogContent sx={{ padding: '20px !important' }}>
|
|
130
|
-
<Typography
|
|
131
|
-
sx={{
|
|
132
|
-
fontSize: '20px',
|
|
133
|
-
fontWeight: '500',
|
|
134
|
-
}}>
|
|
135
|
-
{isOwner ? t('owner.title') : t('guest.title')}
|
|
136
|
-
</Typography>
|
|
137
|
-
<Typography
|
|
138
|
-
sx={{
|
|
139
|
-
marginTop: '20px',
|
|
140
|
-
fontSize: '14px',
|
|
141
|
-
color: 'text.secondary',
|
|
142
|
-
}}>
|
|
143
|
-
{isOwner ? t('owner.description') : t('guest.description')}
|
|
144
|
-
</Typography>
|
|
145
|
-
|
|
146
|
-
{isOwner && (
|
|
147
|
-
<Box component="ul">
|
|
148
|
-
{benefits.map((benefit) => (
|
|
149
|
-
<Typography
|
|
150
|
-
component="li"
|
|
151
|
-
key={benefit}
|
|
152
|
-
sx={{
|
|
153
|
-
fontSize: '14px',
|
|
154
|
-
color: 'text.secondary',
|
|
155
|
-
}}>
|
|
156
|
-
{benefit}
|
|
157
|
-
</Typography>
|
|
158
|
-
))}
|
|
159
|
-
</Box>
|
|
160
|
-
)}
|
|
161
|
-
</DialogContent>
|
|
162
|
-
<DialogActions sx={{ px: '12px !important' }}>
|
|
163
|
-
<Button onClick={handleSkip}>{t('skip')}</Button>
|
|
164
|
-
|
|
165
|
-
{isOwner && (
|
|
166
|
-
<Button variant="contained" onClick={handleDomainConfig}>
|
|
167
|
-
{t('bindDomain')}
|
|
168
|
-
</Button>
|
|
169
|
-
)}
|
|
170
|
-
</DialogActions>
|
|
171
|
-
</Dialog>
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
DomainWarning.propTypes = {
|
|
176
|
-
locale: PropTypes.string,
|
|
177
|
-
session: PropTypes.object,
|
|
178
|
-
};
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import 'iconify-icon';
|
|
2
|
-
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import { createElement, use } from 'react';
|
|
5
|
-
|
|
6
|
-
// FIXME: 直接从 react 中 import Fragment 可能会在 vite 下出错,先暂时从 react/jsx-runtime 导入 Fragment 来跳过这个问题
|
|
7
|
-
import { SessionContext } from '@arcblock/did-connect-react/lib/Session';
|
|
8
|
-
import ThemeModeToggle from '@arcblock/ux/lib/Config/theme-mode-toggle';
|
|
9
|
-
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
10
|
-
import LocaleSelector from '@arcblock/ux/lib/Locale/selector';
|
|
11
|
-
import SessionBlocklet from '@arcblock/ux/lib/SessionBlocklet';
|
|
12
|
-
import SessionUser from '@arcblock/ux/lib/SessionUser';
|
|
13
|
-
import { Fragment } from 'react/jsx-runtime';
|
|
14
|
-
|
|
15
|
-
import { filterNavByRole, getLocalizedNavigation } from '../blocklets';
|
|
16
|
-
import { SessionManagerProps } from '../types';
|
|
17
|
-
import DomainWarning from './domain-warning';
|
|
18
|
-
import NotificationAddon from './notification-addon';
|
|
19
|
-
|
|
20
|
-
const hasNotification = () => {
|
|
21
|
-
const navigations = window?.blocklet?.navigation ?? [];
|
|
22
|
-
return !!navigations.find((n) => n.id === '/userCenter/notification');
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// eslint-disable-next-line no-shadow
|
|
26
|
-
export default function HeaderAddons({
|
|
27
|
-
formattedBlocklet,
|
|
28
|
-
addons = null,
|
|
29
|
-
showDomainWarningDialog = true,
|
|
30
|
-
sessionManagerProps = { showRole: true },
|
|
31
|
-
}) {
|
|
32
|
-
const sessionCtx = use(SessionContext);
|
|
33
|
-
const { locale, languages, defaultLocale } = useLocaleContext() || {};
|
|
34
|
-
const { enableConnect = true, enableLocale = true } = formattedBlocklet;
|
|
35
|
-
const authenticated = !!sessionCtx?.session?.user;
|
|
36
|
-
let localizedNav =
|
|
37
|
-
getLocalizedNavigation({
|
|
38
|
-
navigation: formattedBlocklet?.navigation?.sessionManager,
|
|
39
|
-
locale,
|
|
40
|
-
defaultLocale,
|
|
41
|
-
}) || [];
|
|
42
|
-
// 根据 role 筛选 nav 数据
|
|
43
|
-
localizedNav = filterNavByRole(localizedNav, sessionCtx?.session?.user?.role);
|
|
44
|
-
|
|
45
|
-
const renderAddons = () => {
|
|
46
|
-
// 不关心内置的 session manager 和 locale selector, 直接覆盖 UX Header 的 addons
|
|
47
|
-
if (addons && typeof addons !== 'function') {
|
|
48
|
-
return Array.isArray(addons) ? addons : [addons];
|
|
49
|
-
}
|
|
50
|
-
let addonsArray = [];
|
|
51
|
-
|
|
52
|
-
if (hasNotification()) {
|
|
53
|
-
addonsArray.push(<NotificationAddon key="notification-addon" session={sessionCtx.session} />);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 启用了多语言,且检测到了 locale context,且有多种语言可以切换
|
|
57
|
-
if (enableLocale && locale && languages.length > 1) {
|
|
58
|
-
addonsArray.push(<LocaleSelector key="locale-selector" showText={false} />);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// 切换明暗主题
|
|
62
|
-
addonsArray.push(<ThemeModeToggle key="theme-mode-toggle" />);
|
|
63
|
-
|
|
64
|
-
// 启用了连接钱包并且检测到了 session context
|
|
65
|
-
if (enableConnect && sessionCtx) {
|
|
66
|
-
const menu = [];
|
|
67
|
-
if (authenticated) {
|
|
68
|
-
const navList = localizedNav ? localizedNav.slice(0, 5) : [];
|
|
69
|
-
navList.forEach((x) => {
|
|
70
|
-
menu.push({
|
|
71
|
-
label: x.title,
|
|
72
|
-
icon: x.icon ? <iconify-icon icon={x.icon} height={24} style={{ marginRight: 8 }} /> : null,
|
|
73
|
-
component: 'a',
|
|
74
|
-
href: x.link,
|
|
75
|
-
key: x.link,
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
addonsArray.push(<SessionBlocklet key="session-blocklet" session={sessionCtx.session} locale={locale} />);
|
|
81
|
-
|
|
82
|
-
addonsArray.push(
|
|
83
|
-
<SessionUser
|
|
84
|
-
key="session-user"
|
|
85
|
-
session={sessionCtx.session}
|
|
86
|
-
locale={locale}
|
|
87
|
-
menu={menu}
|
|
88
|
-
showRole
|
|
89
|
-
{...sessionManagerProps}
|
|
90
|
-
/>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (typeof addons === 'function') {
|
|
95
|
-
addonsArray = addons(addonsArray) || [];
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return addonsArray;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const renderedAddons = renderAddons();
|
|
102
|
-
const nodes = Array.isArray(renderedAddons) ? renderedAddons : [renderedAddons];
|
|
103
|
-
const mergedNodes = [
|
|
104
|
-
showDomainWarningDialog ? <DomainWarning session={sessionCtx?.session} locale={locale} /> : null,
|
|
105
|
-
...nodes,
|
|
106
|
-
].filter(Boolean);
|
|
107
|
-
|
|
108
|
-
return createElement(Fragment, null, ...mergedNodes);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
HeaderAddons.propTypes = {
|
|
112
|
-
formattedBlocklet: PropTypes.object.isRequired,
|
|
113
|
-
// 需要考虑 定制的 addons 与内置的 连接钱包/选择语言 addons 共存的情况
|
|
114
|
-
// - PropTypes.func: 可以把自定义 addons 插在 session-manager 或 locale-selector (如果存在的话) 前/中/后
|
|
115
|
-
// - PropTypes.node: 将 addons 原样传给 UX Header 组件
|
|
116
|
-
addons: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
|
|
117
|
-
sessionManagerProps: SessionManagerProps,
|
|
118
|
-
showDomainWarningDialog: PropTypes.bool,
|
|
119
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
function hasParentOfType(node, type) {
|
|
2
|
-
if (!node) return false;
|
|
3
|
-
if (type === node.nodeName) return true;
|
|
4
|
-
return hasParentOfType(node.parentNode, type);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 适用于 header/footer/dashboard "preview mode", 阻止内部组件中所有 link 的默认点击行为
|
|
9
|
-
*/
|
|
10
|
-
function LinkBlocker({ ...rest }) {
|
|
11
|
-
const handleOnClick = (e) => {
|
|
12
|
-
const isInsideLink = hasParentOfType(e.target, 'A');
|
|
13
|
-
if (isInsideLink) {
|
|
14
|
-
e.preventDefault();
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
return <div onClick={handleOnClick} {...rest} />;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default LinkBlocker;
|