[READ-ONLY] Mirror of https://github.com/mrgnw/morganwill.com.
morganwill.com
2.5 kB
103 lines
1<script>
2 let { targetDate, label = "" } = $props();
3
4 let days = $state(0);
5 let hours = $state(0);
6 let minutes = $state(0);
7 let seconds = $state(0);
8 let countingUp = $state(false); // <-- make this reactive state
9
10 function updateCountdown() {
11 const now = new Date().getTime();
12 countingUp = now > targetDate; // <-- update per tick
13 const distance = Math.abs(targetDate - now);
14
15 days = Math.floor(distance / (1000 * 60 * 60 * 24));
16 hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
17 minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
18 seconds = Math.floor((distance % (1000 * 60)) / 1000);
19 }
20
21 let intervalId;
22
23 $effect(() => {
24 updateCountdown();
25 intervalId = setInterval(updateCountdown, 1000);
26
27 return () => clearInterval(intervalId);
28 });
29
30 function padNumber(num) {
31 return num.toString().padStart(2, "0");
32 }
33
34 let timeUnits = $derived([
35 {
36 value: days,
37 label: "Day",
38 size: "text-7xl",
39 weight: "font-bold",
40 opacity: "",
41 },
42 {
43 value: hours,
44 label: "Hour",
45 size: "text-6xl",
46 weight: "font-semibold",
47 opacity: "80",
48 },
49 {
50 value: minutes,
51 label: "Minute",
52 size: "text-5xl",
53 weight: "font-medium",
54 opacity: "60",
55 },
56 {
57 value: seconds,
58 label: "Second",
59 size: "text-4xl",
60 weight: "font-normal",
61 opacity: "40",
62 },
63 ]);
64</script>
65
66<div class="flex flex-col items-center justify-center">
67 <div
68 class="bg-white p-8 rounded-2xl shadow-md flex flex-col items-center gap-2 max-w-3xl border border-gray-200"
69 >
70 {#if label}
71 <h2 class="text-2xl font-bold mb-2">{label}</h2>
72 {/if}
73 <div class="flex flex-wrap justify-center items-center gap-6">
74 {#each timeUnits as unit}
75 <div class="flex flex-col items-center">
76 <span
77 class="{unit.size} {unit.weight} {countingUp ? 'text-up' : 'text-primary'}{unit.opacity
78 ? '/' + unit.opacity
79 : ''} leading-none"
80 >
81 {unit.value === days ? unit.value : padNumber(unit.value)}
82 </span>
83 <span class="text-gray-600{unit.opacity ? '/' + unit.opacity : ''}">
84 {unit.value === 1 ? unit.label : unit.label + "s"}
85 </span>
86 </div>
87 {/each}
88 </div>
89 </div>
90</div>
91
92<style>
93 :global(body) {
94 font-family: "Arial", sans-serif;
95 }
96
97 .text-primary {
98 color: #ff3e00;
99 }
100 .text-up {
101 color: #007aff;
102 }
103</style>