@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.
Files changed (255) hide show
  1. package/lib/common/org-switch/use-org.d.ts +4 -4
  2. package/package.json +9 -6
  3. package/.aigne/doc-smith/.local/afs-storage.sqlite3 +0 -0
  4. package/.aigne/doc-smith/config.yaml +0 -78
  5. package/.aigne/doc-smith/history.yaml +0 -14
  6. package/.aigne/doc-smith/media-description.yaml +0 -11
  7. package/.aigne/doc-smith/output/structure-plan.json +0 -255
  8. package/.aigne/doc-smith/translation-cache.yaml +0 -11
  9. package/.aigne/doc-smith/upload-cache.yaml +0 -528
  10. package/build.config.ts +0 -24
  11. package/docs/_sidebar.md +0 -19
  12. package/docs/assets/diagram/component-installer-diagram-0.ja.jpg +0 -0
  13. package/docs/assets/diagram/component-installer-diagram-0.jpg +0 -0
  14. package/docs/assets/diagram/component-installer-diagram-0.zh-TW.jpg +0 -0
  15. package/docs/assets/diagram/component-installer-diagram-0.zh.jpg +0 -0
  16. package/docs/assets/diagram/component-management-diagram-0.ja.jpg +0 -0
  17. package/docs/assets/diagram/component-management-diagram-0.jpg +0 -0
  18. package/docs/assets/diagram/component-management-diagram-0.zh-TW.jpg +0 -0
  19. package/docs/assets/diagram/component-management-diagram-0.zh.jpg +0 -0
  20. package/docs/assets/diagram/core-concepts-diagram-0.ja.jpg +0 -0
  21. package/docs/assets/diagram/core-concepts-diagram-0.jpg +0 -0
  22. package/docs/assets/diagram/core-concepts-diagram-0.zh-TW.jpg +0 -0
  23. package/docs/assets/diagram/core-concepts-diagram-0.zh.jpg +0 -0
  24. package/docs/assets/diagram/dashboard-diagram-0.ja.jpg +0 -0
  25. package/docs/assets/diagram/dashboard-diagram-0.jpg +0 -0
  26. package/docs/assets/diagram/dashboard-diagram-0.zh-TW.jpg +0 -0
  27. package/docs/assets/diagram/dashboard-diagram-0.zh.jpg +0 -0
  28. package/docs/assets/diagram/header-diagram-0.ja.jpg +0 -0
  29. package/docs/assets/diagram/header-diagram-0.jpg +0 -0
  30. package/docs/assets/diagram/header-diagram-0.zh-TW.jpg +0 -0
  31. package/docs/assets/diagram/header-diagram-0.zh.jpg +0 -0
  32. package/docs/assets/diagram/layout-diagram-0.ja.jpg +0 -0
  33. package/docs/assets/diagram/layout-diagram-0.jpg +0 -0
  34. package/docs/assets/diagram/layout-diagram-0.zh-TW.jpg +0 -0
  35. package/docs/assets/diagram/layout-diagram-0.zh.jpg +0 -0
  36. package/docs/assets/diagram/notifications-diagram-0.ja.jpg +0 -0
  37. package/docs/assets/diagram/notifications-diagram-0.jpg +0 -0
  38. package/docs/assets/diagram/notifications-diagram-0.zh-TW.jpg +0 -0
  39. package/docs/assets/diagram/notifications-diagram-0.zh.jpg +0 -0
  40. package/docs/assets/diagram/overview-diagram-0.ja.jpg +0 -0
  41. package/docs/assets/diagram/overview-diagram-0.jpg +0 -0
  42. package/docs/assets/diagram/overview-diagram-0.zh-TW.jpg +0 -0
  43. package/docs/assets/diagram/overview-diagram-0.zh.jpg +0 -0
  44. package/docs/assets/diagram/user-center-diagram-0.ja.jpg +0 -0
  45. package/docs/assets/diagram/user-center-diagram-0.jpg +0 -0
  46. package/docs/assets/diagram/user-center-diagram-0.zh-TW.jpg +0 -0
  47. package/docs/assets/diagram/user-center-diagram-0.zh.jpg +0 -0
  48. package/docs/assets/diagram/user-management-diagram-0.ja.jpg +0 -0
  49. package/docs/assets/diagram/user-management-diagram-0.jpg +0 -0
  50. package/docs/assets/diagram/user-management-diagram-0.zh-TW.jpg +0 -0
  51. package/docs/assets/diagram/user-management-diagram-0.zh.jpg +0 -0
  52. package/docs/assets/diagram/user-sessions-diagram-0.ja.jpg +0 -0
  53. package/docs/assets/diagram/user-sessions-diagram-0.jpg +0 -0
  54. package/docs/assets/diagram/user-sessions-diagram-0.zh-TW.jpg +0 -0
  55. package/docs/assets/diagram/user-sessions-diagram-0.zh.jpg +0 -0
  56. package/docs/components-component-management-blocklet-studio.ja.md +0 -194
  57. package/docs/components-component-management-blocklet-studio.md +0 -194
  58. package/docs/components-component-management-blocklet-studio.zh-TW.md +0 -194
  59. package/docs/components-component-management-blocklet-studio.zh.md +0 -194
  60. package/docs/components-component-management-component-installer.ja.md +0 -182
  61. package/docs/components-component-management-component-installer.md +0 -182
  62. package/docs/components-component-management-component-installer.zh-TW.md +0 -182
  63. package/docs/components-component-management-component-installer.zh.md +0 -182
  64. package/docs/components-component-management.ja.md +0 -30
  65. package/docs/components-component-management.md +0 -30
  66. package/docs/components-component-management.zh-TW.md +0 -30
  67. package/docs/components-component-management.zh.md +0 -30
  68. package/docs/components-layout-dashboard.ja.md +0 -185
  69. package/docs/components-layout-dashboard.md +0 -187
  70. package/docs/components-layout-dashboard.zh-TW.md +0 -185
  71. package/docs/components-layout-dashboard.zh.md +0 -185
  72. package/docs/components-layout-footer.ja.md +0 -165
  73. package/docs/components-layout-footer.md +0 -165
  74. package/docs/components-layout-footer.zh-TW.md +0 -165
  75. package/docs/components-layout-footer.zh.md +0 -165
  76. package/docs/components-layout-header.ja.md +0 -183
  77. package/docs/components-layout-header.md +0 -183
  78. package/docs/components-layout-header.zh-TW.md +0 -183
  79. package/docs/components-layout-header.zh.md +0 -183
  80. package/docs/components-layout.ja.md +0 -31
  81. package/docs/components-layout.md +0 -31
  82. package/docs/components-layout.zh-TW.md +0 -31
  83. package/docs/components-layout.zh.md +0 -31
  84. package/docs/components-notifications.ja.md +0 -125
  85. package/docs/components-notifications.md +0 -125
  86. package/docs/components-notifications.zh-TW.md +0 -125
  87. package/docs/components-notifications.zh.md +0 -125
  88. package/docs/components-user-management-user-center.ja.md +0 -148
  89. package/docs/components-user-management-user-center.md +0 -147
  90. package/docs/components-user-management-user-center.zh-TW.md +0 -148
  91. package/docs/components-user-management-user-center.zh.md +0 -148
  92. package/docs/components-user-management-user-sessions.ja.md +0 -121
  93. package/docs/components-user-management-user-sessions.md +0 -123
  94. package/docs/components-user-management-user-sessions.zh-TW.md +0 -121
  95. package/docs/components-user-management-user-sessions.zh.md +0 -121
  96. package/docs/components-user-management.ja.md +0 -49
  97. package/docs/components-user-management.md +0 -51
  98. package/docs/components-user-management.zh-TW.md +0 -49
  99. package/docs/components-user-management.zh.md +0 -49
  100. package/docs/components-utilities-icon.ja.md +0 -106
  101. package/docs/components-utilities-icon.md +0 -106
  102. package/docs/components-utilities-icon.zh-TW.md +0 -106
  103. package/docs/components-utilities-icon.zh.md +0 -106
  104. package/docs/components-utilities.ja.md +0 -136
  105. package/docs/components-utilities.md +0 -136
  106. package/docs/components-utilities.zh-TW.md +0 -136
  107. package/docs/components-utilities.zh.md +0 -136
  108. package/docs/components.ja.md +0 -27
  109. package/docs/components.md +0 -27
  110. package/docs/components.zh-TW.md +0 -27
  111. package/docs/components.zh.md +0 -27
  112. package/docs/core-concepts.ja.md +0 -134
  113. package/docs/core-concepts.md +0 -135
  114. package/docs/core-concepts.zh-TW.md +0 -134
  115. package/docs/core-concepts.zh.md +0 -134
  116. package/docs/getting-started.ja.md +0 -132
  117. package/docs/getting-started.md +0 -132
  118. package/docs/getting-started.zh-TW.md +0 -132
  119. package/docs/getting-started.zh.md +0 -132
  120. package/docs/hooks-api.ja.md +0 -214
  121. package/docs/hooks-api.md +0 -214
  122. package/docs/hooks-api.zh-TW.md +0 -214
  123. package/docs/hooks-api.zh.md +0 -214
  124. package/docs/how-to-guides.ja.md +0 -413
  125. package/docs/how-to-guides.md +0 -413
  126. package/docs/how-to-guides.zh-TW.md +0 -413
  127. package/docs/how-to-guides.zh.md +0 -413
  128. package/docs/overview.ja.md +0 -51
  129. package/docs/overview.md +0 -51
  130. package/docs/overview.zh-TW.md +0 -51
  131. package/docs/overview.zh.md +0 -51
  132. package/glossary.md +0 -12
  133. package/src/@types/index.ts +0 -230
  134. package/src/@types/shims.d.ts +0 -18
  135. package/src/BlockletStudio/README.md +0 -116
  136. package/src/BlockletStudio/index.tsx +0 -145
  137. package/src/ComponentInstaller/ComponentInstaller.stories.jsx +0 -16
  138. package/src/ComponentInstaller/index.jsx +0 -207
  139. package/src/ComponentInstaller/installer-item.jsx +0 -129
  140. package/src/ComponentInstaller/locales.js +0 -22
  141. package/src/ComponentInstaller/use-component-installed.js +0 -88
  142. package/src/ComponentManager/components/add-component.tsx +0 -136
  143. package/src/ComponentManager/components/check-component.tsx +0 -3
  144. package/src/ComponentManager/components/publish-component.tsx +0 -90
  145. package/src/ComponentManager/components/resource-dialog.tsx +0 -91
  146. package/src/ComponentManager/index.tsx +0 -3
  147. package/src/ComponentManager/libs/locales.ts +0 -15
  148. package/src/Dashboard/Dashboard.stories.jsx +0 -20
  149. package/src/Dashboard/app-shell/app-badge.stories.tsx +0 -64
  150. package/src/Dashboard/app-shell/app-badge.tsx +0 -94
  151. package/src/Dashboard/app-shell/app-header.tsx +0 -104
  152. package/src/Dashboard/app-shell/app-info-context.tsx +0 -182
  153. package/src/Dashboard/app-shell/badges/app-badge-default.tsx +0 -130
  154. package/src/Dashboard/app-shell/badges/app-badge-did.tsx +0 -28
  155. package/src/Dashboard/app-shell/badges/app-badge-state.tsx +0 -40
  156. package/src/Dashboard/app-shell/badges/app-badge-switch.tsx +0 -72
  157. package/src/Dashboard/app-shell/badges/app-badge-version.tsx +0 -60
  158. package/src/Dashboard/app-shell/index.ts +0 -5
  159. package/src/Dashboard/index.jsx +0 -184
  160. package/src/Footer/Footer.stories.jsx +0 -33
  161. package/src/Footer/brand.jsx +0 -81
  162. package/src/Footer/copyright.jsx +0 -22
  163. package/src/Footer/index.jsx +0 -111
  164. package/src/Footer/internal-footer.jsx +0 -139
  165. package/src/Footer/layout/plain.jsx +0 -55
  166. package/src/Footer/layout/row.jsx +0 -43
  167. package/src/Footer/layout/standard.jsx +0 -114
  168. package/src/Footer/links.jsx +0 -321
  169. package/src/Footer/social-media.jsx +0 -55
  170. package/src/Header/Header.stories.jsx +0 -30
  171. package/src/Header/index.tsx +0 -259
  172. package/src/Icon/Icon.stories.jsx +0 -12
  173. package/src/Icon/index.tsx +0 -87
  174. package/src/Notifications/Snackbar.tsx +0 -261
  175. package/src/Notifications/hooks/use-title.tsx +0 -254
  176. package/src/Notifications/hooks/use-width.tsx +0 -16
  177. package/src/Notifications/utils.ts +0 -246
  178. package/src/UserCenter/assets/banner.png +0 -0
  179. package/src/UserCenter/components/config-inviter.tsx +0 -48
  180. package/src/UserCenter/components/config-profile.tsx +0 -99
  181. package/src/UserCenter/components/danger-zone.tsx +0 -82
  182. package/src/UserCenter/components/editable-field.tsx +0 -273
  183. package/src/UserCenter/components/fallback.tsx +0 -57
  184. package/src/UserCenter/components/nft-preview.tsx +0 -84
  185. package/src/UserCenter/components/nft.tsx +0 -279
  186. package/src/UserCenter/components/notification.tsx +0 -319
  187. package/src/UserCenter/components/passport.tsx +0 -107
  188. package/src/UserCenter/components/privacy.tsx +0 -120
  189. package/src/UserCenter/components/settings.tsx +0 -170
  190. package/src/UserCenter/components/status-dialog/date-picker.tsx +0 -77
  191. package/src/UserCenter/components/status-dialog/index.tsx +0 -293
  192. package/src/UserCenter/components/status-selector/duration-menu.tsx +0 -90
  193. package/src/UserCenter/components/status-selector/index.tsx +0 -58
  194. package/src/UserCenter/components/status-selector/menu-item.tsx +0 -56
  195. package/src/UserCenter/components/storage/action.tsx +0 -49
  196. package/src/UserCenter/components/storage/connected.tsx +0 -61
  197. package/src/UserCenter/components/storage/delete.tsx +0 -72
  198. package/src/UserCenter/components/storage/disconnect.tsx +0 -40
  199. package/src/UserCenter/components/storage/icons/empty-spaces-nft.svg +0 -1
  200. package/src/UserCenter/components/storage/icons/long-arrow.svg +0 -5
  201. package/src/UserCenter/components/storage/icons/space-connected.svg +0 -3
  202. package/src/UserCenter/components/storage/icons/space-disconnect.svg +0 -3
  203. package/src/UserCenter/components/storage/index.tsx +0 -41
  204. package/src/UserCenter/components/storage/preview-nft.tsx +0 -72
  205. package/src/UserCenter/components/third-party-login/index.tsx +0 -199
  206. package/src/UserCenter/components/third-party-login/third-party-item.tsx +0 -296
  207. package/src/UserCenter/components/user-center.tsx +0 -787
  208. package/src/UserCenter/components/user-info/address.tsx +0 -143
  209. package/src/UserCenter/components/user-info/index.tsx +0 -4
  210. package/src/UserCenter/components/user-info/link-preview-input.tsx +0 -274
  211. package/src/UserCenter/components/user-info/metadata.tsx +0 -658
  212. package/src/UserCenter/components/user-info/social-actions/chat.tsx +0 -43
  213. package/src/UserCenter/components/user-info/social-actions/follow.tsx +0 -23
  214. package/src/UserCenter/components/user-info/social-actions/index.tsx +0 -17
  215. package/src/UserCenter/components/user-info/switch-role.tsx +0 -42
  216. package/src/UserCenter/components/user-info/timezone-select.tsx +0 -119
  217. package/src/UserCenter/components/user-info/user-basic-info.tsx +0 -292
  218. package/src/UserCenter/components/user-info/user-info-item.tsx +0 -54
  219. package/src/UserCenter/components/user-info/user-info.tsx +0 -91
  220. package/src/UserCenter/components/user-info/user-status.tsx +0 -234
  221. package/src/UserCenter/components/user-info/utils.ts +0 -320
  222. package/src/UserCenter/components/webhook-item.tsx +0 -248
  223. package/src/UserCenter/index.tsx +0 -1
  224. package/src/UserCenter/libs/locales.ts +0 -378
  225. package/src/UserCenter/libs/utils.ts +0 -30
  226. package/src/UserSessions/components/user-session-info.tsx +0 -78
  227. package/src/UserSessions/components/user-sessions.tsx +0 -545
  228. package/src/UserSessions/index.tsx +0 -1
  229. package/src/UserSessions/libs/locales.ts +0 -60
  230. package/src/UserSessions/libs/utils.ts +0 -82
  231. package/src/blocklets.js +0 -195
  232. package/src/common/domain-warning.jsx +0 -178
  233. package/src/common/header-addons.jsx +0 -119
  234. package/src/common/link-blocker.jsx +0 -20
  235. package/src/common/notification-addon.jsx +0 -135
  236. package/src/common/org-switch/avatar-uploader.jsx +0 -271
  237. package/src/common/org-switch/create.jsx +0 -267
  238. package/src/common/org-switch/index.jsx +0 -407
  239. package/src/common/org-switch/locales.js +0 -52
  240. package/src/common/org-switch/use-org.jsx +0 -79
  241. package/src/common/overridable-theme-provider.jsx +0 -17
  242. package/src/common/wallet-hidden-topbar.js +0 -14
  243. package/src/common/wizard-modal.jsx +0 -200
  244. package/src/common/ws.js +0 -68
  245. package/src/contexts/config-user-space.tsx +0 -88
  246. package/src/contexts/user-followers.tsx +0 -54
  247. package/src/hooks/use-follow.tsx +0 -75
  248. package/src/hooks/use-mobile.tsx +0 -6
  249. package/src/index.ts +0 -16
  250. package/src/libs/constant.ts +0 -1
  251. package/src/libs/spaces.tsx +0 -18
  252. package/src/libs/with-hide-when-embed.tsx +0 -24
  253. package/src/types.js +0 -45
  254. package/src/utils.js +0 -161
  255. 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;