It's a todo list.
7
fork

Configure Feed

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

at feat/improved-timer 119 lines 4.0 kB view raw
1<script module> 2 let selectedTab = $state("set"); 3</script> 4 5<script lang="ts"> 6 import { useInterval } from "runed"; 7 import type { Task } from "./stores.svelte"; 8 import { formatSecondsToDuration } from "./utils"; 9 10 let { task = $bindable(), onDelete }: { task: Task, onDelete: (taskId: string) => void } = $props(); 11 12 const interval = useInterval(1000, { 13 immediate: false, 14 callback: () => { 15 task.duration++; 16 } 17 }); 18 19 function toggleInterval() { 20 if (interval.isActive) { 21 interval.pause(); 22 } 23 else { 24 interval.resume(); 25 } 26 } 27 28 let timerDialog: HTMLDialogElement | undefined = $state(); 29 let hourInput = $state(0); 30 let minuteInput = $state(0); 31 let secondsInput = $state(0); 32 let inputDuration = $derived((hourInput * 3600) + (minuteInput * 60) + secondsInput); 33 34 function handleTimeSubmit() { 35 if (selectedTab === "set") { 36 task.duration = inputDuration; 37 } 38 else if (selectedTab === "add") { 39 task.duration += inputDuration; 40 } 41 } 42</script> 43 44<dialog bind:this={timerDialog} id={`timer_${task.id}`} class="fixed border inset-0 m-auto w-1/2 p-8 rounded-xl"> 45 <form method="dialog" onsubmit={handleTimeSubmit}> 46 <button type="button" onclick={() => timerDialog?.close()} class="absolute right-12">×</button> 47 <div class="flex flex-col items-center gap-4"> 48 <div class="flex items-center text-sm border rounded-full bg-gray-300"> 49 <button type="button" onclick={() => selectedTab = "set"} class={[selectedTab === "set" && "border-black bg-white", "border border-gray-300 px-3 py-1 rounded-l-full bg-gray-300"]}> 50 Set 51 </button> 52 <button type="button" onclick={() => selectedTab = "add"} class={[selectedTab === "add" && "border-black bg-white", "border border-gray-300 px-3 py-1 rounded-r-full bg-gray-300"]}> 53 Add 54 </button> 55 </div> 56 57 <div class="flex w-fit items-center justify-center"> 58 <input type="number" min="0" max="99" bind:value={hourInput} class="text-right" /> 59 <p class="mr-4">:</p> 60 <input type="number" min="0" max="59" bind:value={minuteInput} class="text-right" /> 61 <p class="mr-4">:</p> 62 <input type="number" min="0" max="59" bind:value={secondsInput} class="text-right" /> 63 </div> 64 65 <p> 66 <span class="text-gray-600">{formatSecondsToDuration(task.duration)}</span> 67 {#if selectedTab === "set"} 68 {formatSecondsToDuration(inputDuration)} 69 {:else if selectedTab === "add"} 70 {formatSecondsToDuration(task.duration + inputDuration)} 71 {/if} 72 </p> 73 <button type="submit" class="bg-green-400 px-4 py-1 text-lg rounded-lg"> 74 Confirm 75 </button> 76 </div> 77 </form> 78</dialog> 79 80<li class="group flex justify-between h-fit items-center gap-4"> 81 <div class="flex w-full gap-4 items-center pr-4 py-2"> 82 <input 83 type="checkbox" 84 bind:checked={task.completed} 85 class="w-6 h-6 bg-transparent" 86 /> 87 <input 88 type="text" 89 bind:value={task.description} 90 class={`w-full hover:underline text-ellipsis overflow-hidden bg-transparent ${task.completed && "text-white/50"}`} 91 /> 92 </div> 93 94 <div class="flex gap-4 w-fit h-fit items-center"> 95 <button 96 command="show-modal" 97 commandfor={`timer_${task.id}`} 98 class="w-fit h-fit tabular-nums text-lg hover:bg-gray-50/20 border rounded-lg p-2" 99 > 100 {formatSecondsToDuration(task.duration!)} 101 </button> 102 <button 103 onclick={toggleInterval} 104 class="w-full h-fit bg-white hover:bg-gray-200 border rounded-full p-2" 105 > 106 {#if interval.isActive} 107 <img src="/basil--pause-solid.svg" alt="Pause" class="w-8" /> 108 {:else} 109 <img src="/basil--play-solid.svg" alt="Play" class="w-8" /> 110 {/if} 111 </button> 112 <button 113 onclick={() => onDelete(task.id)} 114 class="p-2 bg-red-500 rounded-xl text-white w-full h-fit" 115 > 116 <img src="/basil--trash-solid.svg" alt="Trash" class="w-24" /> 117 </button> 118 </div> 119</li>