Add clipboard (#105)

This commit is contained in:
Floyd Wang 2024-08-05 11:35:02 +08:00
parent 48c452e6f6
commit 12b5d1b501
6 changed files with 96 additions and 1 deletions

1
assets/icons/copy.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>

After

Width:  |  Height:  |  Size: 337 B

View file

@ -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,

View file

@ -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)),
)
),
)
}
}

View file

@ -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<Box<dyn Fn(&mut WindowContext) -> AnyElement>>,
copied_callback: Option<Box<dyn Fn(SharedString, &mut WindowContext)>>,
}
impl Clipboard {
pub fn new(id: impl Into<ElementId>) -> Self {
Self {
id: id.into(),
value: "".into(),
content_builder: None,
copied_callback: None,
}
}
pub fn value(mut self, value: impl Into<SharedString>) -> Self {
self.value = value.into();
self
}
pub fn content<E, F>(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<F>(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);
}
}),
)
}
}

View file

@ -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()
}

View file

@ -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;