50 lines
1.7 KiB
Rust
50 lines
1.7 KiB
Rust
use dioxus::prelude::*;
|
|
use dioxus_free_icons::icons::bs_icons::*;
|
|
use dioxus_free_icons::Icon;
|
|
|
|
/// A small copy-to-clipboard button that shows a checkmark after copying.
|
|
///
|
|
/// Usage: `CopyButton { value: "text to copy" }`
|
|
#[component]
|
|
pub fn CopyButton(value: String, #[props(default = false)] small: bool) -> Element {
|
|
let mut copied = use_signal(|| false);
|
|
|
|
let size = if small { 12 } else { 14 };
|
|
let class = if small {
|
|
"copy-btn copy-btn-sm"
|
|
} else {
|
|
"copy-btn"
|
|
};
|
|
|
|
rsx! {
|
|
button {
|
|
class: class,
|
|
title: if copied() { "Copied!" } else { "Copy to clipboard" },
|
|
onclick: move |_| {
|
|
let val = value.clone();
|
|
// Escape for JS single-quoted string
|
|
let escaped = val
|
|
.replace('\\', "\\\\")
|
|
.replace('\'', "\\'")
|
|
.replace('\n', "\\n")
|
|
.replace('\r', "\\r");
|
|
let js = format!("navigator.clipboard.writeText('{escaped}')");
|
|
document::eval(&js);
|
|
copied.set(true);
|
|
spawn(async move {
|
|
#[cfg(feature = "web")]
|
|
gloo_timers::future::TimeoutFuture::new(2000).await;
|
|
#[cfg(not(feature = "web"))]
|
|
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
|
|
copied.set(false);
|
|
});
|
|
},
|
|
if copied() {
|
|
Icon { icon: BsCheckLg, width: size, height: size }
|
|
} else {
|
|
Icon { icon: BsClipboard, width: size, height: size }
|
|
}
|
|
}
|
|
}
|
|
}
|