From 12b5d1b50133850c766d4224c3051cd6055583e2 Mon Sep 17 00:00:00 2001 From: Floyd Wang Date: Mon, 5 Aug 2024 11:35:02 +0800 Subject: [PATCH] Add clipboard (#105) --- assets/icons/copy.svg | 1 + crates/app/src/story_workspace.rs | 2 +- crates/story/src/text_story.rs | 21 ++++++++++ crates/ui/src/clipboard.rs | 70 +++++++++++++++++++++++++++++++ crates/ui/src/icon.rs | 2 + crates/ui/src/lib.rs | 1 + 6 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 assets/icons/copy.svg create mode 100644 crates/ui/src/clipboard.rs diff --git a/assets/icons/copy.svg b/assets/icons/copy.svg new file mode 100644 index 00000000..f3b629c6 --- /dev/null +++ b/assets/icons/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/crates/app/src/story_workspace.rs b/crates/app/src/story_workspace.rs index 3f2d428b..557b200d 100644 --- a/crates/app/src/story_workspace.rs +++ b/crates/app/src/story_workspace.rs @@ -177,7 +177,7 @@ impl StoryWorkspace { StoryContainer::add_pane( "Scrollable", - "A scrollable area with scroll bar", + "A scrollable area with scroll bar.", ScrollableStory::view(cx).into(), workspace.clone(), cx, diff --git a/crates/story/src/text_story.rs b/crates/story/src/text_story.rs index fc80a1a4..1f01ae64 100644 --- a/crates/story/src/text_story.rs +++ b/crates/story/src/text_story.rs @@ -6,6 +6,7 @@ use gpui::{ use ui::{ button::{Button, ButtonStyle}, checkbox::Checkbox, + clipboard::Clipboard, h_flex, label::Label, link::Link, @@ -213,5 +214,25 @@ impl Render for TextStory { ) ), ) + .child( + section("Clipboard", cx).child( + h_flex() + .w_full() + .gap_4() + .items_start() + .child( + Clipboard::new("clipboard1") + .content(|_| Label::new("Click icon to copy")) + .value("Copied!") + .on_copied(|value, _| println!("Copied value: {}", value)), + ) + .child( + Clipboard::new("clipboard2") + .content(|_| Link::new("link1").href("https://github.com").child("GitHub")) + .value("https://github.com") + .on_copied(|value, _| println!("Copied value: {}", value)), + ) + ), + ) } } diff --git a/crates/ui/src/clipboard.rs b/crates/ui/src/clipboard.rs new file mode 100644 index 00000000..a2e278f2 --- /dev/null +++ b/crates/ui/src/clipboard.rs @@ -0,0 +1,70 @@ +use gpui::{ + prelude::FluentBuilder, AnyElement, ClipboardItem, ElementId, IntoElement, ParentElement, + RenderOnce, SharedString, Styled, WindowContext, +}; + +use crate::{button::Button, h_flex, Clickable, IconName}; + +#[derive(IntoElement)] +pub struct Clipboard { + id: ElementId, + value: SharedString, + content_builder: Option AnyElement>>, + copied_callback: Option>, +} + +impl Clipboard { + pub fn new(id: impl Into) -> Self { + Self { + id: id.into(), + value: "".into(), + content_builder: None, + copied_callback: None, + } + } + + pub fn value(mut self, value: impl Into) -> Self { + self.value = value.into(); + self + } + + pub fn content(mut self, element_builder: F) -> Self + where + E: IntoElement, + F: Fn(&mut WindowContext) -> E + 'static, + { + self.content_builder = Some(Box::new(move |cx| element_builder(cx).into_any_element())); + self + } + + pub fn on_copied(mut self, handler: F) -> Self + where + F: Fn(SharedString, &mut WindowContext) + 'static, + { + self.copied_callback = Some(Box::new(handler)); + self + } +} + +impl RenderOnce for Clipboard { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + h_flex() + .gap_0p5() + .when_some(self.content_builder, |this, builder| { + this.child(builder(cx)) + }) + .child( + Button::new(self.id, cx) + .icon(IconName::Copy) + .ghost() + .on_click(move |_, cx| { + cx.stop_propagation(); + cx.write_to_clipboard(ClipboardItem::new(self.value.to_string())); + + if let Some(copied) = &self.copied_callback { + copied(self.value.clone(), cx); + } + }), + ) + } +} diff --git a/crates/ui/src/icon.rs b/crates/ui/src/icon.rs index 645b6699..1968f1d1 100644 --- a/crates/ui/src/icon.rs +++ b/crates/ui/src/icon.rs @@ -45,6 +45,7 @@ pub enum IconName { ThumbsDown, ThumbsUp, Menu, + Copy, } impl IconName { @@ -89,6 +90,7 @@ impl IconName { IconName::ThumbsDown => "icons/thumbs-down.svg", IconName::ThumbsUp => "icons/thumbs-up.svg", IconName::Menu => "icons/menu.svg", + IconName::Copy => "icons/copy.svg", } .into() } diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs index 01c38597..25d7549e 100644 --- a/crates/ui/src/lib.rs +++ b/crates/ui/src/lib.rs @@ -12,6 +12,7 @@ mod svg_img; pub mod button; pub mod checkbox; +pub mod clipboard; pub mod divider; pub mod dropdown; pub mod indicator;