feat: add empty state to torrent table for better user feedback
Some checks failed
Build MIPS Binary / build (push) Failing after 1m33s

This commit is contained in:
spinline
2026-02-12 01:01:36 +03:00
parent 38bce3fecf
commit 5cc2fdd8b4
2 changed files with 89 additions and 33 deletions

View File

@@ -1,7 +1,7 @@
use leptos::prelude::*; use leptos::prelude::*;
use leptos::task::spawn_local; use leptos::task::spawn_local;
use std::collections::HashSet; use std::collections::HashSet;
use icons::{ArrowUpDown}; use icons::{ArrowUpDown, Inbox};
use crate::store::{get_action_messages, show_toast}; use crate::store::{get_action_messages, show_toast};
use crate::api; use crate::api;
use shared::NotificationLevel; use shared::NotificationLevel;
@@ -10,6 +10,7 @@ use crate::components::ui::card::{Card, CardHeader, CardTitle, CardContent as Ca
use crate::components::ui::data_table::*; use crate::components::ui::data_table::*;
use crate::components::ui::checkbox::Checkbox; use crate::components::ui::checkbox::Checkbox;
use crate::components::ui::button::{Button, ButtonVariant}; use crate::components::ui::button::{Button, ButtonVariant};
use crate::components::ui::empty::*;
fn format_bytes(bytes: i64) -> String { fn format_bytes(bytes: i64) -> String {
const UNITS: [&str; 6] = ["B", "KB", "MB", "GB", "TB", "PB"]; const UNITS: [&str; 6] = ["B", "KB", "MB", "GB", "TB", "PB"];
@@ -220,29 +221,68 @@ pub fn TorrentTable() -> impl IntoView {
</DataTableRow> </DataTableRow>
</DataTableHeader> </DataTableHeader>
<DataTableBody> <DataTableBody>
<For each=move || filtered_hashes.get() key=|hash| hash.clone() children={ <Show
let on_action = on_action.clone(); when=move || !filtered_hashes.get().is_empty()
move |hash| { fallback=move || view! {
let h = hash.clone(); <DataTableRow class="hover:bg-transparent">
let is_selected = Signal::derive(move || { <DataTableCell attr:colspan="9" class="h-[400px]">
selected_hashes.with(|selected| selected.contains(&h)) <Empty class="h-full">
}); <EmptyHeader>
let h_for_change = hash.clone(); <EmptyMedia variant=EmptyMediaVariant::Icon>
view! { <Inbox class="size-10" />
<TorrentRow </EmptyMedia>
hash=hash.clone() <EmptyTitle>"Torrent Bulunamadı"</EmptyTitle>
on_action=on_action.clone() <EmptyDescription>
is_selected=is_selected {move || {
on_select=Callback::new(move |checked| { let query = store.search_query.get();
selected_hashes.update(|selected| { if query.is_empty() {
if checked { selected.insert(h_for_change.clone()); } "Henüz eklenmiş bir torrent bulunmuyor.".to_string()
else { selected.remove(&h_for_change); } } else {
}); format!("'{}' araması için sonuç bulunamadı.", query)
}) }
/> }}
} </EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button
variant=ButtonVariant::Outline
on:click=move |_| {
store.search_query.set(String::new());
store.filter.set(crate::store::FilterStatus::All);
}
>
"Tümünü Göster"
</Button>
</EmptyContent>
</Empty>
</DataTableCell>
</DataTableRow>
} }
} /> >
<For each=move || filtered_hashes.get() key=|hash| hash.clone() children={
let on_action = on_action.clone();
move |hash| {
let h = hash.clone();
let is_selected = Signal::derive(move || {
selected_hashes.with(|selected| selected.contains(&h))
});
let h_for_change = hash.clone();
view! {
<TorrentRow
hash=hash.clone()
on_action=on_action.clone()
is_selected=is_selected
on_select=Callback::new(move |checked| {
selected_hashes.update(|selected| {
if checked { selected.insert(h_for_change.clone()); }
else { selected.remove(&h_for_change); }
});
})
/>
}
}
} />
</Show>
</DataTableBody> </DataTableBody>
</DataTable> </DataTable>
</div> </div>
@@ -259,16 +299,31 @@ pub fn TorrentTable() -> impl IntoView {
// --- MOBILE VIEW --- // --- MOBILE VIEW ---
<div class="md:hidden flex flex-col h-full bg-muted/10 relative overflow-hidden"> <div class="md:hidden flex flex-col h-full bg-muted/10 relative overflow-hidden">
<div class="flex-1 overflow-y-auto p-3 min-h-0"> <div class="flex-1 overflow-y-auto p-3 min-h-0">
<For each=move || filtered_hashes.get() key=|hash| hash.clone() children={ <Show
let on_action = on_action.clone(); when=move || !filtered_hashes.get().is_empty()
move |hash| { fallback=move || view! {
view! { <Empty class="h-64 mt-10">
<div class="pb-3"> <EmptyHeader>
<TorrentCard hash=hash.clone() on_action=on_action.clone() /> <EmptyMedia variant=EmptyMediaVariant::Icon>
</div> <Inbox class="size-10" />
} </EmptyMedia>
<EmptyTitle>"Boş Görünüyor"</EmptyTitle>
<EmptyDescription>"Burada gösterilecek bir şey yok."</EmptyDescription>
</EmptyHeader>
</Empty>
} }
} /> >
<For each=move || filtered_hashes.get() key=|hash| hash.clone() children={
let on_action = on_action.clone();
move |hash| {
view! {
<div class="pb-3">
<TorrentCard hash=hash.clone() on_action=on_action.clone() />
</div>
}
}
} />
</Show>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -7,3 +7,4 @@ pub mod theme_toggle;
pub mod svg_icon; pub mod svg_icon;
pub mod table; pub mod table;
pub mod data_table;pub mod checkbox; pub mod data_table;pub mod checkbox;
pub mod empty;