Skip to content

Commit 81f9647

Browse files
authored
feat: channel group (#24)
1 parent e9c335c commit 81f9647

34 files changed

Lines changed: 3705 additions & 304 deletions

ERRORS.md

Lines changed: 0 additions & 80 deletions
This file was deleted.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ cp .env.sample .env
1919
### 開発用サーバー
2020

2121
```sh
22-
devenv up -d # run in background, logs at .devenv/processes.log
23-
devenv processes down # kill the background service
22+
bun up # バックグラウンドで起動
23+
bun down # 停止
24+
bun tail # ログを表示
2425
```
2526

2627
## 注意点

TODOS.md

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<script lang="ts">
2+
import ChevronRight from "@lucide/svelte/icons/chevron-right";
3+
import FolderInput from "@lucide/svelte/icons/folder-input";
4+
import FolderOutput from "@lucide/svelte/icons/folder-output";
5+
import Pencil from "@lucide/svelte/icons/pencil";
6+
import Trash2 from "@lucide/svelte/icons/trash-2";
7+
import type { ChannelGroup } from "@packages/api-client";
8+
9+
interface Props {
10+
x: number;
11+
y: number;
12+
currentGroupId: string | null;
13+
groups: ChannelGroup[];
14+
onEdit: () => void;
15+
onDelete: () => void;
16+
onMoveToGroup: (groupId: string | null) => void;
17+
onClose: () => void;
18+
}
19+
20+
const {
21+
x,
22+
y,
23+
currentGroupId,
24+
groups,
25+
onEdit,
26+
onDelete,
27+
onMoveToGroup,
28+
onClose,
29+
}: Props = $props();
30+
31+
let showMoveSubmenu = $state(false);
32+
33+
function handleEdit() {
34+
onEdit();
35+
onClose();
36+
}
37+
38+
function handleDelete() {
39+
onDelete();
40+
onClose();
41+
}
42+
43+
function handleSelect(groupId: string | null) {
44+
onMoveToGroup(groupId);
45+
onClose();
46+
}
47+
48+
const availableGroups = $derived(
49+
groups.filter((g) => g.id !== currentGroupId),
50+
);
51+
</script>
52+
53+
<svelte:window
54+
onclick={onClose}
55+
onkeydown={(e) => e.key === "Escape" && onClose()}
56+
/>
57+
58+
<div
59+
class="menu bg-base-200 rounded-box fixed z-50 w-48 p-2 shadow-lg"
60+
style:left="{x}px"
61+
style:top="{y}px"
62+
role="menu"
63+
tabindex="-1"
64+
onclick={(e) => e.stopPropagation()}
65+
onkeydown={(e) => e.key === "Escape" && onClose()}
66+
>
67+
<button
68+
type="button"
69+
class="btn btn-ghost btn-sm justify-start gap-2"
70+
onclick={handleEdit}
71+
>
72+
<Pencil class="size-4" />
73+
Edit Channel
74+
</button>
75+
76+
<div class="divider my-1"></div>
77+
78+
<!-- Move to submenu trigger -->
79+
<div class="relative">
80+
<button
81+
type="button"
82+
class="btn btn-ghost btn-sm w-full justify-between gap-2"
83+
onmouseenter={() => (showMoveSubmenu = true)}
84+
onmouseleave={() => (showMoveSubmenu = false)}
85+
onfocus={() => (showMoveSubmenu = true)}
86+
>
87+
<span class="flex items-center gap-2">
88+
<FolderInput class="size-4" />
89+
Move to
90+
</span>
91+
<ChevronRight class="size-4" />
92+
</button>
93+
94+
{#if showMoveSubmenu}
95+
<div
96+
class="menu bg-base-200 rounded-box absolute top-0 left-full z-50 ml-1 w-44 p-2 shadow-lg"
97+
role="menu"
98+
tabindex="-1"
99+
onmouseenter={() => (showMoveSubmenu = true)}
100+
onmouseleave={() => (showMoveSubmenu = false)}
101+
>
102+
{#each availableGroups as group (group.id)}
103+
<button
104+
type="button"
105+
class="btn btn-ghost btn-sm justify-start gap-2"
106+
onclick={() => handleSelect(group.id)}
107+
>
108+
{group.name}
109+
</button>
110+
{/each}
111+
112+
{#if availableGroups.length === 0}
113+
<span class="text-muted px-2 py-1 text-xs italic">
114+
No groups available
115+
</span>
116+
{/if}
117+
</div>
118+
{/if}
119+
</div>
120+
121+
{#if currentGroupId}
122+
<button
123+
type="button"
124+
class="btn btn-ghost btn-sm justify-start gap-2"
125+
onclick={() => handleSelect(null)}
126+
>
127+
<FolderOutput class="size-4" />
128+
Remove from Group
129+
</button>
130+
{/if}
131+
132+
<div class="divider my-1"></div>
133+
134+
<button
135+
type="button"
136+
class="btn btn-ghost btn-sm text-error justify-start gap-2"
137+
onclick={handleDelete}
138+
>
139+
<Trash2 class="size-4" />
140+
Delete Channel
141+
</button>
142+
</div>

0 commit comments

Comments
 (0)