1use std::time::Duration;
4
5use gpui::prelude::*;
6use gpui::{div, px, ClickEvent, ClipboardItem, Context, IntoElement, SharedString, Window};
7
8use crate::devtools::Probed;
9use crate::theme::{theme, ColorName, Size};
10
11pub struct CopyButton {
15 text: SharedString,
16 label: SharedString,
17 copied_label: SharedString,
18 copied: bool,
19}
20
21impl CopyButton {
22 pub fn new(text: impl Into<SharedString>) -> Self {
23 CopyButton {
24 text: text.into(),
25 label: SharedString::new_static("Copy"),
26 copied_label: SharedString::new_static("\u{2713} Copied"),
27 copied: false,
28 }
29 }
30
31 pub fn label(mut self, label: impl Into<SharedString>) -> Self {
33 self.label = label.into();
34 self
35 }
36
37 pub fn text(&self) -> SharedString {
39 self.text.clone()
40 }
41
42 pub fn set_text(&mut self, text: impl Into<SharedString>) {
44 self.text = text.into();
45 }
46
47 fn copy(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
48 cx.write_to_clipboard(ClipboardItem::new_string(self.text.to_string()));
49 self.copied = true;
50 cx.notify();
51
52 cx.spawn(async move |this, cx| {
54 cx.background_executor()
55 .timer(Duration::from_millis(1200))
56 .await;
57 this.update(cx, |this, cx| {
58 this.copied = false;
59 cx.notify();
60 })
61 .ok();
62 })
63 .detach();
64 }
65}
66
67impl Render for CopyButton {
68 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
69 let t = theme(cx);
70 let dark = t.scheme.is_dark();
71 let copied = self.copied;
72
73 let (bg, fg) = if copied {
74 (
75 t.color(ColorName::Teal, if dark { 8 } else { 0 }).hsla(),
76 t.color(ColorName::Teal, if dark { 3 } else { 7 }).hsla(),
77 )
78 } else {
79 (t.surface_hover().hsla(), t.dimmed().hsla())
80 };
81 let hover_bg = t.color(ColorName::Gray, if dark { 6 } else { 2 }).hsla();
82 let label = if copied {
83 self.copied_label.clone()
84 } else {
85 self.label.clone()
86 };
87
88 let mut el = div()
89 .id("guise-copy-button")
90 .flex()
91 .items_center()
92 .h(px(24.0))
93 .px(px(8.0))
94 .rounded(px(t.radius(Size::Sm)))
95 .bg(bg)
96 .text_color(fg)
97 .text_size(px(12.0))
98 .child(label)
99 .on_click(cx.listener(Self::copy));
100 if !copied {
101 el = el.hover(move |s| s.bg(hover_bg));
102 }
103 el.probe("CopyButton")
104 }
105}