@blocklet/ui-react 3.4.14 → 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 (256) hide show
  1. package/lib/common/org-switch/use-org.d.ts +4 -4
  2. package/lib/common/ws.d.ts +22 -1
  3. package/package.json +10 -7
  4. package/.aigne/doc-smith/.local/afs-storage.sqlite3 +0 -0
  5. package/.aigne/doc-smith/config.yaml +0 -78
  6. package/.aigne/doc-smith/history.yaml +0 -14
  7. package/.aigne/doc-smith/media-description.yaml +0 -11
  8. package/.aigne/doc-smith/output/structure-plan.json +0 -255
  9. package/.aigne/doc-smith/translation-cache.yaml +0 -11
  10. package/.aigne/doc-smith/upload-cache.yaml +0 -528
  11. package/build.config.ts +0 -24
  12. package/docs/_sidebar.md +0 -19
  13. package/docs/assets/diagram/component-installer-diagram-0.ja.jpg +0 -0
  14. package/docs/assets/diagram/component-installer-diagram-0.jpg +0 -0
  15. package/docs/assets/diagram/component-installer-diagram-0.zh-TW.jpg +0 -0
  16. package/docs/assets/diagram/component-installer-diagram-0.zh.jpg +0 -0
  17. package/docs/assets/diagram/component-management-diagram-0.ja.jpg +0 -0
  18. package/docs/assets/diagram/component-management-diagram-0.jpg +0 -0
  19. package/docs/assets/diagram/component-management-diagram-0.zh-TW.jpg +0 -0
  20. package/docs/assets/diagram/component-management-diagram-0.zh.jpg +0 -0
  21. package/docs/assets/diagram/core-concepts-diagram-0.ja.jpg +0 -0
  22. package/docs/assets/diagram/core-concepts-diagram-0.jpg +0 -0
  23. package/docs/assets/diagram/core-concepts-diagram-0.zh-TW.jpg +0 -0
  24. package/docs/assets/diagram/core-concepts-diagram-0.zh.jpg +0 -0
  25. package/docs/assets/diagram/dashboard-diagram-0.ja.jpg +0 -0
  26. package/docs/assets/diagram/dashboard-diagram-0.jpg +0 -0
  27. package/docs/assets/diagram/dashboard-diagram-0.zh-TW.jpg +0 -0
  28. package/docs/assets/diagram/dashboard-diagram-0.zh.jpg +0 -0
  29. package/docs/assets/diagram/header-diagram-0.ja.jpg +0 -0
  30. package/docs/assets/diagram/header-diagram-0.jpg +0 -0
  31. package/docs/assets/diagram/header-diagram-0.zh-TW.jpg +0 -0
  32. package/docs/assets/diagram/header-diagram-0.zh.jpg +0 -0
  33. package/docs/assets/diagram/layout-diagram-0.ja.jpg +0 -0
  34. package/docs/assets/diagram/layout-diagram-0.jpg +0 -0
  35. package/docs/assets/diagram/layout-diagram-0.zh-TW.jpg +0 -0
  36. package/docs/assets/diagram/layout-diagram-0.zh.jpg +0 -0
  37. package/docs/assets/diagram/notifications-diagram-0.ja.jpg +0 -0
  38. package/docs/assets/diagram/notifications-diagram-0.jpg +0 -0
  39. package/docs/assets/diagram/notifications-diagram-0.zh-TW.jpg +0 -0
  40. package/docs/assets/diagram/notifications-diagram-0.zh.jpg +0 -0
  41. package/docs/assets/diagram/overview-diagram-0.ja.jpg +0 -0
  42. package/docs/assets/diagram/overview-diagram-0.jpg +0 -0
  43. package/docs/assets/diagram/overview-diagram-0.zh-TW.jpg +0 -0
  44. package/docs/assets/diagram/overview-diagram-0.zh.jpg +0 -0
  45. package/docs/assets/diagram/user-center-diagram-0.ja.jpg +0 -0
  46. package/docs/assets/diagram/user-center-diagram-0.jpg +0 -0
  47. package/docs/assets/diagram/user-center-diagram-0.zh-TW.jpg +0 -0
  48. package/docs/assets/diagram/user-center-diagram-0.zh.jpg +0 -0
  49. package/docs/assets/diagram/user-management-diagram-0.ja.jpg +0 -0
  50. package/docs/assets/diagram/user-management-diagram-0.jpg +0 -0
  51. package/docs/assets/diagram/user-management-diagram-0.zh-TW.jpg +0 -0
  52. package/docs/assets/diagram/user-management-diagram-0.zh.jpg +0 -0
  53. package/docs/assets/diagram/user-sessions-diagram-0.ja.jpg +0 -0
  54. package/docs/assets/diagram/user-sessions-diagram-0.jpg +0 -0
  55. package/docs/assets/diagram/user-sessions-diagram-0.zh-TW.jpg +0 -0
  56. package/docs/assets/diagram/user-sessions-diagram-0.zh.jpg +0 -0
  57. package/docs/components-component-management-blocklet-studio.ja.md +0 -194
  58. package/docs/components-component-management-blocklet-studio.md +0 -194
  59. package/docs/components-component-management-blocklet-studio.zh-TW.md +0 -194
  60. package/docs/components-component-management-blocklet-studio.zh.md +0 -194
  61. package/docs/components-component-management-component-installer.ja.md +0 -182
  62. package/docs/components-component-management-component-installer.md +0 -182
  63. package/docs/components-component-management-component-installer.zh-TW.md +0 -182
  64. package/docs/components-component-management-component-installer.zh.md +0 -182
  65. package/docs/components-component-management.ja.md +0 -30
  66. package/docs/components-component-management.md +0 -30
  67. package/docs/components-component-management.zh-TW.md +0 -30
  68. package/docs/components-component-management.zh.md +0 -30
  69. package/docs/components-layout-dashboard.ja.md +0 -185
  70. package/docs/components-layout-dashboard.md +0 -187
  71. package/docs/components-layout-dashboard.zh-TW.md +0 -185
  72. package/docs/components-layout-dashboard.zh.md +0 -185
  73. package/docs/components-layout-footer.ja.md +0 -165
  74. package/docs/components-layout-footer.md +0 -165
  75. package/docs/components-layout-footer.zh-TW.md +0 -165
  76. package/docs/components-layout-footer.zh.md +0 -165
  77. package/docs/components-layout-header.ja.md +0 -183
  78. package/docs/components-layout-header.md +0 -183
  79. package/docs/components-layout-header.zh-TW.md +0 -183
  80. package/docs/components-layout-header.zh.md +0 -183
  81. package/docs/components-layout.ja.md +0 -31
  82. package/docs/components-layout.md +0 -31
  83. package/docs/components-layout.zh-TW.md +0 -31
  84. package/docs/components-layout.zh.md +0 -31
  85. package/docs/components-notifications.ja.md +0 -125
  86. package/docs/components-notifications.md +0 -125
  87. package/docs/components-notifications.zh-TW.md +0 -125
  88. package/docs/components-notifications.zh.md +0 -125
  89. package/docs/components-user-management-user-center.ja.md +0 -148
  90. package/docs/components-user-management-user-center.md +0 -147
  91. package/docs/components-user-management-user-center.zh-TW.md +0 -148
  92. package/docs/components-user-management-user-center.zh.md +0 -148
  93. package/docs/components-user-management-user-sessions.ja.md +0 -121
  94. package/docs/components-user-management-user-sessions.md +0 -123
  95. package/docs/components-user-management-user-sessions.zh-TW.md +0 -121
  96. package/docs/components-user-management-user-sessions.zh.md +0 -121
  97. package/docs/components-user-management.ja.md +0 -49
  98. package/docs/components-user-management.md +0 -51
  99. package/docs/components-user-management.zh-TW.md +0 -49
  100. package/docs/components-user-management.zh.md +0 -49
  101. package/docs/components-utilities-icon.ja.md +0 -106
  102. package/docs/components-utilities-icon.md +0 -106
  103. package/docs/components-utilities-icon.zh-TW.md +0 -106
  104. package/docs/components-utilities-icon.zh.md +0 -106
  105. package/docs/components-utilities.ja.md +0 -136
  106. package/docs/components-utilities.md +0 -136
  107. package/docs/components-utilities.zh-TW.md +0 -136
  108. package/docs/components-utilities.zh.md +0 -136
  109. package/docs/components.ja.md +0 -27
  110. package/docs/components.md +0 -27
  111. package/docs/components.zh-TW.md +0 -27
  112. package/docs/components.zh.md +0 -27
  113. package/docs/core-concepts.ja.md +0 -134
  114. package/docs/core-concepts.md +0 -135
  115. package/docs/core-concepts.zh-TW.md +0 -134
  116. package/docs/core-concepts.zh.md +0 -134
  117. package/docs/getting-started.ja.md +0 -132
  118. package/docs/getting-started.md +0 -132
  119. package/docs/getting-started.zh-TW.md +0 -132
  120. package/docs/getting-started.zh.md +0 -132
  121. package/docs/hooks-api.ja.md +0 -214
  122. package/docs/hooks-api.md +0 -214
  123. package/docs/hooks-api.zh-TW.md +0 -214
  124. package/docs/hooks-api.zh.md +0 -214
  125. package/docs/how-to-guides.ja.md +0 -413
  126. package/docs/how-to-guides.md +0 -413
  127. package/docs/how-to-guides.zh-TW.md +0 -413
  128. package/docs/how-to-guides.zh.md +0 -413
  129. package/docs/overview.ja.md +0 -51
  130. package/docs/overview.md +0 -51
  131. package/docs/overview.zh-TW.md +0 -51
  132. package/docs/overview.zh.md +0 -51
  133. package/glossary.md +0 -12
  134. package/src/@types/index.ts +0 -230
  135. package/src/@types/shims.d.ts +0 -18
  136. package/src/BlockletStudio/README.md +0 -116
  137. package/src/BlockletStudio/index.tsx +0 -145
  138. package/src/ComponentInstaller/ComponentInstaller.stories.jsx +0 -16
  139. package/src/ComponentInstaller/index.jsx +0 -207
  140. package/src/ComponentInstaller/installer-item.jsx +0 -129
  141. package/src/ComponentInstaller/locales.js +0 -22
  142. package/src/ComponentInstaller/use-component-installed.js +0 -88
  143. package/src/ComponentManager/components/add-component.tsx +0 -136
  144. package/src/ComponentManager/components/check-component.tsx +0 -3
  145. package/src/ComponentManager/components/publish-component.tsx +0 -90
  146. package/src/ComponentManager/components/resource-dialog.tsx +0 -91
  147. package/src/ComponentManager/index.tsx +0 -3
  148. package/src/ComponentManager/libs/locales.ts +0 -15
  149. package/src/Dashboard/Dashboard.stories.jsx +0 -20
  150. package/src/Dashboard/app-shell/app-badge.stories.tsx +0 -64
  151. package/src/Dashboard/app-shell/app-badge.tsx +0 -94
  152. package/src/Dashboard/app-shell/app-header.tsx +0 -104
  153. package/src/Dashboard/app-shell/app-info-context.tsx +0 -182
  154. package/src/Dashboard/app-shell/badges/app-badge-default.tsx +0 -130
  155. package/src/Dashboard/app-shell/badges/app-badge-did.tsx +0 -28
  156. package/src/Dashboard/app-shell/badges/app-badge-state.tsx +0 -40
  157. package/src/Dashboard/app-shell/badges/app-badge-switch.tsx +0 -72
  158. package/src/Dashboard/app-shell/badges/app-badge-version.tsx +0 -60
  159. package/src/Dashboard/app-shell/index.ts +0 -5
  160. package/src/Dashboard/index.jsx +0 -184
  161. package/src/Footer/Footer.stories.jsx +0 -33
  162. package/src/Footer/brand.jsx +0 -81
  163. package/src/Footer/copyright.jsx +0 -22
  164. package/src/Footer/index.jsx +0 -111
  165. package/src/Footer/internal-footer.jsx +0 -139
  166. package/src/Footer/layout/plain.jsx +0 -55
  167. package/src/Footer/layout/row.jsx +0 -43
  168. package/src/Footer/layout/standard.jsx +0 -114
  169. package/src/Footer/links.jsx +0 -321
  170. package/src/Footer/social-media.jsx +0 -55
  171. package/src/Header/Header.stories.jsx +0 -30
  172. package/src/Header/index.tsx +0 -259
  173. package/src/Icon/Icon.stories.jsx +0 -12
  174. package/src/Icon/index.tsx +0 -87
  175. package/src/Notifications/Snackbar.tsx +0 -261
  176. package/src/Notifications/hooks/use-title.tsx +0 -254
  177. package/src/Notifications/hooks/use-width.tsx +0 -16
  178. package/src/Notifications/utils.ts +0 -246
  179. package/src/UserCenter/assets/banner.png +0 -0
  180. package/src/UserCenter/components/config-inviter.tsx +0 -48
  181. package/src/UserCenter/components/config-profile.tsx +0 -99
  182. package/src/UserCenter/components/danger-zone.tsx +0 -82
  183. package/src/UserCenter/components/editable-field.tsx +0 -273
  184. package/src/UserCenter/components/fallback.tsx +0 -57
  185. package/src/UserCenter/components/nft-preview.tsx +0 -84
  186. package/src/UserCenter/components/nft.tsx +0 -279
  187. package/src/UserCenter/components/notification.tsx +0 -319
  188. package/src/UserCenter/components/passport.tsx +0 -107
  189. package/src/UserCenter/components/privacy.tsx +0 -120
  190. package/src/UserCenter/components/settings.tsx +0 -170
  191. package/src/UserCenter/components/status-dialog/date-picker.tsx +0 -77
  192. package/src/UserCenter/components/status-dialog/index.tsx +0 -293
  193. package/src/UserCenter/components/status-selector/duration-menu.tsx +0 -90
  194. package/src/UserCenter/components/status-selector/index.tsx +0 -58
  195. package/src/UserCenter/components/status-selector/menu-item.tsx +0 -56
  196. package/src/UserCenter/components/storage/action.tsx +0 -49
  197. package/src/UserCenter/components/storage/connected.tsx +0 -61
  198. package/src/UserCenter/components/storage/delete.tsx +0 -72
  199. package/src/UserCenter/components/storage/disconnect.tsx +0 -40
  200. package/src/UserCenter/components/storage/icons/empty-spaces-nft.svg +0 -1
  201. package/src/UserCenter/components/storage/icons/long-arrow.svg +0 -5
  202. package/src/UserCenter/components/storage/icons/space-connected.svg +0 -3
  203. package/src/UserCenter/components/storage/icons/space-disconnect.svg +0 -3
  204. package/src/UserCenter/components/storage/index.tsx +0 -41
  205. package/src/UserCenter/components/storage/preview-nft.tsx +0 -72
  206. package/src/UserCenter/components/third-party-login/index.tsx +0 -199
  207. package/src/UserCenter/components/third-party-login/third-party-item.tsx +0 -296
  208. package/src/UserCenter/components/user-center.tsx +0 -787
  209. package/src/UserCenter/components/user-info/address.tsx +0 -143
  210. package/src/UserCenter/components/user-info/index.tsx +0 -4
  211. package/src/UserCenter/components/user-info/link-preview-input.tsx +0 -274
  212. package/src/UserCenter/components/user-info/metadata.tsx +0 -658
  213. package/src/UserCenter/components/user-info/social-actions/chat.tsx +0 -43
  214. package/src/UserCenter/components/user-info/social-actions/follow.tsx +0 -23
  215. package/src/UserCenter/components/user-info/social-actions/index.tsx +0 -17
  216. package/src/UserCenter/components/user-info/switch-role.tsx +0 -42
  217. package/src/UserCenter/components/user-info/timezone-select.tsx +0 -119
  218. package/src/UserCenter/components/user-info/user-basic-info.tsx +0 -292
  219. package/src/UserCenter/components/user-info/user-info-item.tsx +0 -54
  220. package/src/UserCenter/components/user-info/user-info.tsx +0 -91
  221. package/src/UserCenter/components/user-info/user-status.tsx +0 -234
  222. package/src/UserCenter/components/user-info/utils.ts +0 -320
  223. package/src/UserCenter/components/webhook-item.tsx +0 -248
  224. package/src/UserCenter/index.tsx +0 -1
  225. package/src/UserCenter/libs/locales.ts +0 -378
  226. package/src/UserCenter/libs/utils.ts +0 -30
  227. package/src/UserSessions/components/user-session-info.tsx +0 -78
  228. package/src/UserSessions/components/user-sessions.tsx +0 -545
  229. package/src/UserSessions/index.tsx +0 -1
  230. package/src/UserSessions/libs/locales.ts +0 -60
  231. package/src/UserSessions/libs/utils.ts +0 -82
  232. package/src/blocklets.js +0 -195
  233. package/src/common/domain-warning.jsx +0 -178
  234. package/src/common/header-addons.jsx +0 -119
  235. package/src/common/link-blocker.jsx +0 -20
  236. package/src/common/notification-addon.jsx +0 -135
  237. package/src/common/org-switch/avatar-uploader.jsx +0 -271
  238. package/src/common/org-switch/create.jsx +0 -267
  239. package/src/common/org-switch/index.jsx +0 -407
  240. package/src/common/org-switch/locales.js +0 -52
  241. package/src/common/org-switch/use-org.jsx +0 -79
  242. package/src/common/overridable-theme-provider.jsx +0 -17
  243. package/src/common/wallet-hidden-topbar.js +0 -14
  244. package/src/common/wizard-modal.jsx +0 -200
  245. package/src/common/ws.js +0 -68
  246. package/src/contexts/config-user-space.tsx +0 -88
  247. package/src/contexts/user-followers.tsx +0 -54
  248. package/src/hooks/use-follow.tsx +0 -75
  249. package/src/hooks/use-mobile.tsx +0 -6
  250. package/src/index.ts +0 -16
  251. package/src/libs/constant.ts +0 -1
  252. package/src/libs/spaces.tsx +0 -18
  253. package/src/libs/with-hide-when-embed.tsx +0 -24
  254. package/src/types.js +0 -45
  255. package/src/utils.js +0 -161
  256. package/vite.config.mjs +0 -34
