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