Compare commits

..

2 Commits

Author SHA1 Message Date
spinline
e23585dfea Fix syntax errors in torrent table component (missing function and closing tags)
All checks were successful
Build MIPS Binary / build (push) Successful in 4m23s
2026-02-07 20:19:49 +03:00
spinline
9d5092649f Update default sort to Date Added (Descending) and display Added column
Some checks failed
Build MIPS Binary / build (push) Failing after 1m18s
2026-02-07 20:16:30 +03:00

View File

@@ -45,6 +45,22 @@ fn format_duration(seconds: i64) -> String {
} }
} }
fn format_date(timestamp: i64) -> String {
if timestamp <= 0 {
return "-".to_string();
}
let date = js_sys::Date::new(&wasm_bindgen::JsValue::from_f64((timestamp * 1000) as f64));
// Simple formatting: YYYY-MM-DD HH:mm
let year = date.get_full_year();
let month = date.get_month() + 1; // 0-based
let day = date.get_date();
let hours = date.get_hours();
let minutes = date.get_minutes();
format!("{:04}-{:02}-{:02} {:02}:{:02}", year, month, day, hours, minutes)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum SortColumn { enum SortColumn {
Name, Name,
@@ -54,6 +70,7 @@ enum SortColumn {
DownSpeed, DownSpeed,
UpSpeed, UpSpeed,
ETA, ETA,
Added,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -66,8 +83,8 @@ enum SortDirection {
pub fn TorrentTable() -> impl IntoView { pub fn TorrentTable() -> impl IntoView {
let store = use_context::<crate::store::TorrentStore>().expect("store not provided"); let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
let sort_col = create_rw_signal(SortColumn::Name); let sort_col = create_rw_signal(SortColumn::Added);
let sort_dir = create_rw_signal(SortDirection::Ascending); let sort_dir = create_rw_signal(SortDirection::Descending);
let filtered_torrents = move || { let filtered_torrents = move || {
let mut torrents = store let mut torrents = store
@@ -127,6 +144,7 @@ pub fn TorrentTable() -> impl IntoView {
let b_eta = if b.eta <= 0 { i64::MAX } else { b.eta }; let b_eta = if b.eta <= 0 { i64::MAX } else { b.eta };
a_eta.cmp(&b_eta) a_eta.cmp(&b_eta)
} }
SortColumn::Added => a.added_date.cmp(&b.added_date),
}; };
if dir == SortDirection::Descending { if dir == SortDirection::Descending {
cmp.reverse() cmp.reverse()
@@ -264,6 +282,9 @@ pub fn TorrentTable() -> impl IntoView {
<th class="w-24 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::ETA)> <th class="w-24 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::ETA)>
<div class="flex items-center">"ETA" {move || sort_arrow(SortColumn::ETA)}</div> <div class="flex items-center">"ETA" {move || sort_arrow(SortColumn::ETA)}</div>
</th> </th>
<th class="w-32 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::Added)>
<div class="flex items-center">"Added" {move || sort_arrow(SortColumn::Added)}</div>
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -317,6 +338,7 @@ pub fn TorrentTable() -> impl IntoView {
<td class="text-right font-mono text-[11px] opacity-80 text-success">{format_speed(t.down_rate)}</td> <td class="text-right font-mono text-[11px] opacity-80 text-success">{format_speed(t.down_rate)}</td>
<td class="text-right font-mono text-[11px] opacity-80 text-primary">{format_speed(t.up_rate)}</td> <td class="text-right font-mono text-[11px] opacity-80 text-primary">{format_speed(t.up_rate)}</td>
<td class="text-right font-mono text-[11px] opacity-80">{format_duration(t.eta)}</td> <td class="text-right font-mono text-[11px] opacity-80">{format_duration(t.eta)}</td>
<td class="text-right font-mono text-[11px] opacity-60 whitespace-nowrap">{format_date(t.added_date)}</td>
</tr> </tr>
} }
}).collect::<Vec<_>>()} }).collect::<Vec<_>>()}
@@ -324,83 +346,85 @@ pub fn TorrentTable() -> impl IntoView {
</table> </table>
</div> </div>
<div class="md:hidden flex flex-col h-full bg-base-200 relative"> <div class="md:hidden flex flex-col h-full bg-base-200 relative">
// Transparent overlay to close sort dropdown // Transparent overlay to close sort dropdown
<Show when=move || sort_open.get()> <Show when=move || sort_open.get()>
<div <div
class="fixed inset-0 z-[98] cursor-default" class="fixed inset-0 z-[98] cursor-default"
on:pointerdown=move |_| set_sort_open.set(false) on:pointerdown=move |_| set_sort_open.set(false)
></div> ></div>
</Show> </Show>
<div class="px-3 py-2 border-b border-base-200 flex justify-between items-center bg-base-100/95 backdrop-blur z-10 shrink-0"> <div class="px-3 py-2 border-b border-base-200 flex justify-between items-center bg-base-100/95 backdrop-blur z-10 shrink-0">
<span class="text-xs font-bold opacity-50 uppercase tracking-wider">"Torrents"</span> <span class="text-xs font-bold opacity-50 uppercase tracking-wider">"Torrents"</span>
<div class="relative"> <div class="relative">
<div <div
role="button" role="button"
class="btn btn-ghost btn-xs gap-1 opacity-70 font-normal" class="btn btn-ghost btn-xs gap-1 opacity-70 font-normal"
on:pointerdown=move |e| { on:pointerdown=move |e| {
e.stop_propagation(); e.stop_propagation();
let cur = sort_open.get_untracked(); let cur = sort_open.get_untracked();
set_sort_open.set(!cur); set_sort_open.set(!cur);
} }
> >
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 7.5L7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5" /> <path stroke-linecap="round" stroke-linejoin="round" d="M3 7.5L7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5" />
</svg> </svg>
"Sort" "Sort"
</div> </div>
<ul <ul
class="absolute top-full right-0 z-[100] menu p-2 shadow bg-base-100 rounded-box w-48 mt-1 border border-base-200 text-xs" class="absolute top-full right-0 z-[100] menu p-2 shadow bg-base-100 rounded-box w-48 mt-1 border border-base-200 text-xs"
style=move || if sort_open.get() { "display: block" } else { "display: none" } style=move || if sort_open.get() { "display: block" } else { "display: none" }
on:pointerdown=move |e| e.stop_propagation() on:pointerdown=move |e| e.stop_propagation()
> >
<li class="menu-title px-2 py-1 opacity-50 text-[10px] uppercase font-bold">"Sort By"</li> <li class="menu-title px-2 py-1 opacity-50 text-[10px] uppercase font-bold">"Sort By"</li>
{ {
let columns = vec![ let columns = vec![
(SortColumn::Name, "Name"), (SortColumn::Added, "Date Added"),
(SortColumn::Size, "Size"), (SortColumn::Name, "Name"),
(SortColumn::Progress, "Progress"), (SortColumn::Size, "Size"),
(SortColumn::Status, "Status"), (SortColumn::Progress, "Progress"),
(SortColumn::DownSpeed, "Down Speed"), (SortColumn::Status, "Status"),
(SortColumn::UpSpeed, "Up Speed"), (SortColumn::DownSpeed, "Down Speed"),
(SortColumn::ETA, "ETA"), (SortColumn::UpSpeed, "Up Speed"),
]; (SortColumn::ETA, "ETA"),
];
columns.into_iter().map(|(col, label)| { columns.into_iter().map(|(col, label)| {
let is_active = move || sort_col.get() == col; let is_active = move || sort_col.get() == col;
let current_dir = move || sort_dir.get(); let current_dir = move || sort_dir.get();
view! { view! {
<li> <li>
<button <button
class=move || if is_active() { "bg-primary/10 text-primary font-bold flex justify-between" } else { "flex justify-between" } class=move || if is_active() { "bg-primary/10 text-primary font-bold flex justify-between" } else { "flex justify-between" }
on:pointerdown=move |e| { on:pointerdown=move |e| {
e.stop_propagation(); e.stop_propagation();
handle_sort(col); handle_sort(col);
set_sort_open.set(false); set_sort_open.set(false);
}
>
{label}
<Show when=is_active fallback=|| ()>
<span class="opacity-70 text-[10px]">
{move || match current_dir() {
SortDirection::Ascending => "",
SortDirection::Descending => "",
}}
</span>
</Show>
</button>
</li>
} }
}).collect::<Vec<_>>() >
} {label}
</ul> <Show when=is_active fallback=|| ()>
</div> <span class="opacity-70 text-[10px]">
</div> {move || match current_dir() {
SortDirection::Ascending => "",
SortDirection::Descending => "",
}}
</span>
</Show>
</button>
</li>
}
}).collect::<Vec<_>>()
}
</ul>
</div>
</div>
<div class="overflow-y-auto p-3 pb-20 flex-1 grid grid-cols-1 content-start gap-3"> {move || filtered_torrents().into_iter().map(|t| { <div class="overflow-y-auto p-3 pb-20 flex-1 grid grid-cols-1 content-start gap-3">
{move || filtered_torrents().into_iter().map(|t| {
let progress_class = if t.percent_complete >= 100.0 { "progress-success" } else { "progress-primary" }; let progress_class = if t.percent_complete >= 100.0 { "progress-success" } else { "progress-primary" };
let status_str = format!("{:?}", t.status); let status_str = format!("{:?}", t.status);
let status_badge_class = match t.status { let status_badge_class = match t.status {