From 5dca5caf9fe06d34b902a13bc99b5b8af0ad279e Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 10 Nov 2023 16:12:14 -0500 Subject: [PATCH 1/4] Add elevation to StyledExt Co-Authored-By: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com> --- crates/ui2/src/components/elevated_surface.rs | 2 +- crates/ui2/src/elevation.md | 4 +- crates/ui2/src/elevation.rs | 38 ++++++++----- crates/ui2/src/styled_ext.rs | 57 ++++++++++++++++++- 4 files changed, 82 insertions(+), 19 deletions(-) diff --git a/crates/ui2/src/components/elevated_surface.rs b/crates/ui2/src/components/elevated_surface.rs index 5d0bbe698c496f6758a61206d3e737fc05f476fa..7a6f11978e4b0dcb6eccda4678c666677c2c2981 100644 --- a/crates/ui2/src/components/elevated_surface.rs +++ b/crates/ui2/src/components/elevated_surface.rs @@ -24,5 +24,5 @@ pub fn elevated_surface(level: ElevationIndex, cx: &mut ViewContext< } pub fn modal(cx: &mut ViewContext) -> Div { - elevated_surface(ElevationIndex::ModalSurfaces, cx) + elevated_surface(ElevationIndex::ModalSurface, cx) } diff --git a/crates/ui2/src/elevation.md b/crates/ui2/src/elevation.md index 08acc6b12e3fb9855aceecaf643df2a63fef723f..3960adb599c56d8babadcaec98723c9f1070039f 100644 --- a/crates/ui2/src/elevation.md +++ b/crates/ui2/src/elevation.md @@ -34,9 +34,9 @@ Material Design 3 has a some great visualizations of elevation that may be helpf The app background constitutes the lowest elevation layer, appearing behind all other surfaces and components. It is predominantly used for the background color of the app. -### UI Surface +### Surface -The UI Surface, located above the app background, is the standard level for all elements +The Surface elevation level, located above the app background, is the standard level for all elements Example Elements: Title Bar, Panel, Tab Bar, Editor diff --git a/crates/ui2/src/elevation.rs b/crates/ui2/src/elevation.rs index 0dd51e33144588a58a25cd8551321f5b6962eced..8a01b9e046a131502c3e4f09025895c361d7dd2f 100644 --- a/crates/ui2/src/elevation.rs +++ b/crates/ui2/src/elevation.rs @@ -11,43 +11,53 @@ pub enum Elevation { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ElevationIndex { - AppBackground, - UISurface, + Background, + Surface, ElevatedSurface, Wash, - ModalSurfaces, + ModalSurface, DraggedElement, } impl ElevationIndex { pub fn z_index(self) -> u32 { match self { - ElevationIndex::AppBackground => 0, - ElevationIndex::UISurface => 100, + ElevationIndex::Background => 0, + ElevationIndex::Surface => 100, ElevationIndex::ElevatedSurface => 200, ElevationIndex::Wash => 300, - ElevationIndex::ModalSurfaces => 400, + ElevationIndex::ModalSurface => 400, ElevationIndex::DraggedElement => 900, } } pub fn shadow(self) -> SmallVec<[BoxShadow; 2]> { match self { - ElevationIndex::AppBackground => smallvec![], + ElevationIndex::Surface => smallvec![], - ElevationIndex::UISurface => smallvec![BoxShadow { + ElevationIndex::ElevatedSurface => smallvec![BoxShadow { color: hsla(0., 0., 0., 0.12), offset: point(px(0.), px(1.)), blur_radius: px(3.), spread_radius: px(0.), }], - _ => smallvec![BoxShadow { - color: hsla(0., 0., 0., 0.32), - offset: point(px(1.), px(3.)), - blur_radius: px(12.), - spread_radius: px(0.), - }], + ElevationIndex::ModalSurface => smallvec![ + BoxShadow { + color: hsla(0., 0., 0., 0.12), + offset: point(px(0.), px(1.)), + blur_radius: px(3.), + spread_radius: px(0.), + }, + BoxShadow { + color: hsla(0., 0., 0., 0.16), + offset: point(px(3.), px(1.)), + blur_radius: px(12.), + spread_radius: px(0.), + }, + ], + + _ => smallvec![], } } } diff --git a/crates/ui2/src/styled_ext.rs b/crates/ui2/src/styled_ext.rs index 543781ef526552df35bb42b16dee09f051cfeb94..06352fa44be5316494cbf4a332deee3f3c7207c5 100644 --- a/crates/ui2/src/styled_ext.rs +++ b/crates/ui2/src/styled_ext.rs @@ -1,6 +1,15 @@ -use gpui::{Div, ElementFocus, ElementInteractivity, Styled}; +use gpui::{Div, ElementFocus, ElementInteractivity, Styled, UniformList, ViewContext}; +use theme2::ActiveTheme; -use crate::UITextSize; +use crate::{ElevationIndex, UITextSize}; + +fn elevated(this: E, cx: &mut ViewContext, index: ElevationIndex) -> E { + this.bg(cx.theme().colors().elevated_surface_background) + .rounded_lg() + .border() + .border_color(cx.theme().colors().border_variant) + .shadow(index.shadow()) +} /// Extends [`Styled`](gpui::Styled) with Zed specific styling methods. pub trait StyledExt: Styled { @@ -64,6 +73,48 @@ pub trait StyledExt: Styled { self.text_size(size) } + + /// The [`Surface`](ui2::ElevationIndex::Surface) elevation level, located above the app background, is the standard level for all elements + /// + /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()` + /// + /// Example Elements: Title Bar, Panel, Tab Bar, Editor + fn elevation_1(self, cx: &mut ViewContext) -> Self + where + Self: Styled + Sized, + { + elevated(self, cx, ElevationIndex::Surface) + } + + /// Non-Modal Elevated Surfaces appear above the [`Surface`](ui2::ElevationIndex::Surface) layer and is used for things that should appear above most UI elements like an editor or panel, but not elements like popovers, context menus, modals, etc. + /// + /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()` + /// + /// Examples: Notifications, Palettes, Detached/Floating Windows, Detached/Floating Panels + fn elevation_2(self, cx: &mut ViewContext) -> Self + where + Self: Styled + Sized, + { + elevated(self, cx, ElevationIndex::ElevatedSurface) + } + + // There is no elevation 3, as the third elevation level is reserved for wash layers. See [`Elevation`](ui2::Elevation). + + /// Modal Surfaces are used for elements that should appear above all other UI elements and are located above the wash layer. This is the maximum elevation at which UI elements can be rendered in their default state. + /// + /// Elements rendered at this layer should have an enforced behavior: Any interaction outside of the modal will either dismiss the modal or prompt an action (Save your progress, etc) then dismiss the modal. + /// + /// If the element does not have this behavior, it should be rendered at the [`Elevated Surface`](ui2::ElevationIndex::ElevatedSurface) layer. + /// + /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()` + /// + /// Examples: Settings Modal, Channel Management, Wizards/Setup UI, Dialogs + fn elevation_4(self, cx: &mut ViewContext) -> Self + where + Self: Styled + Sized, + { + elevated(self, cx, ElevationIndex::ModalSurface) + } } impl StyledExt for Div @@ -72,3 +123,5 @@ where F: ElementFocus, { } + +impl StyledExt for UniformList {} From 3d66ba35a3c7764d85870797fe548572f3c17167 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 10 Nov 2023 16:12:32 -0500 Subject: [PATCH 2/4] Add ui::Divider component Co-Authored-By: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com> --- crates/ui2/src/components.rs | 2 ++ crates/ui2/src/components/divider.rs | 46 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 crates/ui2/src/components/divider.rs diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index 706918c080a4e1795ff4c2fed870e05e53e78955..e7b2d9cf0f02929fef29ec5f41fffc401ad7fe2c 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -3,6 +3,7 @@ mod button; mod checkbox; mod context_menu; mod details; +mod divider; mod elevated_surface; mod facepile; mod icon; @@ -31,6 +32,7 @@ pub use button::*; pub use checkbox::*; pub use context_menu::*; pub use details::*; +pub use divider::*; pub use elevated_surface::*; pub use facepile::*; pub use icon::*; diff --git a/crates/ui2/src/components/divider.rs b/crates/ui2/src/components/divider.rs new file mode 100644 index 0000000000000000000000000000000000000000..5ebfc7a4ff234167ee2fed2f98acd88a4e423047 --- /dev/null +++ b/crates/ui2/src/components/divider.rs @@ -0,0 +1,46 @@ +use crate::prelude::*; + +enum DividerDirection { + Horizontal, + Vertical, +} + +#[derive(Component)] +pub struct Divider { + direction: DividerDirection, + inset: bool, +} + +impl Divider { + pub fn horizontal() -> Self { + Self { + direction: DividerDirection::Horizontal, + inset: false, + } + } + + pub fn vertical() -> Self { + Self { + direction: DividerDirection::Vertical, + inset: false, + } + } + + pub fn inset(mut self) -> Self { + self.inset = true; + self + } + + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + div() + .map(|this| match self.direction { + DividerDirection::Horizontal => { + this.h_px().w_full().when(self.inset, |this| this.mx_1p5()) + } + DividerDirection::Vertical => { + this.w_px().h_full().when(self.inset, |this| this.my_1p5()) + } + }) + .bg(cx.theme().colors().border_variant) + } +} From 6bdb6e486e4964e85bbef1781bfbe8313d596895 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 10 Nov 2023 16:13:25 -0500 Subject: [PATCH 3/4] Refactor command palette, picker and code action styles. Co-Authored-By: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com> --- .../command_palette2/src/command_palette.rs | 6 +++--- crates/editor2/src/editor.rs | 4 ++-- crates/picker2/src/picker2.rs | 21 +++++++------------ 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index abba09519b1685a627fb4701468fa1b644761bc2..0afbe50a03e673742297793e785cb40d9367fcfa 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -8,7 +8,7 @@ use gpui::{ use picker::{Picker, PickerDelegate}; use std::cmp::{self, Reverse}; use theme::ActiveTheme; -use ui::{modal, Label}; +use ui::{modal, v_stack, Label}; use util::{ channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL}, ResultExt, @@ -76,8 +76,8 @@ impl Modal for CommandPalette { impl Render for CommandPalette { type Element = Div; - fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - modal(cx).w_96().child(self.picker.clone()) + fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { + v_stack().w_96().child(self.picker.clone()) } } diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 5bc67a57b61feb5074852bb4a4b567c121a0f968..27ec24b40b2bd5d4aec8a26dfab69f332e7f6419 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -97,7 +97,7 @@ use text::{OffsetUtf16, Rope}; use theme::{ ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings, }; -use ui::IconButton; +use ui::{IconButton, StyledExt}; use util::{post_inc, RangeExt, ResultExt, TryFutureExt}; use workspace::{ item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, @@ -1582,7 +1582,7 @@ impl CodeActionsMenu { .collect() }, ) - .bg(cx.theme().colors().element_background) + .elevation_1(cx) .px_2() .py_1() .with_width_from_item( diff --git a/crates/picker2/src/picker2.rs b/crates/picker2/src/picker2.rs index 9d0019b2dc92a156659aca494987c4160f438e12..4d6e1788498274228f59d7de848d0c86d1c10c0c 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -5,8 +5,7 @@ use gpui::{ WindowContext, }; use std::cmp; -use theme::ActiveTheme; -use ui::v_stack; +use ui::{prelude::*, v_stack, Divider}; pub struct Picker { pub delegate: D, @@ -145,6 +144,7 @@ impl Render for Picker { .id("picker-container") .focusable() .size_full() + .elevation_2(cx) .on_action(Self::select_next) .on_action(Self::select_prev) .on_action(Self::select_first) @@ -153,19 +153,12 @@ impl Render for Picker { .on_action(Self::confirm) .on_action(Self::secondary_confirm) .child( - v_stack().gap_px().child( - v_stack() - .py_0p5() - .px_1() - .child(div().px_2().py_0p5().child(self.editor.clone())), - ), - ) - .child( - div() - .h_px() - .w_full() - .bg(cx.theme().colors().element_background), + v_stack() + .py_0p5() + .px_1() + .child(div().px_2().py_0p5().child(self.editor.clone())), ) + .child(Divider::horizontal()) .child( v_stack() .py_0p5() From 800ad1d3dca82c7a9b8d8f19dbfa99af84bcb84b Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Sun, 12 Nov 2023 22:13:54 -0500 Subject: [PATCH 4/4] Update command palette style --- crates/command_palette2/src/command_palette.rs | 16 +++++++--------- crates/editor2/src/editor.rs | 1 + crates/picker2/src/picker2.rs | 5 ++--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index 0afbe50a03e673742297793e785cb40d9367fcfa..bf9f9fa94b9691405f4ff9f682e6abcf9c6b0b18 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -8,7 +8,7 @@ use gpui::{ use picker::{Picker, PickerDelegate}; use std::cmp::{self, Reverse}; use theme::ActiveTheme; -use ui::{modal, v_stack, Label}; +use ui::{v_stack, Label, StyledExt}; use util::{ channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL}, ResultExt, @@ -305,15 +305,13 @@ impl PickerDelegate for CommandPaletteDelegate { }; div() + .px_1() .text_color(colors.text) - .when(selected, |s| { - s.border_l_10().border_color(colors.terminal_ansi_yellow) - }) - .hover(|style| { - style - .bg(colors.element_active) - .text_color(colors.text_accent) - }) + .text_ui() + .bg(colors.ghost_element_background) + .rounded_md() + .when(selected, |this| this.bg(colors.ghost_element_selected)) + .hover(|this| this.bg(colors.ghost_element_hover)) .child(Label::new(command.name.clone())) } diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 27ec24b40b2bd5d4aec8a26dfab69f332e7f6419..b1f0d2678683fc95bbce9d0feac29896e9d23630 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -1555,6 +1555,7 @@ impl CodeActionsMenu { let colors = cx.theme().colors(); div() .px_2() + .text_ui() .text_color(colors.text) .when(selected, |style| { style diff --git a/crates/picker2/src/picker2.rs b/crates/picker2/src/picker2.rs index 4d6e1788498274228f59d7de848d0c86d1c10c0c..ac1c5f89ea07e058d39ed07173437f3c59cf3c56 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -156,13 +156,12 @@ impl Render for Picker { v_stack() .py_0p5() .px_1() - .child(div().px_2().py_0p5().child(self.editor.clone())), + .child(div().px_1().py_0p5().child(self.editor.clone())), ) .child(Divider::horizontal()) .child( v_stack() - .py_0p5() - .px_1() + .p_1() .grow() .child( uniform_list("candidates", self.delegate.match_count(), {