@blocklet/ui-react 2.12.16 → 2.12.18
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/UserCenter/components/user-center.js +11 -2
- package/lib/UserCenter/components/user-info/clock.d.ts +2 -3
- package/lib/UserCenter/components/user-info/clock.js +47 -23
- package/lib/UserCenter/components/user-info/metadata.js +4 -5
- package/lib/UserCenter/libs/locales.d.ts +12 -0
- package/lib/UserCenter/libs/locales.js +14 -2
- package/lib/hooks/use-clock.d.ts +9 -0
- package/lib/hooks/use-clock.js +49 -0
- package/package.json +5 -5
- package/src/UserCenter/components/user-center.tsx +22 -3
- package/src/UserCenter/components/user-info/clock.tsx +38 -27
- package/src/UserCenter/components/user-info/metadata.tsx +4 -8
- package/src/UserCenter/libs/locales.ts +12 -0
- package/src/hooks/use-clock.tsx +61 -0
|
@@ -498,7 +498,16 @@ export default function UserCenter({
|
|
|
498
498
|
}
|
|
499
499
|
return currentActiveTab?.isPrivate;
|
|
500
500
|
}, [isMyself, currentActiveTab]);
|
|
501
|
-
|
|
501
|
+
const shouldRedirect = useCreation(() => {
|
|
502
|
+
if (onlyProfile) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
const noActiveTabButHasTabs = !disableAutoRedirect && !currentTab && userCenterTabs?.length > 0;
|
|
506
|
+
const invalidCurrentTab = !currentActiveTab;
|
|
507
|
+
const accessingPrivateTab = isPrivateActive;
|
|
508
|
+
return noActiveTabButHasTabs || invalidCurrentTab || accessingPrivateTab;
|
|
509
|
+
}, [disableAutoRedirect, currentTab, userCenterTabs, currentActiveTab, isPrivateActive, onlyProfile]);
|
|
510
|
+
if (shouldRedirect) {
|
|
502
511
|
const firstUserCenterUrl = userCenterTabs[0]?.url;
|
|
503
512
|
const firstTab = userCenterTabs.find((x) => x.value === firstUserCenterUrl);
|
|
504
513
|
if (firstUserCenterUrl && !firstTab?.isPrivate) {
|
|
@@ -510,7 +519,7 @@ export default function UserCenter({
|
|
|
510
519
|
}
|
|
511
520
|
return null;
|
|
512
521
|
}
|
|
513
|
-
if (embed) {
|
|
522
|
+
if (embed || onlyProfile) {
|
|
514
523
|
return /* @__PURE__ */ jsxs(Main, { children: [
|
|
515
524
|
content,
|
|
516
525
|
confirmHolder
|
|
@@ -1,24 +1,48 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import Tooltip from "@mui/material/Tooltip";
|
|
3
|
+
import Typography from "@mui/material/Typography";
|
|
4
|
+
import Box from "@mui/material/Box";
|
|
5
|
+
import { translate } from "@arcblock/ux/lib/Locale/util";
|
|
6
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
7
|
+
import { useMemoizedFn } from "ahooks";
|
|
8
|
+
import { translations } from "../../libs/locales.js";
|
|
9
|
+
import { useClock } from "../../../hooks/use-clock.js";
|
|
10
|
+
export default function Clock({ value }) {
|
|
11
|
+
const { locale } = useLocaleContext();
|
|
12
|
+
const t = useMemoizedFn((key, data = {}) => {
|
|
13
|
+
return translate(translations, key, locale, "en", data);
|
|
14
|
+
});
|
|
15
|
+
const timeInfo = useClock(value, locale);
|
|
16
|
+
return /* @__PURE__ */ jsxs(
|
|
17
|
+
Box,
|
|
18
|
+
{
|
|
19
|
+
sx: {
|
|
20
|
+
whiteSpace: "nowrap",
|
|
21
|
+
overflow: "hidden",
|
|
22
|
+
textOverflow: "ellipsis"
|
|
23
|
+
},
|
|
24
|
+
display: "flex",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
gap: 1,
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ jsx(Typography, { children: value }),
|
|
29
|
+
/* @__PURE__ */ jsx(
|
|
30
|
+
Tooltip,
|
|
31
|
+
{
|
|
32
|
+
title: /* @__PURE__ */ jsxs("span", { children: [
|
|
33
|
+
t("profile.localTime"),
|
|
34
|
+
" ",
|
|
35
|
+
timeInfo.fullDateTime
|
|
36
|
+
] }),
|
|
37
|
+
children: /* @__PURE__ */ jsxs(Typography, { component: "span", fontSize: 14, children: [
|
|
38
|
+
"(",
|
|
39
|
+
locale === "zh" ? `${t(`profile.timezonePhase.${timeInfo.phase}`)} ` : "",
|
|
40
|
+
timeInfo.formattedTime,
|
|
41
|
+
")"
|
|
42
|
+
] })
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
);
|
|
24
48
|
}
|
|
@@ -20,8 +20,8 @@ import { translations } from "../../libs/locales.js";
|
|
|
20
20
|
import EditableField from "../editable-field.js";
|
|
21
21
|
import { LinkPreviewInput } from "./link-preview-input.js";
|
|
22
22
|
import { currentTimezone, defaultButtonStyle, primaryButtonStyle } from "./utils.js";
|
|
23
|
-
import Clock from "./clock.js";
|
|
24
23
|
import { TimezoneSelect } from "./timezone-select.js";
|
|
24
|
+
import Clock from "./clock.js";
|
|
25
25
|
const LocationIcon = lazy(() => import("@arcblock/icons/lib/Location"));
|
|
26
26
|
const TimezoneIcon = lazy(() => import("@arcblock/icons/lib/Timezone"));
|
|
27
27
|
const EmailIcon = lazy(() => import("@arcblock/icons/lib/Email"));
|
|
@@ -245,10 +245,9 @@ export default function UserMetadataComponent({
|
|
|
245
245
|
placeholder: "timezone",
|
|
246
246
|
icon: /* @__PURE__ */ jsx(TimezoneIcon, { ...iconSize }),
|
|
247
247
|
label: t("profile.timezone"),
|
|
248
|
-
|
|
249
|
-
/* @__PURE__ */ jsx(
|
|
250
|
-
|
|
251
|
-
] }),
|
|
248
|
+
renderValue: (value) => {
|
|
249
|
+
return /* @__PURE__ */ jsx(Clock, { value });
|
|
250
|
+
},
|
|
252
251
|
children: /* @__PURE__ */ jsx(
|
|
253
252
|
TimezoneSelect,
|
|
254
253
|
{
|
|
@@ -131,6 +131,12 @@ export declare const translations: {
|
|
|
131
131
|
quickSettings: string;
|
|
132
132
|
selectEndTime: string;
|
|
133
133
|
pleaseSelectTime: string;
|
|
134
|
+
timezonePhase: {
|
|
135
|
+
dawn: string;
|
|
136
|
+
morning: string;
|
|
137
|
+
afternoon: string;
|
|
138
|
+
night: string;
|
|
139
|
+
};
|
|
134
140
|
};
|
|
135
141
|
};
|
|
136
142
|
en: {
|
|
@@ -266,6 +272,12 @@ export declare const translations: {
|
|
|
266
272
|
pleaseSelectTime: string;
|
|
267
273
|
cleanStatus: string;
|
|
268
274
|
quickSettings: string;
|
|
275
|
+
timezonePhase: {
|
|
276
|
+
dawn: string;
|
|
277
|
+
morning: string;
|
|
278
|
+
afternoon: string;
|
|
279
|
+
night: string;
|
|
280
|
+
};
|
|
269
281
|
};
|
|
270
282
|
};
|
|
271
283
|
};
|
|
@@ -130,7 +130,13 @@ export const translations = {
|
|
|
130
130
|
cleanStatus: "\u6E05\u9664\u72B6\u6001",
|
|
131
131
|
quickSettings: "\u5FEB\u6377\u8BBE\u7F6E",
|
|
132
132
|
selectEndTime: "\u9009\u62E9\u7ED3\u675F\u65F6\u95F4",
|
|
133
|
-
pleaseSelectTime: "\u8BF7\u9009\u62E9\u65F6\u95F4"
|
|
133
|
+
pleaseSelectTime: "\u8BF7\u9009\u62E9\u65F6\u95F4",
|
|
134
|
+
timezonePhase: {
|
|
135
|
+
dawn: "\u51CC\u6668",
|
|
136
|
+
morning: "\u4E0A\u5348",
|
|
137
|
+
afternoon: "\u4E0B\u5348",
|
|
138
|
+
night: "\u665A\u4E0A"
|
|
139
|
+
}
|
|
134
140
|
}
|
|
135
141
|
},
|
|
136
142
|
en: {
|
|
@@ -265,7 +271,13 @@ export const translations = {
|
|
|
265
271
|
selectEndTime: "Select end time",
|
|
266
272
|
pleaseSelectTime: "Please select time",
|
|
267
273
|
cleanStatus: "Clean status",
|
|
268
|
-
quickSettings: "Quick Settings"
|
|
274
|
+
quickSettings: "Quick Settings",
|
|
275
|
+
timezonePhase: {
|
|
276
|
+
dawn: "AM",
|
|
277
|
+
morning: "AM",
|
|
278
|
+
afternoon: "PM",
|
|
279
|
+
night: "PM"
|
|
280
|
+
}
|
|
269
281
|
}
|
|
270
282
|
}
|
|
271
283
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from "react";
|
|
2
|
+
import dayjs from "dayjs";
|
|
3
|
+
import utc from "dayjs/plugin/utc";
|
|
4
|
+
import timezonePlugin from "dayjs/plugin/timezone";
|
|
5
|
+
import localizedFormat from "dayjs/plugin/localizedFormat";
|
|
6
|
+
import { formatToDatetime } from "@arcblock/ux/lib/Util";
|
|
7
|
+
import "dayjs/locale/zh-cn";
|
|
8
|
+
import "dayjs/locale/en";
|
|
9
|
+
dayjs.extend(utc);
|
|
10
|
+
dayjs.extend(timezonePlugin);
|
|
11
|
+
dayjs.extend(localizedFormat);
|
|
12
|
+
const currentTimezone = dayjs.tz.guess();
|
|
13
|
+
const getTimePhase = (hour) => {
|
|
14
|
+
if (hour >= 0 && hour < 6)
|
|
15
|
+
return { phase: "dawn", icon: "\u{1F312}" };
|
|
16
|
+
if (hour >= 6 && hour < 12)
|
|
17
|
+
return { phase: "morning", icon: "\u{1F31E}" };
|
|
18
|
+
if (hour >= 12 && hour < 18)
|
|
19
|
+
return { phase: "afternoon", icon: "\u{1F31E}" };
|
|
20
|
+
return { phase: "night", icon: "\u{1F312}" };
|
|
21
|
+
};
|
|
22
|
+
export function useClock(timezone = currentTimezone, locale = "zh") {
|
|
23
|
+
const getLatestTimeInfo = useCallback(() => {
|
|
24
|
+
const currentLocale = locale === "zh" ? "zh-cn" : "en";
|
|
25
|
+
const localeOption = locale === "zh" ? "zh-cn" : "en-us";
|
|
26
|
+
dayjs.locale(currentLocale);
|
|
27
|
+
const now = dayjs().tz(timezone);
|
|
28
|
+
const hour = now.hour();
|
|
29
|
+
const { phase, icon } = getTimePhase(hour);
|
|
30
|
+
return {
|
|
31
|
+
formattedTime: now.format("LT"),
|
|
32
|
+
fullDateTime: formatToDatetime(now.toDate(), { tz: timezone, locale: localeOption }),
|
|
33
|
+
phase,
|
|
34
|
+
icon,
|
|
35
|
+
rawTime: now
|
|
36
|
+
};
|
|
37
|
+
}, [timezone, locale]);
|
|
38
|
+
const [timeInfo, setTimeInfo] = useState(getLatestTimeInfo());
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
setTimeInfo(getLatestTimeInfo());
|
|
41
|
+
const timerId = setInterval(() => {
|
|
42
|
+
setTimeInfo(getLatestTimeInfo());
|
|
43
|
+
}, 6e3);
|
|
44
|
+
return () => {
|
|
45
|
+
clearInterval(timerId);
|
|
46
|
+
};
|
|
47
|
+
}, [timezone, locale, getLatestTimeInfo]);
|
|
48
|
+
return timeInfo;
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/ui-react",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.18",
|
|
4
4
|
"description": "Some useful front-end web components that can be used in Blocklets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@abtnode/constant": "^1.16.39",
|
|
36
|
-
"@arcblock/bridge": "^2.12.
|
|
37
|
-
"@arcblock/react-hooks": "^2.12.
|
|
36
|
+
"@arcblock/bridge": "^2.12.18",
|
|
37
|
+
"@arcblock/react-hooks": "^2.12.18",
|
|
38
38
|
"@arcblock/ws": "^1.19.15",
|
|
39
|
-
"@blocklet/did-space-react": "^1.0.
|
|
39
|
+
"@blocklet/did-space-react": "^1.0.31",
|
|
40
40
|
"@iconify-icons/logos": "^1.2.36",
|
|
41
41
|
"@iconify-icons/material-symbols": "^1.2.58",
|
|
42
42
|
"@iconify/react": "^4.1.1",
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"jest": "^29.7.0",
|
|
88
88
|
"unbuild": "^2.0.0"
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "e5629cf0ff51b952d35fe85d05065740f740048b"
|
|
91
91
|
}
|
|
@@ -566,10 +566,29 @@ export default function UserCenter({
|
|
|
566
566
|
return currentActiveTab?.isPrivate;
|
|
567
567
|
}, [isMyself, currentActiveTab]);
|
|
568
568
|
|
|
569
|
-
//
|
|
570
|
-
|
|
569
|
+
// 判断是否需要重定向到第一个可用的标签页
|
|
570
|
+
const shouldRedirect = useCreation(() => {
|
|
571
|
+
// 非 Profile 模式下才考虑重定向
|
|
572
|
+
if (onlyProfile) {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// 以下任一条件满足时需要重定向:
|
|
577
|
+
// 1. 自动重定向开启且当前无激活标签但有可用标签
|
|
578
|
+
const noActiveTabButHasTabs = !disableAutoRedirect && !currentTab && userCenterTabs?.length > 0;
|
|
579
|
+
// 2. 当前标签页不存在
|
|
580
|
+
const invalidCurrentTab = !currentActiveTab;
|
|
581
|
+
// 3. 当前是私有标签页但用户在查看他人信息
|
|
582
|
+
const accessingPrivateTab = isPrivateActive;
|
|
583
|
+
|
|
584
|
+
return noActiveTabButHasTabs || invalidCurrentTab || accessingPrivateTab;
|
|
585
|
+
}, [disableAutoRedirect, currentTab, userCenterTabs, currentActiveTab, isPrivateActive, onlyProfile]);
|
|
586
|
+
|
|
587
|
+
if (shouldRedirect) {
|
|
588
|
+
// 获取第一个可用的标签页URL
|
|
571
589
|
const firstUserCenterUrl = userCenterTabs[0]?.url;
|
|
572
590
|
const firstTab = userCenterTabs.find((x) => x.value === firstUserCenterUrl);
|
|
591
|
+
// 如果存在非私有的第一个标签页,则重定向
|
|
573
592
|
if (firstUserCenterUrl && !firstTab?.isPrivate) {
|
|
574
593
|
window.location.replace(
|
|
575
594
|
withQuery(firstUserCenterUrl, {
|
|
@@ -581,7 +600,7 @@ export default function UserCenter({
|
|
|
581
600
|
}
|
|
582
601
|
|
|
583
602
|
// 嵌入其它页面内时,只展示 content
|
|
584
|
-
if (embed) {
|
|
603
|
+
if (embed || onlyProfile) {
|
|
585
604
|
return (
|
|
586
605
|
<Main>
|
|
587
606
|
{content}
|
|
@@ -1,30 +1,41 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
2
|
+
import Typography from '@mui/material/Typography';
|
|
3
|
+
import Box from '@mui/material/Box';
|
|
4
|
+
import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
5
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
6
|
+
import { useMemoizedFn } from 'ahooks';
|
|
7
|
+
import { translations } from '../../libs/locales';
|
|
8
|
+
import { useClock } from '../../../hooks/use-clock';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
export default function Clock({ value }: { value: string }) {
|
|
11
|
+
const { locale } = useLocaleContext();
|
|
12
|
+
const t = useMemoizedFn((key, data = {}) => {
|
|
13
|
+
return translate(translations, key, locale, 'en', data);
|
|
14
|
+
});
|
|
15
|
+
const timeInfo = useClock(value, locale);
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
return (
|
|
18
|
+
<Box
|
|
19
|
+
sx={{
|
|
20
|
+
whiteSpace: 'nowrap',
|
|
21
|
+
overflow: 'hidden',
|
|
22
|
+
textOverflow: 'ellipsis',
|
|
23
|
+
}}
|
|
24
|
+
display="flex"
|
|
25
|
+
alignItems="center"
|
|
26
|
+
gap={1}>
|
|
27
|
+
<Typography>{value}</Typography>
|
|
28
|
+
<Tooltip
|
|
29
|
+
title={
|
|
30
|
+
<span>
|
|
31
|
+
{t('profile.localTime')} {timeInfo.fullDateTime}
|
|
32
|
+
</span>
|
|
33
|
+
}>
|
|
34
|
+
<Typography component="span" fontSize={14}>
|
|
35
|
+
({locale === 'zh' ? `${t(`profile.timezonePhase.${timeInfo.phase}`)} ` : ''}
|
|
36
|
+
{timeInfo.formattedTime})
|
|
37
|
+
</Typography>
|
|
38
|
+
</Tooltip>
|
|
39
|
+
</Box>
|
|
40
|
+
);
|
|
30
41
|
}
|
|
@@ -18,15 +18,14 @@ import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
|
18
18
|
import isEmail from 'validator/lib/isEmail';
|
|
19
19
|
import { temp as colors } from '@arcblock/ux/lib/Colors';
|
|
20
20
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
21
|
-
|
|
22
21
|
import { useBrowser } from '@arcblock/react-hooks';
|
|
23
22
|
import { translations } from '../../libs/locales';
|
|
24
23
|
import type { User, UserMetadata, UserPhoneProps } from '../../../@types';
|
|
25
24
|
import EditableField from '../editable-field';
|
|
26
25
|
import { LinkPreviewInput } from './link-preview-input';
|
|
27
26
|
import { currentTimezone, defaultButtonStyle, primaryButtonStyle } from './utils';
|
|
28
|
-
import Clock from './clock';
|
|
29
27
|
import { TimezoneSelect } from './timezone-select';
|
|
28
|
+
import Clock from './clock';
|
|
30
29
|
|
|
31
30
|
const LocationIcon = lazy(() => import('@arcblock/icons/lib/Location'));
|
|
32
31
|
const TimezoneIcon = lazy(() => import('@arcblock/icons/lib/Timezone'));
|
|
@@ -270,12 +269,9 @@ export default function UserMetadataComponent({
|
|
|
270
269
|
placeholder="timezone"
|
|
271
270
|
icon={<TimezoneIcon {...iconSize} />}
|
|
272
271
|
label={t('profile.timezone')}
|
|
273
|
-
|
|
274
|
-
<
|
|
275
|
-
|
|
276
|
-
<Clock timezone={metadata.timezone} locale={locale} />
|
|
277
|
-
</p>
|
|
278
|
-
}>
|
|
272
|
+
renderValue={(value) => {
|
|
273
|
+
return <Clock value={value} />;
|
|
274
|
+
}}>
|
|
279
275
|
<TimezoneSelect
|
|
280
276
|
value={metadata.timezone || currentTimezone}
|
|
281
277
|
onChange={(value) => onChange(value, 'timezone')}
|
|
@@ -133,6 +133,12 @@ export const translations = {
|
|
|
133
133
|
quickSettings: '快捷设置',
|
|
134
134
|
selectEndTime: '选择结束时间',
|
|
135
135
|
pleaseSelectTime: '请选择时间',
|
|
136
|
+
timezonePhase: {
|
|
137
|
+
dawn: '凌晨',
|
|
138
|
+
morning: '上午',
|
|
139
|
+
afternoon: '下午',
|
|
140
|
+
night: '晚上',
|
|
141
|
+
},
|
|
136
142
|
},
|
|
137
143
|
},
|
|
138
144
|
en: {
|
|
@@ -270,6 +276,12 @@ export const translations = {
|
|
|
270
276
|
pleaseSelectTime: 'Please select time',
|
|
271
277
|
cleanStatus: 'Clean status',
|
|
272
278
|
quickSettings: 'Quick Settings',
|
|
279
|
+
timezonePhase: {
|
|
280
|
+
dawn: 'AM',
|
|
281
|
+
morning: 'AM',
|
|
282
|
+
afternoon: 'PM',
|
|
283
|
+
night: 'PM',
|
|
284
|
+
},
|
|
273
285
|
},
|
|
274
286
|
},
|
|
275
287
|
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import utc from 'dayjs/plugin/utc';
|
|
4
|
+
import timezonePlugin from 'dayjs/plugin/timezone';
|
|
5
|
+
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
|
6
|
+
import { formatToDatetime } from '@arcblock/ux/lib/Util';
|
|
7
|
+
import 'dayjs/locale/zh-cn';
|
|
8
|
+
import 'dayjs/locale/en';
|
|
9
|
+
|
|
10
|
+
dayjs.extend(utc);
|
|
11
|
+
dayjs.extend(timezonePlugin);
|
|
12
|
+
dayjs.extend(localizedFormat);
|
|
13
|
+
|
|
14
|
+
const currentTimezone = dayjs.tz.guess();
|
|
15
|
+
|
|
16
|
+
// 获取时间段
|
|
17
|
+
const getTimePhase = (hour: number) => {
|
|
18
|
+
if (hour >= 0 && hour < 6) return { phase: 'dawn', icon: '🌒' }; // 凌晨 00:00-05:59
|
|
19
|
+
if (hour >= 6 && hour < 12) return { phase: 'morning', icon: '🌞' }; // 上午 06:00-11:59
|
|
20
|
+
if (hour >= 12 && hour < 18) return { phase: 'afternoon', icon: '🌞' }; // 下午 12:00-17:59
|
|
21
|
+
return { phase: 'night', icon: '🌒' }; // 晚上 18:00-23:59
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function useClock(timezone = currentTimezone, locale = 'zh') {
|
|
25
|
+
const getLatestTimeInfo = useCallback(() => {
|
|
26
|
+
const currentLocale = locale === 'zh' ? 'zh-cn' : 'en';
|
|
27
|
+
const localeOption = locale === 'zh' ? 'zh-cn' : 'en-us';
|
|
28
|
+
dayjs.locale(currentLocale);
|
|
29
|
+
|
|
30
|
+
const now = dayjs().tz(timezone);
|
|
31
|
+
const hour = now.hour();
|
|
32
|
+
const { phase, icon } = getTimePhase(hour);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
formattedTime: now.format('LT'),
|
|
36
|
+
fullDateTime: formatToDatetime(now.toDate(), { tz: timezone, locale: localeOption }),
|
|
37
|
+
phase,
|
|
38
|
+
icon,
|
|
39
|
+
rawTime: now,
|
|
40
|
+
};
|
|
41
|
+
}, [timezone, locale]);
|
|
42
|
+
|
|
43
|
+
const [timeInfo, setTimeInfo] = useState(getLatestTimeInfo());
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
// 立即更新一次,确保初始状态是最新的
|
|
47
|
+
setTimeInfo(getLatestTimeInfo());
|
|
48
|
+
|
|
49
|
+
// 设置定时器
|
|
50
|
+
const timerId = setInterval(() => {
|
|
51
|
+
setTimeInfo(getLatestTimeInfo());
|
|
52
|
+
}, 6000);
|
|
53
|
+
|
|
54
|
+
// 清理函数
|
|
55
|
+
return () => {
|
|
56
|
+
clearInterval(timerId);
|
|
57
|
+
};
|
|
58
|
+
}, [timezone, locale, getLatestTimeInfo]);
|
|
59
|
+
|
|
60
|
+
return timeInfo;
|
|
61
|
+
}
|