Apply VibeTorrent Glassmorphism Edition theme
Some checks failed
Build MIPS Binary / build (push) Failing after 3s
Some checks failed
Build MIPS Binary / build (push) Failing after 3s
This commit is contained in:
@@ -20,6 +20,11 @@
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="icon-192.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Trunk Assets -->
|
||||
<link data-trunk rel="rust" href="Cargo.toml" data-wasm-opt="0" />
|
||||
<link data-trunk rel="css" href="public/tailwind.css" />
|
||||
|
||||
@@ -3,14 +3,42 @@
|
||||
|
||||
@plugin "daisyui" {
|
||||
themes:
|
||||
light, dark, dim, nord, cupcake, dracula, cyberpunk, emerald, sunset,
|
||||
abyss;
|
||||
vibeglass, dark;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply min-h-dvh w-full overflow-hidden bg-base-100 text-base-content overscroll-y-none;
|
||||
@apply min-h-dvh w-full overflow-hidden bg-[#0f172a] text-base-content overscroll-y-none;
|
||||
background-image:
|
||||
radial-gradient(circle at 15% 50%, rgba(244, 157, 37, 0.08), transparent 25%),
|
||||
radial-gradient(circle at 85% 30%, rgba(59, 130, 246, 0.08), transparent 25%);
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
/* Glassmorphism Utilities */
|
||||
.glass-panel {
|
||||
@apply bg-gray-800/40 backdrop-blur-xl border border-white/10 shadow-xl;
|
||||
}
|
||||
|
||||
.glass-sidebar {
|
||||
@apply bg-gray-900/60 backdrop-blur-xl border-r border-white/5;
|
||||
}
|
||||
|
||||
.glass-header {
|
||||
@apply bg-gray-900/40 backdrop-blur-md border-b border-white/5;
|
||||
}
|
||||
|
||||
.glass-input {
|
||||
@apply bg-gray-700/30 border border-white/10 text-white placeholder-gray-400 focus:border-primary focus:ring-1 focus:ring-primary transition-all backdrop-blur-sm;
|
||||
}
|
||||
|
||||
.glass-card {
|
||||
@apply bg-gray-800/30 backdrop-blur-md border border-white/5 shadow-lg hover:bg-gray-800/40 transition-colors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,3 +58,22 @@
|
||||
:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
/* Scrollbar styling for glass theme */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
@@ -6,13 +6,13 @@ use crate::components::layout::toolbar::Toolbar;
|
||||
#[component]
|
||||
pub fn Protected(children: Children) -> impl IntoView {
|
||||
view! {
|
||||
<div class="drawer lg:drawer-open h-full w-full">
|
||||
<div class="drawer lg:drawer-open h-full w-full bg-transparent">
|
||||
<input id="my-drawer" type="checkbox" class="drawer-toggle" />
|
||||
|
||||
<div class="drawer-content flex flex-col h-full overflow-hidden bg-base-100 text-base-content text-sm select-none">
|
||||
<div class="drawer-content flex flex-col h-full overflow-hidden text-base-content text-sm select-none">
|
||||
<Toolbar />
|
||||
|
||||
<main class="flex-1 flex flex-col min-w-0 bg-base-100 overflow-hidden pb-8">
|
||||
<main class="flex-1 flex flex-col min-w-0 overflow-hidden pb-8">
|
||||
{children()}
|
||||
</main>
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn Protected(children: Children) -> impl IntoView {
|
||||
|
||||
<div class="drawer-side z-40 transition-none duration-0">
|
||||
<label for="my-drawer" aria-label="close sidebar" class="drawer-overlay transition-none duration-0"></label>
|
||||
<div class="menu p-0 min-h-full bg-base-200 text-base-content border-r border-base-300 transition-none duration-0">
|
||||
<div class="menu p-0 min-h-full bg-transparent border-r border-white/5 transition-none duration-0">
|
||||
<Sidebar />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -104,17 +104,17 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
view! {
|
||||
|
||||
<div class="w-64 min-h-[100dvh] flex flex-col bg-base-200 border-r border-base-300 pb-8" style="padding-top: env(safe-area-inset-top);">
|
||||
<div class="w-64 min-h-[100dvh] flex flex-col glass-sidebar pb-8" style="padding-top: env(safe-area-inset-top);">
|
||||
|
||||
<div class="p-2 flex-1 overflow-y-auto">
|
||||
|
||||
<ul class="menu w-full rounded-box gap-1">
|
||||
<ul class="menu w-full gap-1">
|
||||
|
||||
<li class="menu-title text-primary uppercase font-bold px-4">"Filters"</li>
|
||||
<li class="menu-title text-primary uppercase font-bold px-4 tracking-wider text-xs opacity-80">"Filters"</li>
|
||||
|
||||
<li>
|
||||
|
||||
<button class={move || format!("cursor-pointer {}", filter_class(crate::store::FilterStatus::All))} on:click=move |_| set_filter(crate::store::FilterStatus::All)>
|
||||
<button class={move || format!("cursor-pointer hover:bg-white/10 {}", filter_class(crate::store::FilterStatus::All))} on:click=move |_| set_filter(crate::store::FilterStatus::All)>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
|
||||
@@ -124,7 +124,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
"All"
|
||||
|
||||
<span class="badge badge-sm badge-ghost ml-auto">{total_count}</span>
|
||||
<span class="badge badge-sm badge-ghost ml-auto bg-white/10 border-0">{total_count}</span>
|
||||
|
||||
</button>
|
||||
|
||||
@@ -132,7 +132,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
<li>
|
||||
|
||||
<button class={move || format!("cursor-pointer {}", filter_class(crate::store::FilterStatus::Downloading))} on:click=move |_| set_filter(crate::store::FilterStatus::Downloading)>
|
||||
<button class={move || format!("cursor-pointer hover:bg-white/10 {}", filter_class(crate::store::FilterStatus::Downloading))} on:click=move |_| set_filter(crate::store::FilterStatus::Downloading)>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
|
||||
@@ -142,7 +142,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
"Downloading"
|
||||
|
||||
<span class="badge badge-sm badge-ghost ml-auto">{downloading_count}</span>
|
||||
<span class="badge badge-sm badge-ghost ml-auto bg-white/10 border-0">{downloading_count}</span>
|
||||
|
||||
</button>
|
||||
|
||||
@@ -150,7 +150,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
<li>
|
||||
|
||||
<button class={move || format!("cursor-pointer {}", filter_class(crate::store::FilterStatus::Seeding))} on:click=move |_| set_filter(crate::store::FilterStatus::Seeding)>
|
||||
<button class={move || format!("cursor-pointer hover:bg-white/10 {}", filter_class(crate::store::FilterStatus::Seeding))} on:click=move |_| set_filter(crate::store::FilterStatus::Seeding)>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
|
||||
@@ -160,7 +160,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
"Seeding"
|
||||
|
||||
<span class="badge badge-sm badge-ghost ml-auto">{seeding_count}</span>
|
||||
<span class="badge badge-sm badge-ghost ml-auto bg-white/10 border-0">{seeding_count}</span>
|
||||
|
||||
</button>
|
||||
|
||||
@@ -168,7 +168,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
<li>
|
||||
|
||||
<button class={move || format!("cursor-pointer {}", filter_class(crate::store::FilterStatus::Completed))} on:click=move |_| set_filter(crate::store::FilterStatus::Completed)>
|
||||
<button class={move || format!("cursor-pointer hover:bg-white/10 {}", filter_class(crate::store::FilterStatus::Completed))} on:click=move |_| set_filter(crate::store::FilterStatus::Completed)>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
|
||||
@@ -178,7 +178,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
"Completed"
|
||||
|
||||
<span class="badge badge-sm badge-ghost ml-auto">{completed_count}</span>
|
||||
<span class="badge badge-sm badge-ghost ml-auto bg-white/10 border-0">{completed_count}</span>
|
||||
|
||||
</button>
|
||||
|
||||
@@ -186,7 +186,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
<li>
|
||||
|
||||
<button class={move || format!("cursor-pointer {}", filter_class(crate::store::FilterStatus::Paused))} on:click=move |_| set_filter(crate::store::FilterStatus::Paused)>
|
||||
<button class={move || format!("cursor-pointer hover:bg-white/10 {}", filter_class(crate::store::FilterStatus::Paused))} on:click=move |_| set_filter(crate::store::FilterStatus::Paused)>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
|
||||
@@ -196,7 +196,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
"Paused"
|
||||
|
||||
<span class="badge badge-sm badge-ghost ml-auto">{paused_count}</span>
|
||||
<span class="badge badge-sm badge-ghost ml-auto bg-white/10 border-0">{paused_count}</span>
|
||||
|
||||
</button>
|
||||
|
||||
@@ -204,7 +204,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
<li>
|
||||
|
||||
<button class={move || format!("cursor-pointer {}", filter_class(crate::store::FilterStatus::Inactive))} on:click=move |_| set_filter(crate::store::FilterStatus::Inactive)>
|
||||
<button class={move || format!("cursor-pointer hover:bg-white/10 {}", filter_class(crate::store::FilterStatus::Inactive))} on:click=move |_| set_filter(crate::store::FilterStatus::Inactive)>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
|
||||
@@ -214,7 +214,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
"Inactive"
|
||||
|
||||
<span class="badge badge-sm badge-ghost ml-auto">{inactive_count}</span>
|
||||
<span class="badge badge-sm badge-ghost ml-auto bg-white/10 border-0">{inactive_count}</span>
|
||||
|
||||
</button>
|
||||
|
||||
@@ -226,13 +226,13 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
|
||||
|
||||
<div class="p-4 border-t border-base-300 bg-base-200/50">
|
||||
<div class="p-4 border-t border-white/5 bg-black/20 backdrop-blur-sm">
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
|
||||
<div class="avatar">
|
||||
|
||||
<div class="w-8 rounded-full bg-neutral text-neutral-content ring ring-primary ring-offset-base-100 ring-offset-1">
|
||||
<div class="w-8 rounded-full bg-primary/20 text-primary ring ring-primary ring-offset-base-100 ring-offset-1 ring-opacity-50">
|
||||
|
||||
<span class="text-sm font-bold flex items-center justify-center h-full">{first_letter}</span>
|
||||
|
||||
@@ -242,9 +242,9 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
<div class="flex-1 overflow-hidden">
|
||||
|
||||
<div class="font-bold text-sm truncate">{username}</div>
|
||||
<div class="font-bold text-sm truncate text-white">{username}</div>
|
||||
|
||||
<div class="text-[10px] text-base-content/60 truncate">"Online"</div>
|
||||
<div class="text-[10px] text-white/50 truncate">"Online"</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ pub fn Toolbar() -> impl IntoView {
|
||||
let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
|
||||
|
||||
view! {
|
||||
<div class="navbar min-h-14 h-auto bg-base-100 p-0" style="padding-top: env(safe-area-inset-top);">
|
||||
<div class="navbar glass-header min-h-14 h-auto p-0" style="padding-top: env(safe-area-inset-top);">
|
||||
<div class="navbar-start gap-4 px-4">
|
||||
<label for="my-drawer" class="btn btn-square btn-ghost lg:hidden drawer-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="inline-block w-5 h-5 stroke-current"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path></svg>
|
||||
@@ -14,7 +14,7 @@ pub fn Toolbar() -> impl IntoView {
|
||||
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
class="btn btn-sm btn-primary gap-2 font-normal"
|
||||
class="btn btn-sm btn-primary gap-2 font-normal border-0 bg-primary/80 hover:bg-primary backdrop-blur text-white shadow-lg shadow-primary/20"
|
||||
title="Add Magnet Link"
|
||||
on:click=move |_| set_show_add_modal.set(true)
|
||||
>
|
||||
@@ -29,11 +29,11 @@ pub fn Toolbar() -> impl IntoView {
|
||||
</div>
|
||||
|
||||
<div class="navbar-end gap-2 px-4">
|
||||
<div class="join">
|
||||
<div class="join glass-input rounded-lg p-0.5">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
class="input input-sm input-bordered join-item w-full max-w-xs focus:outline-none"
|
||||
class="input input-sm input-ghost join-item w-full max-w-xs focus:outline-none focus:bg-transparent placeholder-gray-400 text-white"
|
||||
prop:value=move || store.search_query.get()
|
||||
on:input=move |ev| store.search_query.set(event_target_value(&ev))
|
||||
on:keydown=move |ev: web_sys::KeyboardEvent| {
|
||||
@@ -44,11 +44,11 @@ pub fn Toolbar() -> impl IntoView {
|
||||
/>
|
||||
<Show when=move || !store.search_query.get().is_empty()>
|
||||
<button
|
||||
class="btn btn-sm btn-ghost join-item border-base-content/20 border-l-0 px-2"
|
||||
class="btn btn-sm btn-ghost join-item px-2 text-white/50 hover:text-white"
|
||||
title="Clear Search"
|
||||
on:click=move |_| store.search_query.set(String::new())
|
||||
>
|
||||
<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 opacity-70">
|
||||
<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="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
@@ -255,33 +255,33 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
};
|
||||
|
||||
view! {
|
||||
<div class="overflow-x-auto h-full bg-base-100 relative">
|
||||
<div class="hidden md:block h-full overflow-x-auto">
|
||||
<div class="overflow-x-auto h-full relative p-4">
|
||||
<div class="hidden md:block h-full overflow-x-auto glass-panel rounded-2xl">
|
||||
<table class="table table-sm table-pin-rows w-full max-w-full whitespace-nowrap">
|
||||
<thead>
|
||||
<tr class="text-xs uppercase text-base-content/60 border-b border-base-200">
|
||||
<th class="cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::Name)>
|
||||
<tr class="text-xs uppercase text-white/50 border-b border-white/5 bg-gray-900/40 backdrop-blur-md">
|
||||
<th class="cursor-pointer hover:bg-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::Name)>
|
||||
<div class="flex items-center">"Name" {move || sort_arrow(SortColumn::Name)}</div>
|
||||
</th>
|
||||
<th class="w-24 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::Size)>
|
||||
<th class="w-24 cursor-pointer hover:bg-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::Size)>
|
||||
<div class="flex items-center">"Size" {move || sort_arrow(SortColumn::Size)}</div>
|
||||
</th>
|
||||
<th class="w-48 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::Progress)>
|
||||
<th class="w-48 cursor-pointer hover:bg-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::Progress)>
|
||||
<div class="flex items-center">"Progress" {move || sort_arrow(SortColumn::Progress)}</div>
|
||||
</th>
|
||||
<th class="w-24 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::Status)>
|
||||
<th class="w-24 cursor-pointer hover:bg-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::Status)>
|
||||
<div class="flex items-center">"Status" {move || sort_arrow(SortColumn::Status)}</div>
|
||||
</th>
|
||||
<th class="w-24 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::DownSpeed)>
|
||||
<th class="w-24 cursor-pointer hover:bg-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::DownSpeed)>
|
||||
<div class="flex items-center">"Down Speed" {move || sort_arrow(SortColumn::DownSpeed)}</div>
|
||||
</th>
|
||||
<th class="w-24 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::UpSpeed)>
|
||||
<th class="w-24 cursor-pointer hover:bg-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::UpSpeed)>
|
||||
<div class="flex items-center">"Up Speed" {move || sort_arrow(SortColumn::UpSpeed)}</div>
|
||||
</th>
|
||||
<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-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::ETA)>
|
||||
<div class="flex items-center">"ETA" {move || sort_arrow(SortColumn::ETA)}</div>
|
||||
</th>
|
||||
<th class="w-32 cursor-pointer hover:bg-base-300 group select-none" on:click=move |_| handle_sort(SortColumn::AddedDate)>
|
||||
<th class="w-32 cursor-pointer hover:bg-white/5 group select-none py-4" on:click=move |_| handle_sort(SortColumn::AddedDate)>
|
||||
<div class="flex items-center">"Date" {move || sort_arrow(SortColumn::AddedDate)}</div>
|
||||
</th>
|
||||
</tr>
|
||||
@@ -295,7 +295,7 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
shared::TorrentStatus::Downloading => "text-primary",
|
||||
shared::TorrentStatus::Paused => "text-warning",
|
||||
shared::TorrentStatus::Error => "text-error",
|
||||
_ => "text-base-content/50"
|
||||
_ => "text-white/50"
|
||||
};
|
||||
let t_hash = t.hash.clone();
|
||||
let t_hash_click = t.hash.clone();
|
||||
@@ -307,7 +307,7 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
view! {
|
||||
<tr
|
||||
class=move || {
|
||||
let base = "hover border-b border-base-200 select-none";
|
||||
let base = "hover:bg-white/5 border-b border-white/5 select-none transition-colors duration-150";
|
||||
if is_selected_fn() {
|
||||
format!("{} bg-primary/10", base)
|
||||
} else {
|
||||
@@ -323,21 +323,21 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
move |_| set_selected_hash.set(Some(t_hash.clone()))
|
||||
}
|
||||
>
|
||||
<td class="font-medium truncate max-w-xs" title={t.name.clone()}>
|
||||
<td class="font-medium truncate max-w-xs py-3 text-white" title={t.name.clone()}>
|
||||
{t.name}
|
||||
</td>
|
||||
<td class="opacity-80 font-mono text-[11px]">{format_bytes(t.size)}</td>
|
||||
<td>
|
||||
<td class="opacity-80 font-mono text-[11px] py-3 text-white/70">{format_bytes(t.size)}</td>
|
||||
<td class="py-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<progress class={format!("progress w-24 {}", progress_class)} value={t.percent_complete} max="100"></progress>
|
||||
<span class="text-[10px] opacity-70">{format!("{:.1}%", t.percent_complete)}</span>
|
||||
<progress class={format!("progress w-24 h-1.5 {}", progress_class)} value={t.percent_complete} max="100"></progress>
|
||||
<span class="text-[10px] opacity-70 text-white/70">{format!("{:.1}%", t.percent_complete)}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class={format!("text-[11px] font-medium {}", status_class)}>{status_str}</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">{format_duration(t.eta)}</td>
|
||||
<td class="text-right font-mono text-[11px] opacity-80 whitespace-nowrap">{format_date(t.added_date)}</td>
|
||||
<td class={format!("text-[11px] font-medium py-3 {}", status_class)}>{status_str}</td>
|
||||
<td class="text-right font-mono text-[11px] opacity-80 text-success py-3">{format_speed(t.down_rate)}</td>
|
||||
<td class="text-right font-mono text-[11px] opacity-80 text-primary py-3">{format_speed(t.up_rate)}</td>
|
||||
<td class="text-right font-mono text-[11px] opacity-80 py-3 text-white/70">{format_duration(t.eta)}</td>
|
||||
<td class="text-right font-mono text-[11px] opacity-80 whitespace-nowrap py-3 text-white/70">{format_date(t.added_date)}</td>
|
||||
</tr>
|
||||
}
|
||||
}).collect::<Vec<_>>()}
|
||||
@@ -345,19 +345,19 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="md:hidden flex flex-col h-full bg-base-200 relative cursor-pointer">
|
||||
<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 cursor-default">
|
||||
<span class="text-xs font-bold opacity-50 uppercase tracking-wider">"Torrents"</span>
|
||||
<div class="md:hidden flex flex-col h-full relative cursor-pointer">
|
||||
<div class="px-3 py-2 flex justify-between items-center glass-header z-10 shrink-0 cursor-default rounded-b-xl mb-3">
|
||||
<span class="text-xs font-bold text-primary uppercase tracking-wider">"Torrents"</span>
|
||||
|
||||
<details class="dropdown dropdown-end" node_ref=sort_details_ref>
|
||||
<summary class="btn btn-ghost btn-xs gap-1 opacity-70 font-normal list-none [&::-webkit-details-marker]:hidden cursor-pointer">
|
||||
<summary class="btn btn-ghost btn-xs gap-1 opacity-70 font-normal list-none [&::-webkit-details-marker]:hidden cursor-pointer text-white">
|
||||
<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 pointer-events-none">
|
||||
<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>
|
||||
<span class="pointer-events-none">"Sort"</span>
|
||||
</summary>
|
||||
<ul class="dropdown-content z-[100] menu p-2 shadow bg-base-100 rounded-box w-48 mt-1 border border-base-200 text-xs cursor-default">
|
||||
<li class="menu-title px-2 py-1 opacity-50 text-[10px] uppercase font-bold">"Sort By"</li>
|
||||
<ul class="dropdown-content z-[100] menu p-2 shadow-xl glass-panel rounded-box w-48 mt-1 text-xs cursor-default">
|
||||
<li class="menu-title px-2 py-1 opacity-50 text-[10px] uppercase font-bold text-white">"Sort By"</li>
|
||||
{
|
||||
let columns = vec![
|
||||
(SortColumn::Name, "Name"),
|
||||
@@ -378,7 +378,7 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
<li>
|
||||
<button
|
||||
type="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/20 text-primary font-bold flex justify-between hover:bg-primary/30" } else { "flex justify-between text-white/80 hover:bg-white/10" }
|
||||
on:click=move |_| {
|
||||
handle_sort(col);
|
||||
if let Some(el) = sort_details_ref.get_untracked() {
|
||||
@@ -408,11 +408,11 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
let progress_class = if t.percent_complete >= 100.0 { "progress-success" } else { "progress-primary" };
|
||||
let status_str = format!("{:?}", t.status);
|
||||
let status_badge_class = match t.status {
|
||||
shared::TorrentStatus::Seeding => "badge-success badge-soft",
|
||||
shared::TorrentStatus::Downloading => "badge-primary badge-soft",
|
||||
shared::TorrentStatus::Paused => "badge-warning badge-soft",
|
||||
shared::TorrentStatus::Error => "badge-error badge-soft",
|
||||
_ => "badge-ghost"
|
||||
shared::TorrentStatus::Seeding => "badge-success badge-soft bg-success/20 text-success border-0",
|
||||
shared::TorrentStatus::Downloading => "badge-primary badge-soft bg-primary/20 text-primary border-0",
|
||||
shared::TorrentStatus::Paused => "badge-warning badge-soft bg-warning/20 text-warning border-0",
|
||||
shared::TorrentStatus::Error => "badge-error badge-soft bg-error/20 text-error border-0",
|
||||
_ => "badge-ghost bg-white/10 text-white/50 border-0"
|
||||
};
|
||||
let _t_hash = t.hash.clone();
|
||||
let t_hash_click = t.hash.clone();
|
||||
@@ -459,7 +459,7 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
view! {
|
||||
<div
|
||||
class=move || {
|
||||
"card card-compact bg-base-100 shadow-sm border border-base-200 transition-transform active:scale-[0.99] select-none cursor-pointer"
|
||||
"card card-compact glass-card transition-transform active:scale-[0.99] select-none cursor-pointer"
|
||||
}
|
||||
style="user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;"
|
||||
on:contextmenu={
|
||||
@@ -477,36 +477,36 @@ pub fn TorrentTable() -> impl IntoView {
|
||||
>
|
||||
<div class="card-body gap-3">
|
||||
<div class="flex justify-between items-start gap-2">
|
||||
<h3 class="font-medium text-sm line-clamp-2 leading-tight">{t.name}</h3>
|
||||
<h3 class="font-medium text-sm line-clamp-2 leading-tight text-white">{t.name}</h3>
|
||||
<div class={format!("badge badge-xs text-[10px] whitespace-nowrap {}", status_badge_class)}>
|
||||
{status_str}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between text-[10px] opacity-70">
|
||||
<div class="flex justify-between text-[10px] opacity-70 text-white/70">
|
||||
<span>{format_bytes(t.size)}</span>
|
||||
<span>{format!("{:.1}%", t.percent_complete)}</span>
|
||||
</div>
|
||||
<progress class={format!("progress w-full h-1.5 {}", progress_class)} value={t.percent_complete} max="100"></progress>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-2 text-[10px] font-mono opacity-80 pt-1 border-t border-base-200/50">
|
||||
<div class="grid grid-cols-4 gap-2 text-[10px] font-mono opacity-80 pt-1 border-t border-white/10">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-[9px] opacity-60 uppercase">"Down"</span>
|
||||
<span class="text-[9px] opacity-60 uppercase text-white/50">"Down"</span>
|
||||
<span class="text-success">{format_speed(t.down_rate)}</span>
|
||||
</div>
|
||||
<div class="flex flex-col text-center border-l border-r border-base-200/50">
|
||||
<span class="text-[9px] opacity-60 uppercase">"Up"</span>
|
||||
<div class="flex flex-col text-center border-l border-r border-white/10">
|
||||
<span class="text-[9px] opacity-60 uppercase text-white/50">"Up"</span>
|
||||
<span class="text-primary">{format_speed(t.up_rate)}</span>
|
||||
</div>
|
||||
<div class="flex flex-col text-center border-r border-base-200/50">
|
||||
<span class="text-[9px] opacity-60 uppercase">"ETA"</span>
|
||||
<span>{format_duration(t.eta)}</span>
|
||||
<div class="flex flex-col text-center border-r border-white/10">
|
||||
<span class="text-[9px] opacity-60 uppercase text-white/50">"ETA"</span>
|
||||
<span class="text-white/70">{format_duration(t.eta)}</span>
|
||||
</div>
|
||||
<div class="flex flex-col text-right">
|
||||
<span class="text-[9px] opacity-60 uppercase">"Date"</span>
|
||||
<span>{format_date(t.added_date)}</span>
|
||||
<span class="text-[9px] opacity-60 uppercase text-white/50">"Date"</span>
|
||||
<span class="text-white/70">{format_date(t.added_date)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,13 +3,56 @@ module.exports = {
|
||||
content: ["./index.html", "./src/**/*.{rs,html}"],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['"Space Grotesk"', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
primary: {
|
||||
DEFAULT: "#f49d25",
|
||||
focus: "#d68315",
|
||||
content: "#ffffff",
|
||||
},
|
||||
gray: {
|
||||
900: "#111827",
|
||||
800: "#1f2937",
|
||||
700: "#374151",
|
||||
glass: "rgba(31, 41, 55, 0.7)",
|
||||
},
|
||||
glass: {
|
||||
100: "rgba(255, 255, 255, 0.1)",
|
||||
200: "rgba(255, 255, 255, 0.2)",
|
||||
border: "rgba(255, 255, 255, 0.1)",
|
||||
}
|
||||
},
|
||||
backgroundImage: {
|
||||
'glass-gradient': 'linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.01) 100%)',
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
plugins: [require("daisyui")],
|
||||
daisyui: {
|
||||
themes: [
|
||||
{
|
||||
vibeglass: {
|
||||
"primary": "#f49d25",
|
||||
"secondary": "#3b82f6",
|
||||
"accent": "#10b981",
|
||||
"neutral": "#1f2937",
|
||||
"base-100": "#0f172a", // Çok koyu mavi/siyah arka plan
|
||||
"base-200": "#1e293b",
|
||||
"base-300": "#334155",
|
||||
"base-content": "#f3f4f6",
|
||||
"info": "#3abff8",
|
||||
"success": "#36d399",
|
||||
"warning": "#fbbd23",
|
||||
"error": "#f87272",
|
||||
"--rounded-box": "0.5rem", // ROUND_EIGHT
|
||||
"--rounded-btn": "0.5rem",
|
||||
"--glass-blur": "12px",
|
||||
"--glass-opacity": "0.7",
|
||||
},
|
||||
},
|
||||
"dark",
|
||||
],
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user