diff --git a/crates/collab_ui/src/channel_view.rs b/crates/collab_ui/src/channel_view.rs index a4e86a9f2f..46e9d04967 100644 --- a/crates/collab_ui/src/channel_view.rs +++ b/crates/collab_ui/src/channel_view.rs @@ -461,7 +461,7 @@ impl Item for ChannelView { .child( Label::new(channel_name) .color(params.text_color()) - .italic(params.preview), + .when(params.preview, |this| this.italic()), ) .when_some(status, |element, status| { element.child( diff --git a/crates/component/src/component.rs b/crates/component/src/component.rs index e4a2ae7921..35ab8751e5 100644 --- a/crates/component/src/component.rs +++ b/crates/component/src/component.rs @@ -1,7 +1,7 @@ use std::ops::{Deref, DerefMut}; use collections::HashMap; -use gpui::{div, prelude::*, AnyElement, App, IntoElement, RenderOnce, SharedString, Window}; +use gpui::{div, prelude::*, px, AnyElement, App, IntoElement, RenderOnce, SharedString, Window}; use linkme::distributed_slice; use once_cell::sync::Lazy; use parking_lot::RwLock; @@ -201,8 +201,9 @@ impl RenderOnce for ComponentExample { }; base.gap_1() - .text_xs() - .text_color(cx.theme().colors().text_muted) + .p_2() + .text_sm() + .text_color(cx.theme().colors().text) .when(self.grow, |this| this.flex_1()) .child(self.element) .child(self.variant_name) @@ -243,13 +244,34 @@ impl RenderOnce for ComponentExampleGroup { .text_sm() .text_color(cx.theme().colors().text_muted) .when(self.grow, |this| this.w_full().flex_1()) - .when_some(self.title, |this, title| this.gap_4().child(title)) + .when_some(self.title, |this, title| { + this.gap_4().pb_5().child( + div() + .flex() + .items_center() + .gap_3() + .child(div().h_px().w_4().bg(cx.theme().colors().border_variant)) + .child( + div() + .flex_none() + .text_size(px(10.)) + .child(title.to_uppercase()), + ) + .child( + div() + .h_px() + .w_full() + .flex_1() + .bg(cx.theme().colors().border), + ), + ) + }) .child( div() .flex() .items_start() .w_full() - .gap_6() + .gap_8() .children(self.examples) .into_any_element(), ) diff --git a/crates/component_preview/src/component_preview.rs b/crates/component_preview/src/component_preview.rs index 84e00f751c..e8edd392fd 100644 --- a/crates/component_preview/src/component_preview.rs +++ b/crates/component_preview/src/component_preview.rs @@ -41,11 +41,21 @@ impl ComponentPreview { let components = components().all_sorted(); let sorted_components = components.clone(); - v_flex().gap_px().p_1().children( - sorted_components - .into_iter() - .map(|component| self.render_sidebar_entry(&component, _cx)), - ) + v_flex() + .max_w_48() + .gap_px() + .p_1() + .children( + sorted_components + .into_iter() + .map(|component| self.render_sidebar_entry(&component, _cx)), + ) + .child( + Label::new("These will be clickable once the layout is moved to a gpui::List.") + .color(Color::Muted) + .size(LabelSize::XSmall) + .italic(), + ) } fn render_sidebar_entry( @@ -56,7 +66,8 @@ impl ComponentPreview { h_flex() .w_40() .px_1p5() - .py_1() + .py_0p5() + .text_sm() .child(component.name().clone()) } @@ -71,18 +82,19 @@ impl ComponentPreview { let description = component.description(); - v_group() + v_flex() + .border_b_1() + .border_color(cx.theme().colors().border) .w_full() - .gap_4() - .p_8() - .rounded_md() + .gap_3() + .py_6() .child( v_flex() .gap_1() .child( h_flex() .gap_1() - .text_xl() + .text_2xl() .child(div().child(name)) .when_some(scope, |this, scope| { this.child(div().opacity(0.5).child(format!("({})", scope))) @@ -110,7 +122,7 @@ impl ComponentPreview { .size_full() .overflow_y_scroll() .p_4() - .gap_2() + .gap_4() .children( components() .all_previews_sorted() diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index d53b95b007..a643be3b57 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -36,7 +36,7 @@ use std::{ }; use text::{BufferId, Selection}; use theme::{Theme, ThemeSettings}; -use ui::{h_flex, prelude::*, IconDecorationKind, Label}; +use ui::{prelude::*, IconDecorationKind}; use util::{paths::PathExt, ResultExt, TryFutureExt}; use workspace::item::{Dedup, ItemSettings, SerializableItem, TabContentParams}; use workspace::{ @@ -679,8 +679,8 @@ impl Item for Editor { .child( Label::new(self.title(cx).to_string()) .color(label_color) - .italic(params.preview) - .strikethrough(was_deleted), + .when(params.preview, |this| this.italic()) + .when(was_deleted, |this| this.strikethrough()), ) .when_some(description, |this, description| { this.child( diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 0de9859dca..43a498d3de 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -1657,9 +1657,7 @@ impl GitPanel { if !parent_str.is_empty() { this.child( self.entry_label(format!("{}/", parent_str), path_color) - .when(status.is_deleted(), |this| { - this.strikethrough(true) - }), + .when(status.is_deleted(), |this| this.strikethrough()), ) } else { this @@ -1667,7 +1665,7 @@ impl GitPanel { }) .child( self.entry_label(display_name.clone(), label_color) - .when(status.is_deleted(), |this| this.strikethrough(true)), + .when(status.is_deleted(), |this| this.strikethrough()), ), ), ) diff --git a/crates/image_viewer/src/image_viewer.rs b/crates/image_viewer/src/image_viewer.rs index 1782009334..a440ae680e 100644 --- a/crates/image_viewer/src/image_viewer.rs +++ b/crates/image_viewer/src/image_viewer.rs @@ -131,7 +131,7 @@ impl Item for ImageView { Label::new(title) .single_line() .color(label_color) - .italic(params.preview) + .when(params.preview, |this| this.italic()) .into_any_element() } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index ffdab5bcb0..cf83d7b726 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -3994,7 +3994,7 @@ impl ProjectPanel { .when( index == active_index && (is_active || is_marked), - |this| this.underline(true), + |this| this.underline(), ), ); diff --git a/crates/repl/src/notebook/notebook_ui.rs b/crates/repl/src/notebook/notebook_ui.rs index dde11a6aab..9b40b973d8 100644 --- a/crates/repl/src/notebook/notebook_ui.rs +++ b/crates/repl/src/notebook/notebook_ui.rs @@ -738,7 +738,7 @@ impl Item for NotebookEditor { Label::new(title) .single_line() .color(params.text_color()) - .italic(params.preview) + .when(params.preview, |this| this.italic()) .into_any_element() } diff --git a/crates/storybook/src/story_selector.rs b/crates/storybook/src/story_selector.rs index 6f844a65b5..9bae13f7bf 100644 --- a/crates/storybook/src/story_selector.rs +++ b/crates/storybook/src/story_selector.rs @@ -25,7 +25,6 @@ pub enum ComponentStory { Icon, IconButton, Keybinding, - Label, List, ListHeader, ListItem, @@ -61,7 +60,6 @@ impl ComponentStory { Self::Icon => cx.new(|_| ui::IconStory).into(), Self::IconButton => cx.new(|_| ui::IconButtonStory).into(), Self::Keybinding => cx.new(|_| ui::KeybindingStory).into(), - Self::Label => cx.new(|_| ui::LabelStory).into(), Self::List => cx.new(|_| ui::ListStory).into(), Self::ListHeader => cx.new(|_| ui::ListHeaderStory).into(), Self::ListItem => cx.new(|_| ui::ListItemStory).into(), diff --git a/crates/ui/src/components/avatar/avatar.rs b/crates/ui/src/components/avatar/avatar.rs index 82f3ea7ae2..65622f8c3f 100644 --- a/crates/ui/src/components/avatar/avatar.rs +++ b/crates/ui/src/components/avatar/avatar.rs @@ -97,6 +97,7 @@ impl RenderOnce for Avatar { } } +// View this component preview using `workspace: open component-preview` impl ComponentPreview for Avatar { fn preview(_window: &mut Window, _cx: &App) -> AnyElement { let example_avatar = "https://avatars.githubusercontent.com/u/1714999?v=4"; diff --git a/crates/ui/src/components/button/button.rs b/crates/ui/src/components/button/button.rs index 0209fd3d17..58a3d5ae91 100644 --- a/crates/ui/src/components/button/button.rs +++ b/crates/ui/src/components/button/button.rs @@ -456,6 +456,7 @@ impl RenderOnce for Button { } } +// View this component preview using `workspace: open component-preview` impl ComponentPreview for Button { fn preview(_window: &mut Window, _cx: &App) -> AnyElement { v_flex() diff --git a/crates/ui/src/components/content_group.rs b/crates/ui/src/components/content_group.rs index 1a57838c2e..30c115b2a5 100644 --- a/crates/ui/src/components/content_group.rs +++ b/crates/ui/src/components/content_group.rs @@ -88,6 +88,7 @@ impl RenderOnce for ContentGroup { } } +// View this component preview using `workspace: open component-preview` impl ComponentPreview for ContentGroup { fn preview(_window: &mut Window, _cx: &App) -> AnyElement { example_group(vec![ diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index d8043f7400..3288c03fc3 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -490,6 +490,7 @@ impl RenderOnce for IconWithIndicator { } } +// View this component preview using `workspace: open component-preview` impl ComponentPreview for Icon { fn preview(_window: &mut Window, _cx: &App) -> AnyElement { v_flex() diff --git a/crates/ui/src/components/icon/decorated_icon.rs b/crates/ui/src/components/icon/decorated_icon.rs index c973dc6096..641fb82f19 100644 --- a/crates/ui/src/components/icon/decorated_icon.rs +++ b/crates/ui/src/components/icon/decorated_icon.rs @@ -24,6 +24,7 @@ impl RenderOnce for DecoratedIcon { } } +// View this component preview using `workspace: open component-preview` impl ComponentPreview for DecoratedIcon { fn preview(_window: &mut Window, cx: &App) -> AnyElement { let decoration_x = IconDecoration::new( diff --git a/crates/ui/src/components/keybinding_hint.rs b/crates/ui/src/components/keybinding_hint.rs index b10e541ba5..ef355336e6 100644 --- a/crates/ui/src/components/keybinding_hint.rs +++ b/crates/ui/src/components/keybinding_hint.rs @@ -205,6 +205,7 @@ impl RenderOnce for KeybindingHint { } } +// View this component preview using `workspace: open component-preview` impl ComponentPreview for KeybindingHint { fn preview(window: &mut Window, _cx: &App) -> AnyElement { let enter_fallback = gpui::KeyBinding::new("enter", menu::Confirm, None); diff --git a/crates/ui/src/components/label/highlighted_label.rs b/crates/ui/src/components/label/highlighted_label.rs index 14ea7a5cf1..a8be462403 100644 --- a/crates/ui/src/components/label/highlighted_label.rs +++ b/crates/ui/src/components/label/highlighted_label.rs @@ -46,13 +46,13 @@ impl LabelCommon for HighlightedLabel { self } - fn strikethrough(mut self, strikethrough: bool) -> Self { - self.base = self.base.strikethrough(strikethrough); + fn strikethrough(mut self) -> Self { + self.base = self.base.strikethrough(); self } - fn italic(mut self, italic: bool) -> Self { - self.base = self.base.italic(italic); + fn italic(mut self) -> Self { + self.base = self.base.italic(); self } @@ -61,8 +61,8 @@ impl LabelCommon for HighlightedLabel { self } - fn underline(mut self, underline: bool) -> Self { - self.base = self.base.underline(underline); + fn underline(mut self) -> Self { + self.base = self.base.underline(); self } diff --git a/crates/ui/src/components/label/label.rs b/crates/ui/src/components/label/label.rs index 59243998df..b9d7b1f63f 100644 --- a/crates/ui/src/components/label/label.rs +++ b/crates/ui/src/components/label/label.rs @@ -1,8 +1,5 @@ -#![allow(missing_docs)] - -use gpui::{AnyElement, App, StyleRefinement, Window}; - -use crate::{prelude::*, LabelCommon, LabelLike, LabelSize, LineHeightStyle}; +use crate::{prelude::*, LabelLike}; +use gpui::StyleRefinement; /// A struct representing a label element in the UI. /// @@ -56,6 +53,9 @@ impl Label { } } +// nate: If we are going to do this, we might as well just +// impl Styled for Label and not constrain styles + // Style methods. impl Label { fn style(&mut self) -> &mut StyleRefinement { @@ -82,6 +82,15 @@ impl LabelCommon for Label { self } + /// Sets the weight of the label using a [`FontWeight`]. + /// + /// # Examples + /// + /// ``` + /// use ui::prelude::*; + /// + /// let my_label = Label::new("Hello, World!").weight(FontWeight::Bold); + /// ``` fn weight(mut self, weight: gpui::FontWeight) -> Self { self.base = self.base.weight(weight); self @@ -124,8 +133,8 @@ impl LabelCommon for Label { /// /// let my_label = Label::new("Hello, World!").strikethrough(true); /// ``` - fn strikethrough(mut self, strikethrough: bool) -> Self { - self.base = self.base.strikethrough(strikethrough); + fn strikethrough(mut self) -> Self { + self.base = self.base.strikethrough(); self } @@ -138,8 +147,8 @@ impl LabelCommon for Label { /// /// let my_label = Label::new("Hello, World!").italic(true); /// ``` - fn italic(mut self, italic: bool) -> Self { - self.base = self.base.italic(italic); + fn italic(mut self) -> Self { + self.base = self.base.italic(); self } @@ -157,8 +166,8 @@ impl LabelCommon for Label { self } - fn underline(mut self, underline: bool) -> Self { - self.base = self.base.underline(underline); + fn underline(mut self) -> Self { + self.base = self.base.underline(); self } @@ -185,52 +194,57 @@ impl RenderOnce for Label { } } -impl ComponentPreview for Label { - fn preview(_window: &mut Window, _cx: &App) -> AnyElement { - v_flex() - .gap_6() - .children(vec![ - example_group_with_title( - "Sizes", - vec![ - single_example("Default", Label::new("Default Label").into_any_element()), - single_example("Small", Label::new("Small Label").size(LabelSize::Small).into_any_element()), - single_example("Large", Label::new("Large Label").size(LabelSize::Large).into_any_element()), - ], - ), - example_group_with_title( - "Colors", - vec![ - single_example("Default", Label::new("Default Color").into_any_element()), - single_example("Accent", Label::new("Accent Color").color(Color::Accent).into_any_element()), - single_example("Error", Label::new("Error Color").color(Color::Error).into_any_element()), - ], - ), - example_group_with_title( - "Styles", - vec![ - single_example("Default", Label::new("Default Style").into_any_element()), - single_example("Bold", Label::new("Bold Style").weight(gpui::FontWeight::BOLD).into_any_element()), - single_example("Italic", Label::new("Italic Style").italic(true).into_any_element()), - single_example("Strikethrough", Label::new("Strikethrough Style").strikethrough(true).into_any_element()), - single_example("Underline", Label::new("Underline Style").underline(true).into_any_element()), - ], - ), - example_group_with_title( - "Line Height Styles", - vec![ - single_example("Default", Label::new("Default Line Height").into_any_element()), - single_example("UI Label", Label::new("UI Label Line Height").line_height_style(LineHeightStyle::UiLabel).into_any_element()), - ], - ), - example_group_with_title( - "Special Cases", - vec![ - single_example("Single Line", Label::new("Single\nLine\nText").single_line().into_any_element()), - single_example("Text Ellipsis", Label::new("This is a very long text that should be truncated with an ellipsis").text_ellipsis().into_any_element()), - ], - ), - ]) - .into_any_element() +mod label_preview { + use crate::prelude::*; + + // View this component preview using `workspace: open component-preview` + impl ComponentPreview for Label { + fn preview(_window: &mut Window, _cx: &App) -> AnyElement { + v_flex() + .gap_6() + .children(vec![ + example_group_with_title( + "Sizes", + vec![ + single_example("Default", Label::new("Project Explorer").into_any_element()), + single_example("Small", Label::new("File: main.rs").size(LabelSize::Small).into_any_element()), + single_example("Large", Label::new("Welcome to Zed").size(LabelSize::Large).into_any_element()), + ], + ), + example_group_with_title( + "Colors", + vec![ + single_example("Default", Label::new("Status: Ready").into_any_element()), + single_example("Accent", Label::new("New Update Available").color(Color::Accent).into_any_element()), + single_example("Error", Label::new("Build Failed").color(Color::Error).into_any_element()), + ], + ), + example_group_with_title( + "Styles", + vec![ + single_example("Default", Label::new("Normal Text").into_any_element()), + single_example("Bold", Label::new("Important Notice").weight(gpui::FontWeight::BOLD).into_any_element()), + single_example("Italic", Label::new("Code Comment").italic().into_any_element()), + single_example("Strikethrough", Label::new("Deprecated Feature").strikethrough().into_any_element()), + single_example("Underline", Label::new("Clickable Link").underline().into_any_element()), + ], + ), + example_group_with_title( + "Line Height Styles", + vec![ + single_example("Default", Label::new("Multi-line\nText\nExample").into_any_element()), + single_example("UI Label", Label::new("Compact\nUI\nLabel").line_height_style(LineHeightStyle::UiLabel).into_any_element()), + ], + ), + example_group_with_title( + "Special Cases", + vec![ + single_example("Single Line", Label::new("Line 1\nLine 2\nLine 3").single_line().into_any_element()), + single_example("Text Ellipsis", div().max_w_24().child(Label::new("This is a very long file name that should be truncated: very_long_file_name_with_many_words.rs").text_ellipsis()).into_any_element()), + ], + ), + ]) + .into_any_element() + } } } diff --git a/crates/ui/src/components/label/label_like.rs b/crates/ui/src/components/label/label_like.rs index fad24d8699..f5d0eeaf73 100644 --- a/crates/ui/src/components/label/label_like.rs +++ b/crates/ui/src/components/label/label_like.rs @@ -1,23 +1,29 @@ -#![allow(missing_docs)] - -use gpui::{relative, AnyElement, FontWeight, StyleRefinement, Styled, UnderlineStyle}; +use crate::prelude::*; +use gpui::{FontWeight, StyleRefinement, UnderlineStyle}; use settings::Settings; use smallvec::SmallVec; use theme::ThemeSettings; -use crate::prelude::*; - +/// Sets the size of a label #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] pub enum LabelSize { + /// The default size of a label. #[default] Default, + /// The large size of a label. Large, + /// The small size of a label. Small, + /// The extra small size of a label. XSmall, } +/// Sets the line height of a label #[derive(Default, PartialEq, Copy, Clone)] pub enum LineHeightStyle { + /// The default line height style of a label, + /// set by either the UI's default line height, + /// or the developer's default buffer line height. #[default] TextLabel, /// Sets the line height to 1. @@ -39,13 +45,13 @@ pub trait LabelCommon { fn color(self, color: Color) -> Self; /// Sets the strikethrough property of the label. - fn strikethrough(self, strikethrough: bool) -> Self; + fn strikethrough(self) -> Self; /// Sets the italic property of the label. - fn italic(self, italic: bool) -> Self; + fn italic(self) -> Self; /// Sets the underline property of the label - fn underline(self, underline: bool) -> Self; + fn underline(self) -> Self; /// Sets the alpha property of the label, overwriting the alpha value of the color. fn alpha(self, alpha: f32) -> Self; @@ -60,6 +66,11 @@ pub trait LabelCommon { fn buffer_font(self, cx: &App) -> Self; } +/// A label-like element that can be used to create a custom label when +/// prebuilt labels are not sufficient. Use this sparingly, as it is +/// unconstrained and may make the UI feel less consistent. +/// +/// This is also used to build the prebuilt labels. #[derive(IntoElement)] pub struct LabelLike { pub(super) base: Div, @@ -83,6 +94,8 @@ impl Default for LabelLike { } impl LabelLike { + /// Creates a new, fully custom label. + /// Prefer using [`Label`] or [`HighlightedLabel`] where possible. pub fn new() -> Self { Self { base: div(), @@ -133,18 +146,18 @@ impl LabelCommon for LabelLike { self } - fn strikethrough(mut self, strikethrough: bool) -> Self { - self.strikethrough = strikethrough; + fn strikethrough(mut self) -> Self { + self.strikethrough = true; self } - fn italic(mut self, italic: bool) -> Self { - self.italic = italic; + fn italic(mut self) -> Self { + self.italic = true; self } - fn underline(mut self, underline: bool) -> Self { - self.underline = underline; + fn underline(mut self) -> Self { + self.underline = true; self } diff --git a/crates/ui/src/components/stories.rs b/crates/ui/src/components/stories.rs index 9161b14b47..9fa380c703 100644 --- a/crates/ui/src/components/stories.rs +++ b/crates/ui/src/components/stories.rs @@ -8,7 +8,6 @@ mod disclosure; mod icon; mod icon_button; mod keybinding; -mod label; mod list; mod list_header; mod list_item; @@ -23,7 +22,6 @@ pub use disclosure::*; pub use icon::*; pub use icon_button::*; pub use keybinding::*; -pub use label::*; pub use list::*; pub use list_header::*; pub use list_item::*; diff --git a/crates/ui/src/components/stories/label.rs b/crates/ui/src/components/stories/label.rs deleted file mode 100644 index 63b8091b20..0000000000 --- a/crates/ui/src/components/stories/label.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::time::Duration; - -use crate::{prelude::*, HighlightedLabel, Label}; -use gpui::{pulsating_between, Animation, AnimationExt, Render}; -use story::Story; - -pub struct LabelStory; - -impl Render for LabelStory { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { - Story::container() - .child(Story::title_for::