diff --git a/crates/story/src/clipboard_story.rs b/crates/story/src/clipboard_story.rs new file mode 100644 index 00000000..897d3a3f --- /dev/null +++ b/crates/story/src/clipboard_story.rs @@ -0,0 +1,78 @@ +use gpui::{ + App, AppContext, Context, Entity, Focusable, IntoElement, ParentElement, Render, SharedString, + Styled, Window, +}; + +use gpui_component::{clipboard::Clipboard, label::Label, link::Link, v_flex, ContextModal}; + +use crate::section; + +pub struct ClipboardStory { + focus_handle: gpui::FocusHandle, + masked: bool, +} + +impl super::Story for ClipboardStory { + fn title() -> &'static str { + "Clipboard" + } + + fn description() -> &'static str { + "A button that helps you copy text or other content to your clipboard." + } + + fn new_view(window: &mut Window, cx: &mut App) -> Entity { + Self::view(window, cx) + } +} + +impl ClipboardStory { + pub(crate) fn new(_: &mut Window, cx: &mut App) -> Self { + Self { + focus_handle: cx.focus_handle(), + masked: false, + } + } + + pub fn view(window: &mut Window, cx: &mut App) -> Entity { + cx.new(|cx| Self::new(window, cx)) + } +} +impl Focusable for ClipboardStory { + fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle { + self.focus_handle.clone() + } +} +impl Render for ClipboardStory { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { + v_flex().gap_6().child( + section("Copy to Clipboard") + .max_w_md() + .child( + Clipboard::new("clipboard1") + .content(|_, _| Label::new("Click icon to copy")) + .value_fn({ + let view = cx.entity().clone(); + move |_, cx| { + SharedString::from(format!("masked :{}", view.read(cx).masked)) + } + }) + .on_copied(|value, window, cx| { + window.push_notification(format!("Copied value: {}", value), cx) + }), + ) + .child( + Clipboard::new("clipboard2") + .content(|_, _| { + Link::new("link1") + .href("https://github.com") + .child("GitHub") + }) + .value("https://github.com") + .on_copied(|value, window, cx| { + window.push_notification(format!("Copied value: {}", value), cx) + }), + ), + ) + } +} diff --git a/crates/story/src/label_story.rs b/crates/story/src/label_story.rs index a7a159fc..d8a70f23 100644 --- a/crates/story/src/label_story.rs +++ b/crates/story/src/label_story.rs @@ -1,17 +1,13 @@ use gpui::{ - div, px, rems, App, AppContext, Context, Entity, Focusable, IntoElement, Keystroke, - ParentElement, Render, SharedString, Styled, Window, + div, px, rems, App, AppContext, Context, Entity, Focusable, IntoElement, ParentElement, Render, + Styled, Window, }; use gpui_component::{ button::{Button, ButtonVariant, ButtonVariants as _}, - clipboard::Clipboard, - h_flex, + green_500, h_flex, label::Label, - link::Link, - red_500, - tag::Tag, - v_flex, yellow_500, yellow_800, ColorName, IconName, Kbd, Sizable, StyledExt, + v_flex, IconName, StyledExt, }; use crate::section; @@ -63,22 +59,36 @@ impl Render for LabelStory { .gap_6() .child( section("Label") + .max_w_md() .items_start() - .child( - v_flex() - .w_full() - .gap_4() - .child(Label::new("Text align left")) - .child(Label::new("Text align center").text_center()) - .child(Label::new("Text align right").text_right()), - ) - .child(Label::new("Color Label").text_color(red_500())) - .child( - Label::new("Font Size Label") - .text_size(px(20.)) - .font_semibold() - .line_height(rems(1.8)), - ) + .child(Label::new("This is a label")), + ) + .child( + section("Alignment").max_w_md().child( + v_flex() + .w_full() + .gap_4() + .child(Label::new("Text align left")) + .child(Label::new("Text align center").text_center()) + .child(Label::new("Text align right").text_right()), + ), + ) + .child( + section("Label with color") + .max_w_md() + .child(Label::new("Color Label").text_color(green_500())), + ) + .child( + section("Font Size").max_w_md().child( + Label::new("Font Size Label") + .text_size(px(20.)) + .font_semibold() + .line_height(rems(1.8)), + ), + ) + .child( + section("Multi-line, line-height and text wrap") + .max_w_md() .child( div().w(px(200.)).child( Label::new( @@ -90,84 +100,7 @@ impl Render for LabelStory { ), ) .child( - h_flex() - .gap_3() - .child( - section("Link").child( - h_flex() - .items_start() - .gap_3() - .child( - Link::new("link1") - .href("https://github.com") - .child("GitHub"), - ) - .child( - Link::new("link2") - .href("https://github.com") - .text_color(red_500()) - .text_decoration_color(red_500()) - .child("Red Link"), - ) - .child( - Link::new("link3") - .child( - h_flex() - .gap_1() - .child(IconName::GitHub) - .child("GitHub"), - ) - .on_click(cx.listener(|_, _, _, cx| { - cx.open_url("https://google.com") - })), - ) - .child( - div().w(px(250.)).child( - Link::new("link4") - .child("https://github.com/longbridge/gpui-component") - .href("https://github.com/longbridge/gpui-component"), - ), - ), - ), - ) - .child( - section("Clipboard").child( - h_flex() - .w_full() - .gap_4() - .child( - Clipboard::new("clipboard1") - .content(|_, _| Label::new("Click icon to copy")) - .value_fn({ - let view = cx.entity().clone(); - move |_, cx| { - SharedString::from(format!( - "masked :{}", - view.read(cx).masked - )) - } - }) - .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) - }), - ), - ), - ), - ) - .child( - section("Maksed Label").child( + section("Maksed Label").max_w_md().child( v_flex() .w_full() .gap_4() @@ -190,57 +123,5 @@ impl Render for LabelStory { .child(Label::new("500 USD").text_xl().masked(self.masked)), ), ) - .child( - section("Tag") - .child( - h_flex() - .gap_2() - .child(Tag::primary().small().child("Tag")) - .child(Tag::secondary().small().child("Secondary")) - .child(Tag::outline().small().child("Outline")) - .child(Tag::danger().small().child("danger")) - .child( - Tag::custom(yellow_500(), yellow_800(), yellow_500()) - .small() - .child("Custom"), - ), - ) - .child( - h_flex() - .gap_2() - .child(Tag::primary().child("Tag")) - .child(Tag::secondary().child("Secondary")) - .child(Tag::outline().child("Outline")) - .child(Tag::danger().child("danger")) - .child( - Tag::custom(yellow_500(), yellow_800(), yellow_500()) - .child("Custom"), - ), - ), - ) - .child( - section("Tag::color").child( - v_flex().gap_4().child( - h_flex().gap_2().flex_wrap().children( - ColorName::all() - .into_iter() - .filter(|color| *color != ColorName::Gray) - .map(|color| Tag::color(color).child(color.to_string())), - ), - ), - ), - ) - .child( - section("Kbd").child( - h_flex() - .gap_2() - .child(Kbd::new(Keystroke::parse("cmd-shift-p").unwrap())) - .child(Kbd::new(Keystroke::parse("cmd-ctrl-t").unwrap())) - .child(Kbd::new(Keystroke::parse("escape").unwrap())) - .child(Kbd::new(Keystroke::parse("backspace").unwrap())) - .child(Kbd::new(Keystroke::parse("/").unwrap())) - .child(Kbd::new(Keystroke::parse("enter").unwrap())), - ), - ) } } diff --git a/crates/story/src/lib.rs b/crates/story/src/lib.rs index dfdb484f..57ce1379 100644 --- a/crates/story/src/lib.rs +++ b/crates/story/src/lib.rs @@ -5,6 +5,7 @@ mod badge_story; mod button_story; mod calendar_story; mod checkbox_story; +mod clipboard_story; mod drawer_story; mod dropdown_story; mod form_story; @@ -52,6 +53,7 @@ pub use badge_story::BadgeStory; pub use button_story::ButtonStory; pub use calendar_story::CalendarStory; pub use checkbox_story::CheckboxStory; +pub use clipboard_story::ClipboardStory; pub use drawer_story::DrawerStory; pub use dropdown_story::DropdownStory; pub use form_story::FormStory; diff --git a/crates/story/src/main.rs b/crates/story/src/main.rs index de45b4b5..83d62b8a 100644 --- a/crates/story/src/main.rs +++ b/crates/story/src/main.rs @@ -28,6 +28,7 @@ impl Gallery { StoryContainer::panel::(window, cx), StoryContainer::panel::(window, cx), StoryContainer::panel::(window, cx), + StoryContainer::panel::(window, cx), StoryContainer::panel::(window, cx), StoryContainer::panel::(window, cx), StoryContainer::panel::(window, cx), diff --git a/crates/ui/src/accordion.rs b/crates/ui/src/accordion.rs index fb255ba4..8af31e55 100644 --- a/crates/ui/src/accordion.rs +++ b/crates/ui/src/accordion.rs @@ -217,83 +217,86 @@ impl RenderOnce for AccordionItem { _ => rems(1.0), }; - v_flex() - .bg(cx.theme().accordion) - .overflow_hidden() - .when(self.bordered, |this| { - this.border_1() - .rounded(cx.theme().radius) - .border_color(cx.theme().border) - }) - .text_size(text_size) - .child( - h_flex() - .id(self.index) - .justify_between() - .map(|this| match self.size { - Size::XSmall => this.py_0().px_1p5(), - Size::Small => this.py_0p5().px_2(), - Size::Large => this.py_1p5().px_4(), - _ => this.py_1().px_3(), - }) - .when(self.open, |this| { - this.when(self.bordered, |this| { - this.bg(cx.theme().accordion_active) - .text_color(cx.theme().foreground) - .border_b_1() - .border_color(cx.theme().border) - }) - }) - .when(!self.bordered, |this| { - this.border_b_1().border_color(cx.theme().border) - }) - .child( - h_flex() - .items_center() - .map(|this| match self.size { - Size::XSmall => this.gap_1(), - Size::Small => this.gap_1(), - _ => this.gap_2(), - }) - .when_some(self.icon, |this, icon| { - this.child( - icon.with_size(self.size) - .text_color(cx.theme().muted_foreground), - ) - }) - .child(self.title), - ) - .when(!self.disabled, |this| { - this.hover(|this| this.bg(cx.theme().accordion_hover)) - .child( - Icon::new(if self.open { - IconName::ChevronUp - } else { - IconName::ChevronDown - }) - .xsmall() - .text_color(cx.theme().muted_foreground), - ) - .when_some(self.on_toggle_click, |this, on_toggle_click| { - this.on_click({ - move |_, window, cx| { - on_toggle_click(&!self.open, window, cx); - } - }) - }) - }), - ) - .when(self.open, |this| { - this.child( - div() + div().flex_1().child( + v_flex() + .w_full() + .bg(cx.theme().accordion) + .overflow_hidden() + .when(self.bordered, |this| { + this.border_1() + .rounded(cx.theme().radius) + .border_color(cx.theme().border) + }) + .text_size(text_size) + .child( + h_flex() + .id(self.index) + .justify_between() .map(|this| match self.size { - Size::XSmall => this.p_1p5(), - Size::Small => this.p_2(), - Size::Large => this.p_4(), - _ => this.p_3(), + Size::XSmall => this.py_0().px_1p5(), + Size::Small => this.py_0p5().px_2(), + Size::Large => this.py_1p5().px_4(), + _ => this.py_1().px_3(), }) - .child(self.content), + .when(self.open, |this| { + this.when(self.bordered, |this| { + this.bg(cx.theme().accordion_active) + .text_color(cx.theme().foreground) + .border_b_1() + .border_color(cx.theme().border) + }) + }) + .when(!self.bordered, |this| { + this.border_b_1().border_color(cx.theme().border) + }) + .child( + h_flex() + .items_center() + .map(|this| match self.size { + Size::XSmall => this.gap_1(), + Size::Small => this.gap_1(), + _ => this.gap_2(), + }) + .when_some(self.icon, |this, icon| { + this.child( + icon.with_size(self.size) + .text_color(cx.theme().muted_foreground), + ) + }) + .child(self.title), + ) + .when(!self.disabled, |this| { + this.hover(|this| this.bg(cx.theme().accordion_hover)) + .child( + Icon::new(if self.open { + IconName::ChevronUp + } else { + IconName::ChevronDown + }) + .xsmall() + .text_color(cx.theme().muted_foreground), + ) + .when_some(self.on_toggle_click, |this, on_toggle_click| { + this.on_click({ + move |_, window, cx| { + on_toggle_click(&!self.open, window, cx); + } + }) + }) + }), ) - }) + .when(self.open, |this| { + this.child( + div() + .map(|this| match self.size { + Size::XSmall => this.p_1p5(), + Size::Small => this.p_2(), + Size::Large => this.p_4(), + _ => this.p_3(), + }) + .child(self.content), + ) + }), + ) } }