+5
-5
src/routes/+layout.svelte
+5
-5
src/routes/+layout.svelte
···
7
7
import toast, { Toaster } from "svelte-french-toast";
8
8
import { persisted, pinned_list } from "$lib/stores.svelte";
9
9
10
-
const theme = persisted<string>("theme", "light");
10
+
let theme = persisted<string>("theme", "dark");
11
11
let is_menu_open = $state(false);
12
-
let theme_style = $derived(theme.value === "light"
13
-
? "text-black absolute inset-0 -z-10 h-full w-full bg-white bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px]"
14
-
: "text-white absolute top-0 z-[-2] h-screen w-screen bg-[#000000] bg-[radial-gradient(#ffffff33_1px,#00091d_1px)] bg-[size:20px_20px]"
12
+
let theme_style = $derived(theme.value === "dark"
13
+
? "text-white absolute top-0 z-[-2] h-screen w-screen bg-[#000000] bg-[radial-gradient(#ffffff33_1px,#00091d_1px)] bg-[size:20px_20px]"
14
+
: "text-black absolute inset-0 -z-10 h-full w-full bg-white bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px]"
15
15
);
16
16
17
17
function comingSoon() {
···
41
41
onclick={comingSoon}
42
42
class="flex gap-2 text-start w-full h-full rounded-xl pl-2 pr-5 py-2 hover:bg-slate-500/10 transition-all duration-150 items-center"
43
43
>
44
-
<img src="/shooting-star.svg" alt="Item 1" class="w-8 h-8" />
44
+
<img src="/shooting-star-line.svg" alt="Item 1" class="w-8 h-8" />
45
45
Try a new list
46
46
</button>
47
47
<button
+1
src/routes/+page.svelte
+1
src/routes/+page.svelte
···
1
+
<p>Test</p>
+97
-6
src/routes/[id]/+page.svelte
+97
-6
src/routes/[id]/+page.svelte
···
1
1
<script lang="ts">
2
-
import { onMount } from "svelte";
2
+
import { onMount, tick } from "svelte";
3
3
import { page } from "$app/stores";
4
4
import { local_lists, pinned_list, generateId, type List } from "$lib/stores.svelte";
5
+
import { goto, pushState } from "$app/navigation";
6
+
import toast, { Toaster } from "svelte-french-toast";
5
7
8
+
let is_menu_open = $state(false);
6
9
let list : List | undefined = $state();
7
10
let task_input = $state("");
11
+
let user_lists = $derived(local_lists.value) as List[];
8
12
9
13
onMount(() => {
10
14
list = local_lists.value!.find((l) => l.id === $page.params.id);
11
15
});
12
16
17
+
// since list points to something inside local_lists,
18
+
// it will run when list state changes
13
19
$effect(() => local_lists.update());
14
20
15
21
function addTask() {
22
+
if (task_input.length === 0) {
23
+
toast.error("Enter a task to add");
24
+
return;
25
+
}
26
+
16
27
list?.tasks.push({
17
28
id: generateId(),
18
29
description: task_input,
···
27
38
list.tasks = list.tasks.filter((t) => t.id !== id);
28
39
}
29
40
}
41
+
42
+
function createList() {
43
+
const new_list = {
44
+
id: generateId(),
45
+
title: "",
46
+
tasks: []
47
+
};
48
+
49
+
local_lists.value!.push(new_list);
50
+
list = local_lists.value!.find((l) => l.id === new_list.id);
51
+
goto(`/${list!.id}`);
52
+
}
53
+
54
+
function switchToList(id: string) {
55
+
list = local_lists.value!.find((l) => l.id === id);
56
+
goto(`/${list!.id}`);
57
+
}
58
+
59
+
function pinList(id: string) {
60
+
pinned_list.value = id;
61
+
}
62
+
63
+
function deleteList() {
64
+
if (pinned_list.value === $page.params.id) {
65
+
toast.error("Cannot delete pinned list");
66
+
return;
67
+
}
68
+
69
+
local_lists.value = local_lists.value!.filter((l) => l.id !== $page.params.id);
70
+
list = local_lists.value.find((l) => l.id === pinned_list.value);
71
+
goto(`/${list!.id}`);
72
+
}
30
73
</script>
31
74
32
75
<main class="flex flex-col w-full px-2 pt-8 pb-12 lg:p-4 lg:pb-24 gap-8 text-xl lg:text-3xl">
33
76
{#if list}
34
-
<input
35
-
type="text"
36
-
bind:value={list.title}
37
-
class="text-5xl font-bold bg-transparent"
38
-
/>
77
+
<section class="relative flex gap-4 w-full">
78
+
<div class="flex gap-4 border-black border w-fit h-fit p-2 bg-white rounded-xl">
79
+
<button onclick={() => is_menu_open = !is_menu_open}>
80
+
<img
81
+
src="/list-box-line.svg"
82
+
alt="Lists button"
83
+
class="w-12 h-12 hover:bg-slate-500/10 rounded-full"
84
+
/>
85
+
</button>
86
+
<button onclick={() => pinList(list!.id)}>
87
+
<img
88
+
src={pinned_list.value === list.id ? "/pin.svg" : "/pin-line.svg"}
89
+
alt="Pin list button"
90
+
class="w-12 h-12 hover:bg-slate-500/10 rounded-full"
91
+
/>
92
+
</button>
93
+
<button onclick={deleteList}>
94
+
<img
95
+
src="/trash-line.svg"
96
+
alt="Delete list button"
97
+
class="w-12 h-12 hover:bg-slate-500/10 rounded-full"
98
+
/>
99
+
</button>
100
+
</div>
101
+
102
+
{#if is_menu_open}
103
+
<menu class="absolute flex flex-col gap-2 w-fit h-fit top-20 p-2 bg-white border border-black rounded-lg !text-black !text-lg">
104
+
{#each user_lists as user_list : List (user_list.id)}
105
+
<button
106
+
onclick={() => switchToList(user_list.id)}
107
+
class="flex gap-2 justify-between text-start w-full h-full rounded-xl pl-2 pr-5 py-2 hover:bg-slate-500/10 transition-all duration-150 items-center"
108
+
>
109
+
{user_list.title.length > 0 ? user_list.title : "Untitled"}
110
+
{#if user_list.id === list.id}
111
+
<img src="/check-line.svg" alt="Item 1" class="w-8 h-8" />
112
+
{/if}
113
+
</button>
114
+
{/each}
115
+
<button
116
+
onclick={createList}
117
+
class="flex gap-2 justify-between text-start w-full h-full rounded-xl pl-2 pr-5 py-2 hover:bg-slate-500/10 transition-all duration-150 items-center"
118
+
>
119
+
Create new list
120
+
</button>
121
+
</menu>
122
+
{/if}
123
+
</section>
124
+
<input
125
+
type="text"
126
+
bind:value={list.title}
127
+
placeholder="Untitled"
128
+
class="text-5xl font-bold bg-transparent"
129
+
/>
39
130
<ul class="flex flex-col gap-4">
40
131
{#each list.tasks as task (task.id)}
41
132
<li class="group flex justify-between items-center gap-4">
+1
static/check-line.svg
+1
static/check-line.svg
···
1
+
<svg width="512" height="512" viewBox="0 0 512 512" style="color:currentColor" xmlns="http://www.w3.org/2000/svg" class="h-full w-full"><rect width="512" height="512" x="0" y="0" rx="30" fill="transparent" stroke="transparent" stroke-width="0" stroke-opacity="100%" paint-order="stroke"></rect><svg width="256px" height="256px" viewBox="0 0 24 24" fill="currentColor" x="128" y="128" role="img" style="display:inline-block;vertical-align:middle" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor"><g fill="currentColor"><path d="M19.707 6.293a1 1 0 0 1 0 1.414l-10 10a1 1 0 0 1-1.414 0l-4-4a1 1 0 1 1 1.414-1.414L9 15.586l9.293-9.293a1 1 0 0 1 1.414 0z"/></g></g></svg></svg>
+1
static/list-box-line.svg
+1
static/list-box-line.svg
···
1
+
<svg width="512" height="512" viewBox="0 0 512 512" style="color:currentColor" xmlns="http://www.w3.org/2000/svg" class="h-full w-full"><rect width="512" height="512" x="0" y="0" rx="30" fill="transparent" stroke="transparent" stroke-width="0" stroke-opacity="100%" paint-order="stroke"></rect><svg width="256px" height="256px" viewBox="0 0 24 24" fill="currentColor" x="128" y="128" role="img" style="display:inline-block;vertical-align:middle" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 8h5m0 4h-5m5 4h-5m-5 4h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2zM8 8h.001M8 12h.001M8 16h.001"/></g></svg></svg>
+1
static/pin-line.svg
+1
static/pin-line.svg
···
1
+
<svg width="512" height="512" viewBox="0 0 512 512" style="color:currentColor" xmlns="http://www.w3.org/2000/svg" class="h-full w-full"><rect width="512" height="512" x="0" y="0" rx="30" fill="transparent" stroke="transparent" stroke-width="0" stroke-opacity="100%" paint-order="stroke"></rect><svg width="256px" height="256px" viewBox="0 0 24 24" fill="currentColor" x="128" y="128" role="img" style="display:inline-block;vertical-align:middle" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m4 20l5-5m0 0l3.956 3.956a1 1 0 0 0 1.626-.314l2.255-5.261a1 1 0 0 1 .548-.535l3.207-1.283a1 1 0 0 0 .336-1.635l-6.856-6.856a1 1 0 0 0-1.635.336l-1.283 3.207a1 1 0 0 1-.535.548L5.358 9.418a1 1 0 0 0-.314 1.626L9 15z"/></g></svg></svg>
+1
static/shooting-star-line.svg
+1
static/shooting-star-line.svg
···
1
+
<svg width="512" height="512" viewBox="0 0 512 512" style="color:currentColor" xmlns="http://www.w3.org/2000/svg" class="h-full w-full"><rect width="512" height="512" x="0" y="0" rx="30" fill="transparent" stroke="transparent" stroke-width="0" stroke-opacity="100%" paint-order="stroke"></rect><svg width="256px" height="256px" viewBox="0 0 24 24" fill="currentColor" x="128" y="128" role="img" style="display:inline-block;vertical-align:middle" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 8c-1.667.667-5.4 2.7-7 5.5m9.5-2.5C9.167 12.333 4 16.4 2 22m10.5-7.5c-1.167 1.167-3.8 4.1-5 6.5m7.174-14.55l.673-3.285l2.225 2.51l3.027-.294l-1.768 3.062l1.743 2.639l-3.286-.673l-2.51 2.225l.19-3.156l-3.062-1.768l2.768-1.26z"/></g></svg></svg>
-1
static/shooting-star.svg
-1
static/shooting-star.svg
···
1
-
<svg width="512" height="512" viewBox="0 0 512 512" style="color:currentColor" xmlns="http://www.w3.org/2000/svg" class="h-full w-full"><rect width="512" height="512" x="0" y="0" rx="30" fill="transparent" stroke="transparent" stroke-width="0" stroke-opacity="100%" paint-order="stroke"></rect><svg width="256px" height="256px" viewBox="0 0 24 24" fill="currentColor" x="128" y="128" role="img" style="display:inline-block;vertical-align:middle" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M9 8c-1.667.667-5.4 2.7-7 5.5m9.5-2.5C9.167 12.333 4 16.4 2 22m10.5-7.5c-1.167 1.167-3.8 4.1-5 6.5"/><path fill="currentColor" d="m14.674 6.45l.673-3.285l2.225 2.51l3.027-.294l-1.768 3.062l1.743 2.639l-3.286-.673l-2.51 2.225l.19-3.156l-3.062-1.768l2.768-1.26z"/></g></g></svg></svg>
+1
static/trash-line.svg
+1
static/trash-line.svg
···
1
+
<svg width="512" height="512" viewBox="0 0 512 512" style="color:currentColor" xmlns="http://www.w3.org/2000/svg" class="h-full w-full"><rect width="512" height="512" x="0" y="0" rx="30" fill="transparent" stroke="transparent" stroke-width="0" stroke-opacity="100%" paint-order="stroke"></rect><svg width="256px" height="256px" viewBox="0 0 24 24" fill="currentColor" x="128" y="128" role="img" style="display:inline-block;vertical-align:middle" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor"><g fill="currentColor"><path d="M4 7a1 1 0 0 1 1-1h14a1 1 0 1 1 0 2v10a3 3 0 0 1-3 3H8a3 3 0 0 1-3-3V8a1 1 0 0 1-1-1zm3 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8H7z"/><path d="M11 5a1 1 0 0 0-1 1v1a1 1 0 0 1-2 0V6a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v1a1 1 0 1 1-2 0V6a1 1 0 0 0-1-1h-2zm-1 5a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0v-5a1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0v-5a1 1 0 0 1 1-1z"/></g></g></svg></svg>