@@ -1,234 +0,0 @@
1
- import { Box, Badge, Tooltip, type SvgIconProps } from '@mui/material';
2
- import styled from '@emotion/styled';
3
- import { lazy, Suspense, useCallback, useEffect, useMemo, useState } from 'react';
4
- import { useCreation, useMemoizedFn, useInterval, useUnmount } from 'ahooks';
5
- import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
6
- import { translate } from '@arcblock/ux/lib/Locale/util';
7
- import { formatToDatetime } from '@arcblock/ux/lib/Util';
8
- import type { UserMetadata } from '../../../@types';
9
- import { DurationEnum, StatusEnum } from '../../../@types';
10
- import StatusDialog from '../status-dialog';
11
- import { translations } from '../../libs/locales';
12
- import { getTimeRemaining, isNotClear, isWithinTimeRange } from './utils';
13
- import { StatusItem } from '../status-selector/menu-item';
14
-
15
- const MeetingIcon = lazy(() => import('@arcblock/icons/lib/Meeting'));
16
- const CommunityIcon = lazy(() => import('@arcblock/icons/lib/Community'));
17
- const HolidayIcon = lazy(() => import('@arcblock/icons/lib/Holiday'));
18
- const OffSickIcon = lazy(() => import('@arcblock/icons/lib/OffSick'));
19
- const WorkingRemotelyIcon = lazy(() => import('@arcblock/icons/lib/WorkingRemotely'));
20
-
21
- const StatusIconMap: Record<StatusEnum, React.FC<SvgIconProps> | undefined> = {
22
- [StatusEnum.Meeting]: MeetingIcon,
23
- [StatusEnum.Community]: CommunityIcon,
24
- [StatusEnum.Holiday]: HolidayIcon,
25
- [StatusEnum.OffSick]: OffSickIcon,
26
- [StatusEnum.WorkingRemotely]: WorkingRemotelyIcon,
27
- };
28
-
29
- const QuickSettings = {
30
- [StatusEnum.Meeting]: {
31
- duration: DurationEnum.OneHour,
32
- durationName: 'userStatus.duration.OneHour',
33
- },
34
- [StatusEnum.Community]: {
35
- duration: DurationEnum.ThirtyMinutes,
36
- durationName: 'userStatus.duration.ThirtyMinutes',
37
- },
38
- [StatusEnum.Holiday]: {
39
- duration: DurationEnum.ThisWeek,
40
- durationName: 'userStatus.duration.ThisWeek',
41
- },
42
- [StatusEnum.OffSick]: {
43
- duration: DurationEnum.Today,
44
- durationName: 'userStatus.duration.Today',
45
- },
46
- [StatusEnum.WorkingRemotely]: {
47
- duration: DurationEnum.ThisWeek,
48
- durationName: 'userStatus.duration.ThisWeek',
49
- },
50
- };
51
-
52
- export default function UserStatus({
53
- isMobile = undefined,
54
- size,
55
- isMyself,
56
- status,
57
- onChange,
58
- timezone = undefined,
59
- }: {
60
- isMobile?: boolean;
61
- size: number;
62
- isMyself: boolean;
63
- status: UserMetadata['status'];
64
- onChange: (v: UserMetadata['status']) => void;
65
- timezone?: string;
66
- }) {
67
- const { locale } = useLocaleContext();
68
- const t = useMemoizedFn((key, data = {}) => {
69
- return translate(translations, key, locale, 'en', data);
70
- });
71
-
72
- const [interval, setInterval] = useState<number | undefined>(undefined);
73
-
74
- const pauseInterval = useMemoizedFn(() => {
75
- setInterval(undefined);
76
- });
77
-
78
- useEffect(() => {
79
- setInterval(1000);
80
- }, [status]);
81
-
82
- const clear = useInterval(() => {
83
- if (status?.value && status?.dateRange?.length === 2) {
84
- const notClear = isNotClear(status);
85
- if (notClear) {
86
- return;
87
- }
88
- const isWithin = isWithinTimeRange(status.dateRange as [Date, Date]);
89
- if (!isWithin) {
90
- pauseInterval();
91
- onChange(undefined);
92
- } else {
93
- // 根据距离结束时间长度,设置 interval
94
- const timeRemaining = getTimeRemaining(status.dateRange[1]);
95
- if (timeRemaining > 0) {
96
- setInterval(timeRemaining);
97
- } else {
98
- pauseInterval();
99
- onChange(undefined);
100
- }
101
- }
102
- } else {
103
- pauseInterval();
104
- }
105
- }, interval);
106
-
107
- useUnmount(() => {
108
- clear();
109
- });
110
-
111
- const [anchorEl, setAnchorEl] = useState<HTMLDivElement | null>(null);
112
-
113
- const getDurationData = useCallback(() => {
114
- const data = Object.keys(DurationEnum).map((key) => ({
115
- id: DurationEnum[key as keyof typeof DurationEnum],
116
- name: t(`userStatus.duration.${key}`),
117
- }));
118
- return data;
119
- }, [t]);
120
-
121
- const statusData = useCreation(() => {
122
- const durationData = getDurationData();
123
- return Object.keys(StatusEnum).map((key) => {
124
- const quickSetting = QuickSettings[StatusEnum[key as keyof typeof StatusEnum]];
125
-
126
- return {
127
- id: StatusEnum[key as keyof typeof StatusEnum],
128
- name: t(`userStatus.${key}`),
129
- icon: StatusIconMap[StatusEnum[key as keyof typeof StatusEnum]],
130
- ...(quickSetting ? { duration: quickSetting.duration, durationName: t(quickSetting.durationName) } : {}),
131
- children: durationData,
132
- };
133
- });
134
- }, [t, getDurationData, locale]);
135
-
136
- const onOpenStatusSelector = (event: React.MouseEvent<HTMLDivElement>) => {
137
- if (!isMyself) {
138
- return;
139
- }
140
- setAnchorEl(event.currentTarget);
141
- };
142
-
143
- const onCloseStatusSelector = () => {
144
- setAnchorEl(null);
145
- };
146
-
147
- const onStatusChange = (v?: UserMetadata['status']) => {
148
- if (!isMyself) {
149
- return;
150
- }
151
- onChange(v);
152
- onCloseStatusSelector();
153
- };
154
-
155
- const StatusIcon = StatusIconMap[status?.value as keyof typeof StatusIconMap];
156
-
157
- const tooltipTitle = useMemo(() => {
158
- const currentStatus = statusData.find((item) => item.id === status?.value);
159
- if (currentStatus) {
160
- const localeOption = locale === 'zh' ? 'zh-cn' : 'en-us';
161
- let range;
162
- const notClear = isNotClear(status);
163
- if (!notClear) {
164
- range = status?.dateRange?.map((item) => {
165
- return formatToDatetime(item, { locale: localeOption });
166
- });
167
- }
168
- if (range && range.length > 0) {
169
- return `${currentStatus.name}: ${range.join('~')}`;
170
- }
171
- return currentStatus.name;
172
- }
173
- return null;
174
- }, [status, statusData, locale]);
175
-
176
- const open = Boolean(anchorEl);
177
-
178
- return (
179
- <StatusDiv size={size} isMobile={isMobile}>
180
- <Tooltip title={tooltipTitle}>
181
- <Box
182
- className="status-icon"
183
- onClick={onOpenStatusSelector}
184
- sx={{
185
- display: 'flex',
186
- alignItems: 'center',
187
- justifyContent: 'center',
188
- }}>
189
- {StatusIcon ? (
190
- <Suspense fallback={null}>
191
- <StatusIcon style={{ width: 16, height: 16 }} />
192
- </Suspense>
193
- ) : (
194
- <Badge color="success" variant="dot" />
195
- )}
196
- </Box>
197
- </Tooltip>
198
- {open && (
199
- <StatusDialog
200
- selected={status}
201
- data={statusData as StatusItem[]}
202
- open={open}
203
- onSelect={onStatusChange}
204
- onClose={onCloseStatusSelector}
205
- timezone={timezone}
206
- />
207
- )}
208
- </StatusDiv>
209
- );
210
- }
211
-
212
- const StatusDiv = styled('div')<{ size: number; isMobile?: boolean }>`
213
- position: absolute;
214
- left: ${({ size }) => `${(size * 3) / 4}px`};
215
- top: ${({ size }) => `${size * 0.65}px`};
216
- width: ${({ isMobile }) => (isMobile ? '22px' : '32px')};
217
- height: ${({ isMobile }) => (isMobile ? '22px' : '32px')};
218
- border-radius: ${({ isMobile }) => (isMobile ? '11px' : '16px')};
219
- display: flex;
220
- align-items: center;
221
- justify-content: center;
222
- background-color: #ffffff;
223
- overflow: hidden;
224
- white-space: nowrap;
225
- cursor: pointer;
226
-
227
- .status-icon {
228
- flex-shrink: 0;
229
- width: ${({ isMobile }) => (isMobile ? '16px' : '26px')};
230
- height: ${({ isMobile }) => (isMobile ? '16px' : '26px')};
231
- border-radius: ${({ isMobile }) => (isMobile ? '8px' : '13px')};
232
- background-color: #eff1f5;
233
- }
234
- `;
@@ -1,320 +0,0 @@
1
- import isUrl from 'is-url';
2
- import { withHttps } from 'ufo';
3
- import dayjs from 'dayjs';
4
- import timezone from 'dayjs/plugin/timezone';
5
- import utc from 'dayjs/plugin/utc';
6
- import { DurationEnum, UserMetadata } from '../../../@types';
7
-
8
- // 扩展 dayjs 插件
9
- dayjs.extend(utc);
10
- dayjs.extend(timezone);
11
-
12
- const HOUR = 3600;
13
- const MINUTES_30 = 1800;
14
- const MINUTES_10 = 600;
15
- const MINUTES_5 = 300;
16
- const MINUTES_1 = 60;
17
- const SECOND = 1;
18
-
19
- export const currentTimezone = dayjs.tz.guess();
20
-
21
- // 常用时区列表,作为兼容性 fallback
22
- const COMMON_TIMEZONES = [
23
- 'America/New_York',
24
- 'America/Chicago',
25
- 'America/Denver',
26
- 'America/Los_Angeles',
27
- 'Europe/London',
28
- 'Europe/Paris',
29
- 'Europe/Berlin',
30
- 'Europe/Rome',
31
- 'Asia/Tokyo',
32
- 'Asia/Shanghai',
33
- 'Asia/Hong_Kong',
34
- 'Asia/Singapore',
35
- 'Asia/Seoul',
36
- 'Asia/Kolkata',
37
- 'Australia/Sydney',
38
- 'Australia/Melbourne',
39
- 'Pacific/Auckland',
40
- 'America/Sao_Paulo',
41
- 'America/Mexico_City',
42
- 'Africa/Cairo',
43
- 'UTC',
44
- ];
45
-
46
- // 获取时区列表的兼容性函数
47
- const getTimezoneList = () => {
48
- // 优先使用现代 API
49
- if (typeof Intl !== 'undefined' && Intl.supportedValuesOf) {
50
- try {
51
- return Intl.supportedValuesOf('timeZone');
52
- } catch (error) {
53
- console.warn('Intl.supportedValuesOf not supported, falling back to common timezones');
54
- }
55
- }
56
-
57
- // 尝试使用 Intl.DateTimeFormat 获取时区
58
- if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
59
- try {
60
- // 使用 resolvedOptions 检测当前时区是否可用
61
- const formatter = new Intl.DateTimeFormat('en', { timeZone: 'UTC' });
62
- if (formatter.resolvedOptions().timeZone) {
63
- return COMMON_TIMEZONES;
64
- }
65
- } catch (error) {
66
- console.warn('Intl.DateTimeFormat timezone support limited');
67
- }
68
- }
69
-
70
- // 最后的 fallback
71
- return COMMON_TIMEZONES;
72
- };
73
-
74
- export const getTimezones = () => {
75
- const timezones = getTimezoneList();
76
-
77
- const formattedTimezones = timezones
78
- .map((tz) => {
79
- try {
80
- const offset = dayjs.tz(dayjs(), tz).utcOffset() / 60; // 计算 UTC 偏移 (小时)
81
- const hours = Math.floor(offset);
82
- const minutes = (offset % 1) * 60;
83
- const label = `GMT${hours >= 0 ? '+' : ''}${hours}:${minutes === 30 ? '30' : '00'}`;
84
-
85
- return { label, value: tz };
86
- } catch (error) {
87
- // 如果时区不支持,跳过
88
- console.warn(`Timezone ${tz} not supported, skipping`);
89
- return null;
90
- }
91
- })
92
- .filter((tz): tz is { label: string; value: string } => tz !== null); // 类型守卫
93
-
94
- return formattedTimezones
95
- .sort((a, b) => {
96
- const [hoursA, minutesA] = a.label.replace('GMT', '').split(':').map(Number);
97
- const [hoursB, minutesB] = b.label.replace('GMT', '').split(':').map(Number);
98
- const totalOffsetA = hoursA * 60 + minutesA; // 统一为分钟数
99
- const totalOffsetB = hoursB * 60 + minutesB;
100
- return totalOffsetB - totalOffsetA; // **降序排列**
101
- })
102
- .map((tz) => ({
103
- label: `(${tz.label}) ${tz.value}`,
104
- value: tz.value,
105
- }));
106
- };
107
-
108
- export const isValidUrl = (url: string) => {
109
- return isUrl(withHttps(url)); // 补充协议后在进行验证是否是合法的url
110
- };
111
-
112
- export const isDuplicateUrl = (url1: string, url2: string) => {
113
- if (!url1 || !url2) {
114
- return false;
115
- }
116
- if (!isValidUrl(url1) || !isValidUrl(url2)) {
117
- return false;
118
- }
119
-
120
- const parsedUrl1 = withHttps(url1.trim());
121
- const parsedUrl2 = withHttps(url2.trim());
122
- return parsedUrl1.toLowerCase() === parsedUrl2.toLowerCase();
123
- };
124
-
125
- /**
126
- * 根据 duration 类型,计算出date range
127
- * @param status
128
- * @returns
129
- */
130
- export const getStatusDuration = (status: UserMetadata['status']) => {
131
- let dateRange: dayjs.Dayjs[] = status?.dateRange?.map((d) => dayjs(d)) ?? [];
132
- const current = dayjs();
133
- switch (status?.duration) {
134
- case DurationEnum.ThirtyMinutes:
135
- dateRange = [current, current.add(30, 'minutes')];
136
- break;
137
- case DurationEnum.OneHour:
138
- dateRange = [current, current.add(1, 'hour')];
139
- break;
140
- case DurationEnum.FourHours:
141
- dateRange = [current, current.add(4, 'hours')];
142
- break;
143
- case DurationEnum.Today:
144
- dateRange = [current, current.endOf('day')];
145
- break;
146
- case DurationEnum.ThisWeek:
147
- dateRange = [current, current.endOf('week')];
148
- break;
149
- case DurationEnum.NoClear:
150
- dateRange = [current, current];
151
- break;
152
- default:
153
- break;
154
- }
155
- return dateRange.map((d) => d.toDate());
156
- };
157
-
158
- /**
159
- * 根据状态的 duration,判断是否在时间范围内
160
- * @param status
161
- * @returns
162
- */
163
- export const isWithinTimeRange = (dateRange: [Date, Date]) => {
164
- const current = dayjs();
165
- return current.isAfter(dayjs(dateRange[0])) && current.isBefore(dayjs(dateRange[1]));
166
- };
167
-
168
- /**
169
- * 判断状态持续时间是否为不可清除
170
- * @param status
171
- * @returns
172
- */
173
- export const isNotClear = (status: UserMetadata['status']) => {
174
- const { duration, dateRange } = status ?? {};
175
- if (!duration || !dateRange) {
176
- return false;
177
- }
178
- return duration === DurationEnum.NoClear || dayjs(dateRange?.[0]).isSame(dayjs(dateRange?.[1]));
179
- };
180
-
181
- /**
182
- * 获取当前时间距离结束时间还有多久
183
- */
184
- export const getTimeRemaining = (date: Date) => {
185
- const now = dayjs();
186
- const end = dayjs(date);
187
- const diffSeconds = end.diff(now, 'seconds');
188
-
189
- // 转换为毫秒
190
- const toMilliseconds = (seconds: number) => seconds * 1000;
191
-
192
- if (diffSeconds >= HOUR) {
193
- return toMilliseconds(HOUR); // 1小时 = 3600000ms
194
- }
195
- if (diffSeconds >= MINUTES_30) {
196
- return toMilliseconds(MINUTES_30); // 30分钟 = 1800000ms
197
- }
198
- if (diffSeconds >= MINUTES_10) {
199
- return toMilliseconds(MINUTES_10); // 10分钟 = 600000ms
200
- }
201
- if (diffSeconds >= MINUTES_5) {
202
- return toMilliseconds(MINUTES_5); // 5分钟 = 300000ms
203
- }
204
- if (diffSeconds >= MINUTES_1) {
205
- return toMilliseconds(MINUTES_1); // 1分钟 = 60000ms
206
- }
207
- if (diffSeconds >= SECOND) {
208
- return toMilliseconds(SECOND); // 1秒 = 1000ms
209
- }
210
-
211
- return 0; // 如果时间已过期,返回0
212
- };
213
-
214
- // 只支持在 sx 中使用
215
- export const defaultButtonStyle = {
216
- color: 'text.primary',
217
- borderColor: 'grey.100',
218
- backgroundColor: 'background.default',
219
- '&:hover': {
220
- borderColor: 'grey.100',
221
- backgroundColor: 'action.hover',
222
- },
223
- py: 0.5,
224
- borderRadius: 1,
225
- };
226
-
227
- export const primaryButtonStyle = {
228
- color: 'primary.contrastText',
229
- borderColor: 'primary.main',
230
- backgroundColor: 'primary.main',
231
- '&:hover': {
232
- borderColor: 'primary.main',
233
- backgroundColor: 'primary.main',
234
- },
235
- py: 0.5,
236
- borderRadius: 1,
237
- };
238
-
239
- // 域名关键词到平台标识符的映射表
240
- const DOMAIN_PLATFORM_MAP: Record<string, { domains: string[]; options?: Record<string, any> }> = {
241
- x: {
242
- domains: ['twitter.com', 'x.com'],
243
- },
244
- facebook: {
245
- domains: ['facebook.com', 'fb.com'],
246
- options: { skipDarkInvert: true },
247
- },
248
- 'linkedin-icon': {
249
- domains: ['linkedin.com'],
250
- options: { skipDarkInvert: true },
251
- },
252
- 'github-icon': {
253
- domains: ['github.com'],
254
- },
255
- 'instagram-icon': {
256
- domains: ['instagram.com'],
257
- },
258
- 'youtube-icon': {
259
- domains: ['youtube.com', 'youtu.be'],
260
- options: { skipDarkInvert: true },
261
- },
262
- 'tiktok-icon': {
263
- domains: ['tiktok.com'],
264
- },
265
- 'reddit-icon': {
266
- domains: ['reddit.com'],
267
- options: { skipDarkInvert: true },
268
- },
269
- 'medium-icon': {
270
- domains: ['medium.com'],
271
- },
272
- 'discord-icon': {
273
- domains: ['discord.com', 'discord.gg'],
274
- options: { skipDarkInvert: true },
275
- },
276
- telegram: {
277
- domains: ['telegram.org', 't.me'],
278
- options: { skipDarkInvert: true },
279
- },
280
- 'whatsapp-monochrome-icon': {
281
- domains: ['whatsapp.com'],
282
- },
283
- producthunt: {
284
- domains: ['producthunt.com'],
285
- options: { skipDarkInvert: true },
286
- },
287
- ycombinator: {
288
- domains: ['ycombinator.com', 'news.ycombinator.com'],
289
- options: { skipDarkInvert: true },
290
- },
291
- };
292
-
293
- export const getLogoByUrl = (url: string): { icon: string; options?: Record<string, any> } | undefined => {
294
- try {
295
- // 添加协议(如果没有)
296
- const fullUrl = withHttps(url);
297
-
298
- // 解析 URL
299
- const urlObj = new URL(fullUrl);
300
- const hostname = urlObj.hostname.toLowerCase();
301
-
302
- // 移除 www. 前缀
303
- const domain = hostname.replace(/^www\./, '');
304
-
305
- // 根据域名返回对应的平台标识符
306
- for (const [platform, { domains, options }] of Object.entries(DOMAIN_PLATFORM_MAP)) {
307
- if (domains.some((d) => domain === d || domain.endsWith(`.${d}`))) {
308
- return {
309
- icon: `logos:${platform}`,
310
- options,
311
- };
312
- }
313
- }
314
-
315
- // 对于未匹配的域名,返回空字符串
316
- return undefined;
317
- } catch {
318
- return undefined;
319
- }
320
- };