shared_ui.rs
1 use dioxus::prelude::*; 2 use lucide_dioxus::{Database, File, FileCode, FileSpreadsheet, FileText, Image}; 3 4 pub fn file_icon(name: &str) -> Element { 5 let extension = name.rsplit('.').next().unwrap_or("").to_ascii_lowercase(); 6 match extension.as_str() { 7 "js" | "rs" | "css" | "toml" => rsx! { FileCode { class: "w-4 h-4 text-primary" } }, 8 "html" | "htm" => rsx! { FileCode { class: "w-4 h-4 text-chart-3" } }, 9 "svg" | "png" | "jpg" => rsx! { Image { class: "w-4 h-4 text-chart-2" } }, 10 "csv" | "tsv" => rsx! { FileSpreadsheet { class: "w-4 h-4 text-chart-4" } }, 11 "db" | "sqlite" => rsx! { Database { class: "w-4 h-4 text-chart-4" } }, 12 "txt" | "log" | "md" => rsx! { FileText { class: "w-4 h-4 text-muted-foreground" } }, 13 "wasm" | "was" => rsx! { FileCode { class: "w-4 h-4 text-chart-5" } }, 14 _ => rsx! { File { class: "w-4 h-4 text-muted-foreground" } }, 15 } 16 } 17 18 #[component] 19 pub fn LiveIndicator(connected: bool) -> Element { 20 let (dot_class, ping_class, label) = if connected { 21 ("bg-emerald-400", "absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-70 animate-ping", "LIVE") 22 } else { 23 ("bg-amber-500", "absolute inline-flex h-full w-full rounded-full bg-amber-500 opacity-70 animate-pulse", "POLLING") 24 }; 25 rsx! { 26 div { class: "flex items-center gap-2 rounded-full border border-border bg-background/60 px-3 py-1.5 text-xs text-muted-foreground shrink-0", 27 span { class: "relative flex h-2 w-2", 28 span { class: "{ping_class}" } 29 span { class: "relative inline-flex h-2 w-2 rounded-full {dot_class}" } 30 } 31 span { class: "font-medium text-foreground", "{label}" } 32 } 33 } 34 } 35 36 #[component] 37 pub fn StatusBadge(icon: Element, value: String) -> Element { 38 rsx! { 39 span { class: "inline-flex items-center gap-1.5 rounded-full border border-border bg-background/60 px-2.5 py-1 text-xs font-mono text-foreground", 40 {icon} 41 "{value}" 42 } 43 } 44 } 45 46 #[component] 47 pub fn Th(children: Element) -> Element { 48 rsx! { 49 th { scope: "col", class: "text-left px-3 py-2 border-b border-border text-muted-foreground text-xs uppercase tracking-wider sticky top-0 bg-muted whitespace-nowrap", 50 {children} 51 } 52 } 53 } 54 55 #[component] 56 pub fn Td(children: Element, class: Option<String>) -> Element { 57 let extra = class.unwrap_or_default(); 58 rsx! { 59 td { class: "px-3 py-2 text-sm {extra}", {children} } 60 } 61 }