Skip to main content

dioxus_docs_kit/components/
copy_page.rs

1use dioxus::prelude::*;
2use dioxus_free_icons::{Icon, icons::ld_icons::*};
3
4/// "Copy page" button for MDX documentation pages.
5///
6/// Copies the page's raw Markdown source to the clipboard — the "copy page for
7/// LLMs" pattern. On success it swaps to a "Copied" state (check icon) for ~2
8/// seconds, then reverts.
9///
10/// The Markdown is handed to the clipboard via `document::eval` argument
11/// passing (`eval.send`), never string-interpolated into the script, so
12/// backticks and quotes in the source can't break the JS.
13///
14/// # Props
15///
16/// - `content`: Raw Markdown source of the current page.
17///
18/// # Stable public classes
19///
20/// Carries `dk-copy-page` so theme presets can target the button.
21#[component]
22pub fn CopyPageButton(content: String) -> Element {
23    #[allow(unused_mut)]
24    let mut copied = use_signal(|| false);
25
26    rsx! {
27        button {
28            class: "dk-copy-page btn btn-ghost btn-sm gap-1.5 opacity-60 hover:opacity-100 transition-all duration-150 hover:bg-base-content/10 shrink-0",
29            title: "Copy page as Markdown",
30            onclick: move |_| {
31                #[cfg(target_arch = "wasm32")]
32                {
33                    let content = content.clone();
34                    spawn(async move {
35                        // Send the Markdown into the script as an argument rather
36                        // than interpolating it — the source contains backticks
37                        // and quotes that would otherwise break the JS.
38                        let eval = document::eval(
39                            "const text = await dioxus.recv();\n\
40                             await navigator.clipboard.writeText(text);",
41                        );
42                        let _ = eval.send(content);
43                        copied.set(true);
44                        gloo_timers::future::TimeoutFuture::new(2000).await;
45                        copied.set(false);
46                    });
47                }
48            },
49            if copied() {
50                Icon { class: "size-4 text-success", icon: LdCheck }
51                span { class: "text-xs", "Copied!" }
52            } else {
53                Icon { class: "size-4", icon: LdCopy }
54                span { class: "text-xs", "Copy page" }
55            }
56        }
57    }
58}