Add clipboard (#105)
This commit is contained in:
parent
48c452e6f6
commit
12b5d1b501
6 changed files with 96 additions and 1 deletions
1
assets/icons/copy.svg
Normal file
1
assets/icons/copy.svg
Normal 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 |
|
|
@ -177,7 +177,7 @@ impl StoryWorkspace {
|
||||||
|
|
||||||
StoryContainer::add_pane(
|
StoryContainer::add_pane(
|
||||||
"Scrollable",
|
"Scrollable",
|
||||||
"A scrollable area with scroll bar",
|
"A scrollable area with scroll bar.",
|
||||||
ScrollableStory::view(cx).into(),
|
ScrollableStory::view(cx).into(),
|
||||||
workspace.clone(),
|
workspace.clone(),
|
||||||
cx,
|
cx,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use gpui::{
|
||||||
use ui::{
|
use ui::{
|
||||||
button::{Button, ButtonStyle},
|
button::{Button, ButtonStyle},
|
||||||
checkbox::Checkbox,
|
checkbox::Checkbox,
|
||||||
|
clipboard::Clipboard,
|
||||||
h_flex,
|
h_flex,
|
||||||
label::Label,
|
label::Label,
|
||||||
link::Link,
|
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)),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
70
crates/ui/src/clipboard.rs
Normal file
70
crates/ui/src/clipboard.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,6 +45,7 @@ pub enum IconName {
|
||||||
ThumbsDown,
|
ThumbsDown,
|
||||||
ThumbsUp,
|
ThumbsUp,
|
||||||
Menu,
|
Menu,
|
||||||
|
Copy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IconName {
|
impl IconName {
|
||||||
|
|
@ -89,6 +90,7 @@ impl IconName {
|
||||||
IconName::ThumbsDown => "icons/thumbs-down.svg",
|
IconName::ThumbsDown => "icons/thumbs-down.svg",
|
||||||
IconName::ThumbsUp => "icons/thumbs-up.svg",
|
IconName::ThumbsUp => "icons/thumbs-up.svg",
|
||||||
IconName::Menu => "icons/menu.svg",
|
IconName::Menu => "icons/menu.svg",
|
||||||
|
IconName::Copy => "icons/copy.svg",
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ mod svg_img;
|
||||||
|
|
||||||
pub mod button;
|
pub mod button;
|
||||||
pub mod checkbox;
|
pub mod checkbox;
|
||||||
|
pub mod clipboard;
|
||||||
pub mod divider;
|
pub mod divider;
|
||||||
pub mod dropdown;
|
pub mod dropdown;
|
||||||
pub mod indicator;
|
pub mod indicator;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue