diff --git a/frontend/src/app.rs b/frontend/src/app.rs index 078dae4..228246d 100644 --- a/frontend/src/app.rs +++ b/frontend/src/app.rs @@ -6,7 +6,7 @@ use crate::components::auth::setup::Setup; use leptos::prelude::*; use leptos::task::spawn_local; use leptos_router::components::{Router, Routes, Route}; -use leptos_router::hooks::use_navigate; +use leptos_router::hooks::{use_navigate, use_location}; use crate::components::ui::toast::Toaster; use crate::components::hooks::use_theme_mode::ThemeMode; @@ -41,6 +41,7 @@ pub fn App() -> impl IntoView { fn InnerApp() -> impl IntoView { crate::store::provide_torrent_store(); let store = use_context::(); + let _loc = use_location(); let is_loading = signal(true); let is_authenticated = signal(false); diff --git a/frontend/src/components/layout/toolbar.rs b/frontend/src/components/layout/toolbar.rs index 011e0e8..acd9494 100644 --- a/frontend/src/components/layout/toolbar.rs +++ b/frontend/src/components/layout/toolbar.rs @@ -1,14 +1,13 @@ use leptos::prelude::*; -use icons::PanelLeft; -use crate::components::torrent::add_torrent::AddTorrentDialog; -use crate::components::ui::button::{Button, ButtonVariant, ButtonSize}; +use icons::{PanelLeft, Plus}; +use crate::components::torrent::add_torrent::AddTorrentDialogContent; +use crate::components::ui::button::{ButtonVariant, ButtonSize}; use crate::components::ui::sheet::{Sheet, SheetContent, SheetTrigger, SheetDirection}; +use crate::components::ui::dialog::{Dialog, DialogContent, DialogTrigger}; use crate::components::layout::sidebar::Sidebar; #[component] pub fn Toolbar() -> impl IntoView { - let show_add_modal = signal(false); - view! {
// Sol kısım: Menü butonu (Mobil) + Add Torrent @@ -33,25 +32,24 @@ pub fn Toolbar() -> impl IntoView {
- + + + + + "Add" + + + + + // Sağ kısım boş
- - - - } -} \ No newline at end of file +} diff --git a/frontend/src/components/torrent/add_torrent.rs b/frontend/src/components/torrent/add_torrent.rs index 0d110af..018980f 100644 --- a/frontend/src/components/torrent/add_torrent.rs +++ b/frontend/src/components/torrent/add_torrent.rs @@ -1,17 +1,15 @@ use leptos::prelude::*; use leptos::task::spawn_local; +use wasm_bindgen::JsCast; use crate::components::ui::input::{Input, InputType}; -use crate::store::TorrentStore; use crate::api; - -use crate::components::ui::button::{Button, ButtonVariant}; +use crate::components::ui::button::Button; +use crate::components::ui::dialog::{ + DialogBody, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose +}; #[component] -pub fn AddTorrentDialog( - on_close: Callback<()>, -) -> impl IntoView { - let _store = use_context::().expect("TorrentStore not provided"); - +pub fn AddTorrentDialogContent() -> impl IntoView { let uri = RwSignal::new(String::new()); let is_loading = signal(false); let error_msg = signal(Option::::None); @@ -21,20 +19,30 @@ pub fn AddTorrentDialog( let uri_val = uri.get(); if uri_val.is_empty() { - error_msg.1.set(Some("Please enter a Magnet URI or URL".to_string())); + error_msg.1.set(Some("Lütfen bir Magnet URI veya URL girin".to_string())); return; } is_loading.1.set(true); error_msg.1.set(None); - let on_close = on_close.clone(); spawn_local(async move { match api::torrent::add(&uri_val).await { Ok(_) => { log::info!("Torrent added successfully"); crate::store::toast_success("Torrent başarıyla eklendi"); - on_close.run(()); + + // Programmatically close the dialog by triggering the close button + if let Some(doc) = web_sys::window().and_then(|w| w.document()) { + if let Some(el) = doc.get_element_by_id("add-torrent-dialog") { + if let Some(close_btn) = el.query_selector("[data-dialog-close]").ok().flatten() { + let _ = close_btn.dyn_into::().map(|btn| btn.click()); + } + } + } + + uri.set(String::new()); + is_loading.1.set(false); } Err(e) => { log::error!("Failed to add torrent: {:?}", e); @@ -45,29 +53,16 @@ pub fn AddTorrentDialog( }); }; - let handle_backdrop = { - let on_close = on_close.clone(); - move |e: web_sys::MouseEvent| { - e.stop_propagation(); - on_close.run(()); - } - }; - view! { - // Backdrop overlay -
- // Dialog panel -
- // Header -
-

