-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLocalTime.tsx
More file actions
94 lines (81 loc) · 2.53 KB
/
Copy pathLocalTime.tsx
File metadata and controls
94 lines (81 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"use client"
import { type FC, useEffect, useState } from "react"
import { useNow, useTranslations } from "next-intl"
import dayjs from "dayjs"
import timezone from "dayjs/plugin/timezone"
import utc from "dayjs/plugin/utc"
import { AnimatePresence } from "framer-motion"
import { DEFAULT_TIMEZONE } from "@shared/i18n/request"
import { cn } from "@shared/lib"
import { RotateNumber } from "@shared/motion-ui"
import { Badge } from "@shared/ui"
dayjs.extend(utc)
dayjs.extend(timezone)
type Props = {
className?: string
}
/**
* LocalTime component to display the current time in the specified timezone.
* It shows a loading state until the time is available, then displays the formatted time.
*/
export const LocalTime: FC<Props> = ({ className }) => {
const t = useTranslations("Layout")
const now = useNow({
updateInterval: 1000,
})
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
setIsLoading(false)
}, [])
const formattedTime = dayjs(now).tz(DEFAULT_TIMEZONE).format("HH:mm:ss")
if (isLoading) {
return (
<div
aria-label={t("localeTime")}
className={cn("flex animate-pulse items-center gap-2", className)}
>
<p className="select-none font-mono text-sm font-medium text-foreground">
{t("localeTime")}
</p>
<Badge
className="select-none rounded-xl border-border px-4 py-2 font-mono text-sm hover:bg-secondary"
variant="secondary"
>
<time>00:00:00</time>
</Badge>
</div>
)
}
return (
<div
aria-live="polite"
className={cn(
"flex items-center gap-2 transition-opacity duration-300",
className,
)}
>
<p className="animate-fade-in select-none font-mono text-sm font-medium text-highlight">
{t("localeTime")}
</p>
<Badge
className="group relative h-full min-h-10 select-none overflow-hidden rounded-xl border-border px-4 py-2 font-mono text-sm hover:bg-secondary"
variant="secondary"
>
<div className="relative flex">
<AnimatePresence mode="popLayout">
{formattedTime.split("").map((char, index) => (
<time
key={`${index}-${char}`}
aria-live="assertive"
style={{ height: "1.5em" }}
>
{char === ":" ? <span>:</span> : <RotateNumber number={char} />}
</time>
))}
</AnimatePresence>
</div>
</Badge>
</div>
)
}
LocalTime.displayName = "LocalTime"