[READ-ONLY] Mirror of https://github.com/mrgnw/morganwill.com. morganwill.com
0

Configure Feed

Select the types of activity you want to include in your feed.

morganwill.com / src / components / Countdown.svelte
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>