-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy path+page.svelte
124 lines (117 loc) · 3.07 KB
/
+page.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<script lang="ts">
import { PREPEND, APPEND, groupJSON } from "$lib";
import Sortable from "./components/Sortable.svelte";
import Overlay from "./components/Overlay.svelte";
import { database } from "$lib/svelte";
import { onDestroy } from "svelte";
import { schema } from "./schema";
import { trpc } from "../client";
const { replicated, close } = database(schema, {
name: "sortable.db",
push: trpc.sortable.push.mutate,
pull: trpc.sortable.pull.subscribe,
});
onDestroy(close);
const hash = (s: string) =>
s.split("").reduce((a, b) => {
a = (a << 5) - a + b.charCodeAt(0);
return a & a;
}, 0);
const lists = replicated(
(db) =>
db
.selectFrom((qb) =>
qb
.selectFrom("items")
.innerJoin("lists", "lists.id", "items.list")
.selectAll()
.orderBy("order")
.orderBy("id")
.as("data"),
)
.select([
"title",
(qb) =>
groupJSON(qb, {
id: "id",
data: "data",
order: "order",
}).as("items"),
])
.groupBy("list"),
{
async add(db, list: string, item: string, append = true) {
await db
.insertInto("lists")
.onConflict((qb) => qb.doNothing())
.values({ id: hash(list), title: list })
.execute();
await db
.insertInto("items")
.onConflict((qb) => qb.doNothing())
.values({
id: hash(item),
data: item,
list: hash(list),
order: append ? APPEND : PREPEND,
})
.execute();
},
async move(db, list: number, from: number, to: number) {
const source = $lists[list].items[from];
const target = $lists[list].items[to - (to < from ? 1 : 0)];
await db
.updateTable("items_fractindex" as any)
.set({ after_id: target?.id || null })
.where("id", "=", source.id)
.execute();
},
},
);
let list = "";
let item = "";
</script>
<Overlay />
{#if $lists}
<div>
<input placeholder="List" type="text" bind:value={list} />
<input placeholder="Item" type="text" bind:value={item} />
<button on:click={() => lists.add(list, item)}>Append</button>
<button on:click={() => lists.add(list, item, false)}>Prepend</button>
</div>
{#each $lists as list, i}
<h2>{list.title}</h2>
<ul>
<Sortable
items={list.items.slice()}
identify={(item) => item.id}
let:item
on:sort={({ detail }) => lists.move(i, detail.from, detail.to)}
animation={150}
>
<article>
{item.data}
<span>{item.order}</span>
</article>
</Sortable>
</ul>
{/each}
{:else}
Loading...
{/if}
<style>
article {
background-color: crimson;
align-items: center;
border-radius: 0.5rem;
display: flex;
color: white;
padding: 1rem;
margin: 0.5rem;
}
span {
margin-left: auto;
font-size: 0.8rem;
opacity: 0.7;
}
</style>