"Add Torrent"

-

"Enter a Magnet link or a .torrent file URL."

-
+ + + "Add Torrent" + + "Enter a Magnet link or a .torrent file URL." + + -
+ })} -
- +
+
- - // Close button (X) - -
+ } -} \ No newline at end of file +} diff --git a/frontend/src/components/torrent/table.rs b/frontend/src/components/torrent/table.rs index c3f0eaa..862f0bd 100644 --- a/frontend/src/components/torrent/table.rs +++ b/frontend/src/components/torrent/table.rs @@ -7,7 +7,6 @@ use crate::store::{get_action_messages, show_toast}; use crate::api; use shared::NotificationLevel; use crate::components::context_menu::TorrentContextMenu; -use crate::components::ui::card::{Card, CardHeader, CardTitle, CardContent as CardBody}; use crate::components::ui::data_table::*; use crate::components::ui::checkbox::Checkbox; use crate::components::ui::badge::{Badge, BadgeVariant}; diff --git a/frontend/src/components/ui/dialog.rs b/frontend/src/components/ui/dialog.rs index 2b97d68..f7c1eb5 100644 --- a/frontend/src/components/ui/dialog.rs +++ b/frontend/src/components/ui/dialog.rs @@ -72,13 +72,13 @@ pub fn DialogTrigger( pub fn DialogContent( children: Children, #[prop(optional, into)] class: String, + #[prop(optional, into)] id: Option, #[prop(into, optional)] hide_close_button: Option, #[prop(default = true)] close_on_backdrop_click: bool, #[prop(default = "Dialog")] data_name_prefix: &'static str, ) -> impl IntoView { let ctx = expect_context::(); let merged_class = tw_merge!( - // "flex flex-col gap-4", // TODO 🐛 Bug when I try to have this.. Using DialogBody instead. "relative bg-background border rounded-2xl shadow-lg p-6 w-full max-w-[calc(100%-2rem)] max-h-[85vh] fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-100 transition-all duration-200 data-[state=closed]:opacity-0 data-[state=closed]:scale-95 data-[state=open]:opacity-100 data-[state=open]:scale-100", class ); @@ -88,10 +88,14 @@ pub fn DialogContent( let target_id_clone = ctx.target_id.clone(); let backdrop_id = format!("{}_backdrop", ctx.target_id); - let target_id_for_script = ctx.target_id.clone(); let backdrop_id_for_script = backdrop_id.clone(); let backdrop_behavior = if close_on_backdrop_click { "auto" } else { "manual" }; + // Use provided id or fallback to random target_id + let final_id = id.unwrap_or_else(|| ctx.target_id.clone()); + let final_id_for_script = final_id.clone(); + let trigger_id_for_script = ctx.target_id.clone(); + view! { @@ -105,7 +109,7 @@ pub fn DialogContent(
{{ - // Lock scrolling - window.ScrollLock.lock(); - + if (window.ScrollLock) window.ScrollLock.lock(); dialog.setAttribute('data-state', 'open'); backdrop.setAttribute('data-state', 'open'); dialog.style.pointerEvents = 'auto'; @@ -161,28 +163,18 @@ pub fn DialogContent( backdrop.setAttribute('data-state', 'closed'); dialog.style.pointerEvents = 'none'; backdrop.style.pointerEvents = 'none'; - - // Unlock scrolling after animation window.ScrollLock.unlock(200); }}; - // Open dialog when trigger is clicked trigger.addEventListener('click', openDialog); - - // Close buttons - const closeButtons = dialog.querySelectorAll('[data-dialog-close]'); - closeButtons.forEach(btn => {{ + dialog.querySelectorAll('[data-dialog-close]').forEach(btn => {{ btn.addEventListener('click', closeDialog); }}); - - // Close on backdrop click (if data-backdrop="auto") backdrop.addEventListener('click', () => {{ if (dialog.getAttribute('data-backdrop') === 'auto') {{ closeDialog(); }} }}); - - // Handle ESC key to close document.addEventListener('keydown', (e) => {{ if (e.key === 'Escape' && dialog.getAttribute('data-state') === 'open') {{ e.preventDefault(); @@ -190,17 +182,12 @@ pub fn DialogContent( }} }}); }}; - - if (document.readyState === 'loading') {{ - document.addEventListener('DOMContentLoaded', setupDialog); - }} else {{ - setupDialog(); - }} + setupDialog(); }})(); "#, - target_id_for_script, + final_id_for_script, backdrop_id_for_script, - target_id_for_script, + trigger_id_for_script, )} }