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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use dioxus::prelude::*;
use hooks::db_reactivity::Table;
use hooks::use_db_queries::use_playlists;
#[component]
pub fn FolderPickerModal(playlist_id: String, on_close: EventHandler<()>) -> Element {
let mut new_folder_name = use_signal(String::new);
let mut show_create = use_signal(|| false);
let gens = hooks::db_reactivity::use_generations();
let playlists_res = use_playlists();
let folders = playlists_res
.read()
.as_ref()
.map(|s| s.folders.clone())
.unwrap_or_default();
let pid = playlist_id.clone();
let pid_keydown = pid.clone();
let pid_btn = pid.clone();
rsx! {
div {
class: "fixed inset-0 z-50 flex items-center justify-center bg-black/60",
onclick: move |_| on_close.call(()),
div {
class: "bg-neutral-900 border border-white/10 rounded-lg p-6 w-80 shadow-2xl",
onclick: move |evt| evt.stop_propagation(),
h2 { class: "text-lg font-bold text-white mb-4", "{i18n::t(\"move_to_folder\")}" }
if folders.is_empty() && !*show_create.read() {
p { class: "text-sm text-slate-500 mb-4", "{i18n::t(\"no_folders_yet\")}" }
} else {
div { class: "space-y-1 mb-3 max-h-48 overflow-y-auto",
for folder in &folders {
{
let fid = folder.id.clone();
let fname = folder.name.clone();
let pid2 = pid.clone();
rsx! {
button {
key: "{fid}",
class: "w-full text-left px-3 py-2 rounded-lg text-sm text-white hover:bg-white/10 flex items-center gap-2 transition-colors",
onclick: move |_| {
let local = consume_context::<Signal<::server::source::ActiveSource>>().peek().clone();
let pid = pid2.clone();
let fid = fid.clone();
spawn(async move {
if local
.set_playlist_folder(&pid, Some(&fid))
.await
.is_ok()
{
gens.bump(Table::Folders);
}
});
on_close.call(());
},
i { class: "fa-solid fa-folder text-amber-400 text-xs" }
"{fname}"
}
}
}
}
}
}
if *show_create.read() {
div { class: "flex gap-2 mb-3",
input {
class: "flex-1 bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-sm text-white placeholder-slate-500 focus:outline-none focus:border-indigo-500",
placeholder: i18n::t("folder_name"),
value: "{new_folder_name}",
oninput: move |evt| new_folder_name.set(evt.value()),
onkeydown: move |evt| {
if evt.key() == Key::Enter {
let name = new_folder_name.read().trim().to_string();
if !name.is_empty() {
let new_id = uuid::Uuid::new_v4().to_string();
let pid = pid_keydown.clone();
let source = consume_context::<Signal<::server::source::ActiveSource>>().peek().clone();
spawn(async move {
if source.create_folder(&new_id, &name).await.is_ok()
&& source
.set_playlist_folder(&pid, Some(&new_id))
.await
.is_ok()
{
gens.bump(Table::Folders);
}
});
on_close.call(());
}
}
},
}
button {
class: "px-3 py-2 bg-indigo-500 hover:bg-indigo-400 text-white rounded-lg text-sm transition-colors",
onclick: {
let pid4 = pid_btn.clone();
move |_| {
let name = new_folder_name.read().trim().to_string();
if !name.is_empty() {
let new_id = uuid::Uuid::new_v4().to_string();
let pid = pid4.clone();
let source = consume_context::<Signal<::server::source::ActiveSource>>().peek().clone();
spawn(async move {
if source.create_folder(&new_id, &name).await.is_ok()
&& source
.set_playlist_folder(&pid, Some(&new_id))
.await
.is_ok()
{
gens.bump(Table::Folders);
}
});
on_close.call(());
}
}
},
"{i18n::t(\"create\")}"
}
}
}
div { class: "flex gap-2",
button {
class: "flex-1 py-2 text-sm text-slate-400 hover:text-white border border-white/10 rounded-lg transition-colors",
onclick: move |_| {
let next = !*show_create.read();
show_create.set(next);
new_folder_name.set(String::new());
},
i { class: "fa-solid fa-folder-plus mr-2 text-xs" }
"{i18n::t(\"new_folder\")}"
}
button {
class: "px-4 py-2 text-sm text-slate-400 hover:text-white transition-colors",
onclick: move |_| on_close.call(()),
"{i18n::t(\"cancel\")}"
}
}
}
}
}
}