diff --git a/Cargo.lock b/Cargo.lock index 31a8fc7..4afd32b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1260,7 +1260,15 @@ dependencies = [ "gloo-timers", "js-sys", "leptos", - "leptos-shadcn-ui", + "leptos-shadcn-avatar", + "leptos-shadcn-badge", + "leptos-shadcn-button", + "leptos-shadcn-card", + "leptos-shadcn-context-menu", + "leptos-shadcn-input", + "leptos-shadcn-progress", + "leptos-shadcn-separator", + "leptos-shadcn-sheet", "leptos-use", "leptos_router", "log", @@ -2149,6 +2157,35 @@ dependencies = [ "send_wrapper", ] +[[package]] +name = "leptos-shadcn-avatar" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb3c5b1f5ba02f7282b55fde1513cdfecef3b25bf5fa44e1eb29fcaf8b927c5" +dependencies = [ + "leptos", + "leptos-shadcn-signal-management", + "leptos-style", + "tailwind_fuse", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos-shadcn-badge" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24578fb0bc21eb21be4e686e6719c7e183acb8fd071a4f81fb27fe452751c88a" +dependencies = [ + "leptos", + "leptos-node-ref", + "leptos-shadcn-signal-management", + "leptos-struct-component", + "leptos-style", + "tailwind_fuse", + "web-sys", +] + [[package]] name = "leptos-shadcn-button" version = "0.8.1" @@ -2164,6 +2201,37 @@ dependencies = [ "web-sys", ] +[[package]] +name = "leptos-shadcn-card" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b5cda16742d1e20284e5f6805eab88b6e54c1378d1548a8e15a5eedda1ea3eb" +dependencies = [ + "leptos", + "leptos-node-ref", + "leptos-shadcn-signal-management", + "leptos-struct-component", + "leptos-style", + "tailwind_fuse", + "web-sys", +] + +[[package]] +name = "leptos-shadcn-context-menu" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f440e9a7517dfe6ba758080ddba1dfe42e4697008f60adfc112c5da02dca8d" +dependencies = [ + "leptos", + "leptos-node-ref", + "leptos-shadcn-signal-management", + "leptos-struct-component", + "leptos-style", + "tailwind_fuse", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "leptos-shadcn-input" version = "0.8.1" @@ -2180,6 +2248,51 @@ dependencies = [ "web-sys", ] +[[package]] +name = "leptos-shadcn-progress" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34ca41b8ebfd7f29126e4f8656987834f3613717016f11f3983da85a90669f6" +dependencies = [ + "leptos", + "leptos-node-ref", + "leptos-shadcn-signal-management", + "leptos-struct-component", + "leptos-style", + "tailwind_fuse", + "web-sys", +] + +[[package]] +name = "leptos-shadcn-separator" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5dfda49f059fd4d1549d663e6743e37a5c6c84d1ac2d6daec32caa3156bc268" +dependencies = [ + "leptos", + "leptos-node-ref", + "leptos-shadcn-signal-management", + "leptos-struct-component", + "leptos-style", + "tailwind_fuse", + "web-sys", +] + +[[package]] +name = "leptos-shadcn-sheet" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba85819a0c94a7705ed92989442c64cc75d9ed3a4540e711e87c56b206431611" +dependencies = [ + "leptos", + "leptos-node-ref", + "leptos-shadcn-signal-management", + "leptos-struct-component", + "leptos-style", + "tailwind_fuse", + "web-sys", +] + [[package]] name = "leptos-shadcn-signal-management" version = "0.1.0" @@ -2194,23 +2307,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "leptos-shadcn-ui" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43430605d3d049a4cf68fb7dff4e6f940426ec48131f4662963f62f11baa3e18" -dependencies = [ - "gloo-timers", - "leptos", - "leptos-node-ref", - "leptos-shadcn-button", - "leptos-shadcn-input", - "leptos-struct-component", - "leptos-style", - "leptos_router", - "tailwind_fuse", -] - [[package]] name = "leptos-struct-component" version = "0.2.0" diff --git a/backend/src/main.rs b/backend/src/main.rs index 85d6015..82979cd 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -346,10 +346,7 @@ async fn main() { match diff::diff_torrents(&previous_torrents, &new_torrents) { diff::DiffResult::FullUpdate => { - let _ = event_bus_tx.send(AppEvent::FullList { - torrents: new_torrents.clone(), - timestamp: now, - }); + let _ = event_bus_tx.send(AppEvent::FullList(new_torrents.clone(), now)); } diff::DiffResult::Partial(updates) => { for update in updates { diff --git a/backend/src/sse.rs b/backend/src/sse.rs index 1f14263..09b2f0a 100644 --- a/backend/src/sse.rs +++ b/backend/src/sse.rs @@ -210,10 +210,7 @@ pub async fn sse_handler( .unwrap() .as_secs(); - let event_data = AppEvent::FullList { - torrents: initial_torrents, - timestamp, - }; + let event_data = AppEvent::FullList(initial_torrents, timestamp); match rmp_serde::to_vec(&event_data) { Ok(bytes) => Event::default().data(BASE64.encode(bytes)), @@ -250,7 +247,7 @@ pub async fn sse_handler( .keep_alive(axum::response::sse::KeepAlive::default()); ( - [("content-type", "application/x-msgpack")], + [("content-type", "text/event-stream")], sse ) } \ No newline at end of file diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index 04491aa..1b6d51a 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -33,4 +33,14 @@ codee = "0.3" thiserror = "2.0" rmp-serde = "1.3" struct-patch = "0.5" -leptos-shadcn-ui = { version = "0.9.0", default-features = false, features = ["button", "input"] } + +# ShadCN UI Components (Individual) +leptos-shadcn-button = "0.8" +leptos-shadcn-input = "0.8" +leptos-shadcn-card = "0.8" +leptos-shadcn-badge = "0.8" +leptos-shadcn-context-menu = "0.8" +leptos-shadcn-separator = "0.8" +leptos-shadcn-progress = "0.8" +leptos-shadcn-avatar = "0.8" +leptos-shadcn-sheet = "0.8" \ No newline at end of file diff --git a/frontend/input.css b/frontend/input.css index bc485a4..b261934 100644 --- a/frontend/input.css +++ b/frontend/input.css @@ -126,6 +126,14 @@ body { @apply bg-background text-foreground; } + + /* Ensure Shadcn Utilities are always available */ + .bg-popover { background-color: hsl(var(--popover)); } + .text-popover-foreground { color: hsl(var(--popover-foreground)); } + .border-border { border-color: hsl(var(--border)); } + .shadow-md { box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); } + .z-50 { z-index: 50; } + .z-100 { z-index: 100; } } /* Fix for iOS click/blur events */ diff --git a/frontend/public/tailwind.css b/frontend/public/tailwind.css index 75f985b..b06a21b 100644 --- a/frontend/public/tailwind.css +++ b/frontend/public/tailwind.css @@ -50,18 +50,17 @@ --text-lg--line-height: calc(1.75 / 1.125); --text-2xl: 1.5rem; --text-2xl--line-height: calc(2 / 1.5); - --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; --tracking-tight: -0.025em; - --tracking-wider: 0.05em; --leading-tight: 1.25; --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); --radius-xl: 0.75rem; + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --animate-spin: spin 1s linear infinite; + --blur-sm: 8px; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); @@ -239,9 +238,6 @@ .pointer-events-auto { pointer-events: auto; } - .pointer-events-none { - pointer-events: none; - } .absolute { position: absolute; } @@ -254,12 +250,15 @@ .static { position: static; } + .inset-0 { + inset: calc(var(--spacing) * 0); + } + .inset-y-0 { + inset-block: calc(var(--spacing) * 0); + } .top-1\/2 { top: calc(1/2 * 100%); } - .top-full { - top: 100%; - } .right-0 { right: calc(var(--spacing) * 0); } @@ -278,8 +277,11 @@ .left-2 { left: calc(var(--spacing) * 2); } - .z-10 { - z-index: 10; + .z-40 { + z-index: 40; + } + .z-50 { + z-index: 50; } .z-\[99\] { z-index: 99; @@ -305,12 +307,6 @@ max-width: 96rem; } } - .my-0\.5 { - margin-block: calc(var(--spacing) * 0.5); - } - .mt-1 { - margin-top: calc(var(--spacing) * 1); - } .mt-2 { margin-top: calc(var(--spacing) * 2); } @@ -413,9 +409,6 @@ .min-h-14 { min-height: calc(var(--spacing) * 14); } - .min-h-\[100dvh\] { - min-height: 100dvh; - } .min-h-screen { min-height: 100vh; } @@ -452,6 +445,9 @@ .w-48 { width: calc(var(--spacing) * 48); } + .w-56 { + width: calc(var(--spacing) * 56); + } .w-64 { width: calc(var(--spacing) * 64); } @@ -470,18 +466,20 @@ .min-w-\[8rem\] { min-width: 8rem; } - .min-w-\[10rem\] { - min-width: 10rem; - } - .min-w-\[200px\] { - min-width: 200px; - } .flex-1 { flex: 1; } .shrink-0 { flex-shrink: 0; } + .-translate-x-full { + --tw-translate-x: -100%; + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .translate-x-0 { + --tw-translate-x: calc(var(--spacing) * 0); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .-translate-y-1\/2 { --tw-translate-y: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -528,9 +526,6 @@ .justify-start { justify-content: flex-start; } - .gap-0\.5 { - gap: calc(var(--spacing) * 0.5); - } .gap-1 { gap: calc(var(--spacing) * 1); } @@ -592,9 +587,6 @@ .rounded-full { border-radius: calc(infinity * 1px); } - .rounded-lg { - border-radius: var(--radius-lg); - } .rounded-md { border-radius: var(--radius-md); } @@ -682,10 +674,10 @@ .bg-background { background-color: var(--color-background); } - .bg-background\/95 { - background-color: color-mix(in srgb, hsl(var(--background)) 95%, transparent); + .bg-background\/80 { + background-color: color-mix(in srgb, hsl(var(--background)) 80%, transparent); @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-background) 95%, transparent); + background-color: color-mix(in oklab, var(--color-background) 80%, transparent); } } .bg-blue-100 { @@ -802,15 +794,15 @@ .pr-2 { padding-right: calc(var(--spacing) * 2); } + .pb-0 { + padding-bottom: calc(var(--spacing) * 0); + } .pb-2 { padding-bottom: calc(var(--spacing) * 2); } .pb-3 { padding-bottom: calc(var(--spacing) * 3); } - .pb-8 { - padding-bottom: calc(var(--spacing) * 8); - } .pl-8 { padding-left: calc(var(--spacing) * 8); } @@ -858,10 +850,6 @@ --tw-font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium); } - .font-normal { - --tw-font-weight: var(--font-weight-normal); - font-weight: var(--font-weight-normal); - } .font-semibold { --tw-font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold); @@ -870,10 +858,6 @@ --tw-tracking: var(--tracking-tight); letter-spacing: var(--tracking-tight); } - .tracking-wider { - --tw-tracking: var(--tracking-wider); - letter-spacing: var(--tracking-wider); - } .whitespace-nowrap { white-space: nowrap; } @@ -977,25 +961,14 @@ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } - .shadow-xl { - --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } - .ring-2 { - --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } - .ring-primary { - --tw-ring-color: var(--color-primary); - } .ring-offset-background { --tw-ring-offset-color: var(--color-background); } .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } - .backdrop-blur { - --tw-backdrop-blur: blur(8px); + .backdrop-blur-sm { + --tw-backdrop-blur: blur(var(--blur-sm)); -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); } @@ -1014,14 +987,23 @@ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); } - .duration-100 { - --tw-duration: 100ms; - transition-duration: 100ms; + .transition-transform { + transition-property: transform, translate, scale, rotate; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .duration-300 { + --tw-duration: 300ms; + transition-duration: 300ms; } .duration-500 { --tw-duration: 500ms; transition-duration: 500ms; } + .ease-in-out { + --tw-ease: var(--ease-in-out); + transition-timing-function: var(--ease-in-out); + } .outline-none { --tw-outline-style: none; outline-style: none; @@ -1030,9 +1012,6 @@ -webkit-user-select: none; user-select: none; } - .ring-inset { - --tw-ring-inset: inset; - } .group-open\:block { &:is(:where(.group):is([open], :popover-open, :open) *) { display: block; @@ -1083,6 +1062,13 @@ color: var(--color-muted-foreground); } } + .hover\:border-primary { + &:hover { + @media (hover: hover) { + border-color: var(--color-primary); + } + } + } .hover\:bg-accent { &:hover { @media (hover: hover) { @@ -1107,13 +1093,6 @@ } } } - .hover\:bg-primary { - &:hover { - @media (hover: hover) { - background-color: var(--color-primary); - } - } - } .hover\:bg-primary\/90 { &:hover { @media (hover: hover) { @@ -1160,11 +1139,21 @@ background-color: var(--color-accent); } } + .focus\:bg-destructive { + &:focus { + background-color: var(--color-destructive); + } + } .focus\:text-accent-foreground { &:focus { color: var(--color-accent-foreground); } } + .focus\:text-destructive-foreground { + &:focus { + color: var(--color-destructive-foreground); + } + } .focus\:ring-2 { &:focus { --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); @@ -1297,11 +1286,22 @@ max-width: 420px; } } + .lg\:relative { + @media (width >= 64rem) { + position: relative; + } + } .lg\:hidden { @media (width >= 64rem) { display: none; } } + .lg\:translate-x-0 { + @media (width >= 64rem) { + --tw-translate-x: calc(var(--spacing) * 0); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + } .dark\:border-blue-800 { @media (prefers-color-scheme: dark) { border-color: var(--color-blue-800); @@ -1479,6 +1479,24 @@ background-color: var(--color-background); color: var(--color-foreground); } + .bg-popover { + background-color: hsl(var(--popover)); + } + .text-popover-foreground { + color: hsl(var(--popover-foreground)); + } + .border-border { + border-color: hsl(var(--border)); + } + .shadow-md { + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + } + .z-50 { + z-index: 50; + } + .z-100 { + z-index: 100; + } } @media (hover: none) { body { @@ -1712,6 +1730,10 @@ syntax: "*"; inherits: false; } +@property --tw-ease { + syntax: "*"; + inherits: false; +} @keyframes spin { to { transform: rotate(360deg); @@ -1771,6 +1793,7 @@ --tw-backdrop-saturate: initial; --tw-backdrop-sepia: initial; --tw-duration: initial; + --tw-ease: initial; } } } diff --git a/frontend/src/app.rs b/frontend/src/app.rs index 6e975b0..d54ed6f 100644 --- a/frontend/src/app.rs +++ b/frontend/src/app.rs @@ -3,7 +3,6 @@ use crate::components::toast::ToastContainer; use crate::components::torrent::table::TorrentTable; use crate::components::auth::login::Login; use crate::components::auth::setup::Setup; -use crate::api; use leptos::prelude::*; use leptos::task::spawn_local; use leptos_router::components::{Router, Routes, Route}; @@ -122,14 +121,14 @@ pub fn App() -> impl IntoView {
"Yükleniyor..."
- }> + }.into_any()>