diff --git a/frontend/src/components/hooks/use_random.rs b/frontend/src/components/hooks/use_random.rs
index d2f5617..049f410 100644
--- a/frontend/src/components/hooks/use_random.rs
+++ b/frontend/src/components/hooks/use_random.rs
@@ -1,31 +1,5 @@
-use std::collections::hash_map::DefaultHasher;
-use std::hash::{Hash, Hasher};
-use std::sync::atomic::{AtomicUsize, Ordering};
+use leptos::prelude::*;
-const PREFIX: &str = "rust_ui"; // Must NOT contain "/" or "-"
-
-pub fn use_random_id() -> String {
- format!("_{PREFIX}_{}", generate_hash())
+pub fn use_random_id_for(prefix: &str) -> String {
+ format!("{}_{}", prefix, js_sys::Math::random().to_string().replace(".", ""))
}
-
-pub fn use_random_id_for(element: &str) -> String {
- format!("{}_{PREFIX}_{}", element, generate_hash())
-}
-
-pub fn use_random_transition_name() -> String {
- let random_id = use_random_id();
- format!("view-transition-name: {random_id}")
-}
-
-/* ========================================================== */
-/* ✨ FUNCTIONS ✨ */
-/* ========================================================== */
-
-static COUNTER: AtomicUsize = AtomicUsize::new(1);
-
-fn generate_hash() -> u64 {
- let mut hasher = DefaultHasher::new();
- let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
- counter.hash(&mut hasher);
- hasher.finish()
-}
\ No newline at end of file
diff --git a/frontend/src/components/torrent/table.rs b/frontend/src/components/torrent/table.rs
index 528bc37..0964158 100644
--- a/frontend/src/components/torrent/table.rs
+++ b/frontend/src/components/torrent/table.rs
@@ -6,7 +6,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/drag_and_drop.rs b/frontend/src/components/ui/drag_and_drop.rs
deleted file mode 100644
index 2029507..0000000
--- a/frontend/src/components/ui/drag_and_drop.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use leptos::prelude::*;
-use leptos_ui::clx;
-
-mod components {
- use super::*;
- clx! {Draggable, div, "flex flex-col gap-4 w-full max-w-4xl"}
- clx! {DraggableZone, div, "dragabble__container", "bg-neutral-600 p-4 mt-4"}
-
- // TODO. ItemRoot (needs `draggable` as clx attribute).
-}
-
-pub use components::*;
-
-/* ========================================================== */
-/* ✨ FUNCTIONS ✨ */
-/* ========================================================== */
-
-#[component]
-pub fn DraggableItem(#[prop(into)] text: String) -> impl IntoView {
- view! {
-
- {text}
-
- }
-}
\ No newline at end of file
diff --git a/frontend/src/components/ui/sonner.rs b/frontend/src/components/ui/sonner.rs
deleted file mode 100644
index 742ab05..0000000
--- a/frontend/src/components/ui/sonner.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use leptos::prelude::*;
-use tw_merge::*;
-
-#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display)]
-pub enum ToastType {
- #[default]
- Default,
- Success,
- Error,
- Warning,
- Info,
- Loading,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display)]
-pub enum SonnerPosition {
- TopLeft,
- TopCenter,
- TopRight,
- #[default]
- BottomRight,
- BottomCenter,
- BottomLeft,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display)]
-pub enum SonnerDirection {
- TopDown,
- #[default]
- BottomUp,
-}
-
-#[component]
-pub fn SonnerTrigger(
- children: Children,
- #[prop(into, optional)] class: String,
- #[prop(optional, default = ToastType::default())] variant: ToastType,
- #[prop(into)] title: String,
- #[prop(into)] description: String,
- #[prop(into, optional)] position: String,
-) -> impl IntoView {
- let variant_classes = match variant {
- ToastType::Default => "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
- ToastType::Success => "bg-success text-success-foreground hover:bg-success/90",
- ToastType::Error => "bg-destructive text-white shadow-xs hover:bg-destructive/90 dark:bg-destructive/60",
- ToastType::Warning => "bg-warning text-warning-foreground hover:bg-warning/90",
- ToastType::Info => "bg-info text-info-foreground shadow-xs hover:bg-info/90",
- ToastType::Loading => "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
- };
-
- let merged_class = tw_merge!(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] w-fit cursor-pointer h-9 px-4 py-2",
- variant_classes,
- class
- );
-
- // Only set position attribute if not empty
- let position_attr = if position.is_empty() { None } else { Some(position) };
-
- view! {
-
- }
-}
-
-#[component]
-pub fn SonnerContainer(
- children: Children,
- #[prop(into, optional)] class: String,
- #[prop(optional, default = SonnerPosition::default())] position: SonnerPosition,
-) -> impl IntoView {
- let merged_class = tw_merge!("toast__container fixed z-50", class);
-
- view! {
-
- {children()}
-
- }
-}
-
-#[component]
-pub fn SonnerList(
- children: Children,
- #[prop(into, optional)] class: String,
- #[prop(optional, default = SonnerPosition::default())] position: SonnerPosition,
- #[prop(optional, default = SonnerDirection::default())] direction: SonnerDirection,
- #[prop(into, default = "false".to_string())] expanded: String,
- #[prop(into, optional)] style: String,
-) -> impl IntoView {
- // pointer-events-none: container doesn't block clicks when empty
- // [&>*]:pointer-events-auto: toast items still receive clicks
- let merged_class = tw_merge!(
- "flex relative flex-col opacity-100 gap-[15px] h-[100px] w-[400px] pointer-events-none [&>*]:pointer-events-auto",
- class
- );
-
- view! {
-
- {children()}
-
- }
-}
-
-#[component]
-pub fn SonnerToaster(#[prop(default = SonnerPosition::default())] position: SonnerPosition) -> impl IntoView {
- // Auto-derive direction from position
- let direction = match position {
- SonnerPosition::TopLeft | SonnerPosition::TopCenter | SonnerPosition::TopRight => SonnerDirection::TopDown,
- _ => SonnerDirection::BottomUp,
- };
-
- let container_class = match position {
- SonnerPosition::TopLeft => "left-6 top-6",
- SonnerPosition::TopRight => "right-6 top-6",
- SonnerPosition::TopCenter => "left-1/2 -translate-x-1/2 top-6",
- SonnerPosition::BottomCenter => "left-1/2 -translate-x-1/2 bottom-6",
- SonnerPosition::BottomLeft => "left-6 bottom-6",
- SonnerPosition::BottomRight => "right-6 bottom-6",
- };
-
- view! {
-
-
- ""
-
-
- }
-}
\ No newline at end of file
diff --git a/frontend/src/components/ui/toast.rs b/frontend/src/components/ui/toast.rs
index 3200d09..480255a 100644
--- a/frontend/src/components/ui/toast.rs
+++ b/frontend/src/components/ui/toast.rs
@@ -49,6 +49,7 @@ pub fn SonnerTrigger(
is_expanded: Signal,
#[prop(optional)] on_dismiss: Option>,
) -> impl IntoView {
+ let _ = is_expanded; // Silence unused warning while keeping prop name intact for builder
let variant_classes = match toast.variant {
ToastType::Default => "bg-background text-foreground border-border",
ToastType::Success => "bg-background text-foreground border-border [&_.icon]:text-green-500",