your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import NumberFlow, { NumberFlowGroup } from '@number-flow/svelte';
3 import type { ContentComponentProps } from '../types';
4 import type { ClockCardData } from './index';
5 import { onMount } from 'svelte';
6
7 let { item }: ContentComponentProps = $props();
8
9 let cardData = $derived(item.cardData as ClockCardData);
10
11 let now = $state(new Date());
12
13 onMount(() => {
14 const interval = setInterval(() => {
15 now = new Date();
16 }, 1000);
17 return () => clearInterval(interval);
18 });
19
20 let clockParts = $derived.by(() => {
21 try {
22 return new Intl.DateTimeFormat('en-US', {
23 timeZone: cardData.timezone || 'UTC',
24 hour: '2-digit',
25 minute: '2-digit',
26 second: '2-digit',
27 hour12: false
28 }).formatToParts(now);
29 } catch {
30 return null;
31 }
32 });
33
34 let clockHours = $derived(
35 clockParts ? parseInt(clockParts.find((p) => p.type === 'hour')?.value || '0') : 0
36 );
37 let clockMinutes = $derived(
38 clockParts ? parseInt(clockParts.find((p) => p.type === 'minute')?.value || '0') : 0
39 );
40 let clockSeconds = $derived(
41 clockParts ? parseInt(clockParts.find((p) => p.type === 'second')?.value || '0') : 0
42 );
43
44 let timezoneDisplay = $derived.by(() => {
45 if (!cardData.timezone) return '';
46 try {
47 const formatter = new Intl.DateTimeFormat('en-US', {
48 timeZone: cardData.timezone,
49 timeZoneName: 'short'
50 });
51 const parts = formatter.formatToParts(now);
52 return parts.find((p) => p.type === 'timeZoneName')?.value || cardData.timezone;
53 } catch {
54 return cardData.timezone;
55 }
56 });
57</script>
58
59<div class="@container flex h-full w-full flex-col items-center justify-center p-4">
60 <NumberFlowGroup>
61 <div
62 class="text-base-900 dark:text-base-100 accent:text-base-900 flex items-center text-3xl font-bold @xs:text-4xl @sm:text-5xl @md:text-6xl @lg:text-7xl"
63 style="font-variant-numeric: tabular-nums;"
64 >
65 <NumberFlow value={clockHours} format={{ minimumIntegerDigits: 2 }} />
66 <span class="text-base-400 dark:text-base-500 accent:text-accent-950 mx-0.5">:</span>
67 <NumberFlow
68 value={clockMinutes}
69 format={{ minimumIntegerDigits: 2 }}
70 digits={{ 1: { max: 5 } }}
71 trend={1}
72 />
73 <span class="text-base-400 dark:text-base-500 accent:text-accent-950 mx-0.5">:</span>
74 <NumberFlow
75 value={clockSeconds}
76 format={{ minimumIntegerDigits: 2 }}
77 digits={{ 1: { max: 5 } }}
78 trend={1}
79 />
80 </div>
81 </NumberFlowGroup>
82 {#if timezoneDisplay}
83 <div class="text-base-500 dark:text-base-400 accent:text-base-600 mt-1 text-xs @sm:text-sm">
84 {timezoneDisplay}
85 </div>
86 {/if}
87</div>