1use gpui::{App, Styled, hsla};
2
3use crate::ElevationIndex;
4use crate::prelude::*;
5
6fn elevated<E: Styled>(this: E, cx: &App, index: ElevationIndex) -> E {
7 this.bg(cx.theme().colors().elevated_surface_background)
8 .rounded_lg()
9 .border_1()
10 .border_color(cx.theme().colors().border_variant)
11 .shadow(index.shadow(cx))
12}
13
14fn elevated_borderless<E: Styled>(this: E, cx: &mut App, index: ElevationIndex) -> E {
15 this.bg(cx.theme().colors().elevated_surface_background)
16 .rounded_lg()
17 .shadow(index.shadow(cx))
18}
19
20/// Extends [`gpui::Styled`] with Zed-specific styling methods.
21// gate on rust-analyzer so rust-analyzer never needs to expand this macro, it takes up to 10 seconds to expand due to inefficiencies in rust-analyzers proc-macro srv
22#[cfg_attr(
23 all(debug_assertions, not(rust_analyzer)),
24 gpui_macros::derive_inspector_reflection
25)]
26pub trait StyledExt: Styled + Sized {
27 /// Horizontally stacks elements.
28 ///
29 /// Sets `flex()`, `flex_row()`, `items_center()`
30 fn h_flex(self) -> Self {
31 self.flex().flex_row().items_center()
32 }
33
34 /// Vertically stacks elements.
35 ///
36 /// Sets `flex()`, `flex_col()`
37 fn v_flex(self) -> Self {
38 self.flex().flex_col()
39 }
40
41 /// The [`Surface`](ElevationIndex::Surface) elevation level, located above the app background, is the standard level for all elements
42 ///
43 /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
44 ///
45 /// Example Elements: Title Bar, Panel, Tab Bar, Editor
46 fn elevation_1(self, cx: &App) -> Self {
47 elevated(self, cx, ElevationIndex::Surface)
48 }
49
50 /// See [`elevation_1`](Self::elevation_1).
51 ///
52 /// Renders a borderless version [`elevation_1`](Self::elevation_1).
53 fn elevation_1_borderless(self, cx: &mut App) -> Self {
54 elevated_borderless(self, cx, ElevationIndex::Surface)
55 }
56
57 /// Non-Modal Elevated Surfaces appear above the [`Surface`](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.
58 ///
59 /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
60 ///
61 /// Examples: Notifications, Palettes, Detached/Floating Windows, Detached/Floating Panels
62 fn elevation_2(self, cx: &App) -> Self {
63 elevated(self, cx, ElevationIndex::ElevatedSurface)
64 }
65
66 /// See [`elevation_2`](Self::elevation_2).
67 ///
68 /// Renders a borderless version [`elevation_2`](Self::elevation_2).
69 fn elevation_2_borderless(self, cx: &mut App) -> Self {
70 elevated_borderless(self, cx, ElevationIndex::ElevatedSurface)
71 }
72
73 /// 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.
74 ///
75 /// 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.
76 ///
77 /// If the element does not have this behavior, it should be rendered at the [`Elevated Surface`](ElevationIndex::ElevatedSurface) layer.
78 ///
79 /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
80 ///
81 /// Examples: Settings Modal, Channel Management, Wizards/Setup UI, Dialogs
82 fn elevation_3(self, cx: &App) -> Self {
83 elevated(self, cx, ElevationIndex::ModalSurface)
84 }
85
86 /// See [`elevation_3`](Self::elevation_3).
87 ///
88 /// Renders a borderless version [`elevation_3`](Self::elevation_3).
89 fn elevation_3_borderless(self, cx: &mut App) -> Self {
90 elevated_borderless(self, cx, ElevationIndex::ModalSurface)
91 }
92
93 /// The theme's primary border color.
94 fn border_primary(self, cx: &mut App) -> Self {
95 self.border_color(cx.theme().colors().border)
96 }
97
98 /// The theme's secondary or muted border color.
99 fn border_muted(self, cx: &mut App) -> Self {
100 self.border_color(cx.theme().colors().border_variant)
101 }
102
103 /// Sets the background color to red for debugging when building UI.
104 fn debug_bg_red(self) -> Self {
105 self.bg(hsla(0. / 360., 1., 0.5, 1.))
106 }
107
108 /// Sets the background color to green for debugging when building UI.
109 fn debug_bg_green(self) -> Self {
110 self.bg(hsla(120. / 360., 1., 0.5, 1.))
111 }
112
113 /// Sets the background color to blue for debugging when building UI.
114 fn debug_bg_blue(self) -> Self {
115 self.bg(hsla(240. / 360., 1., 0.5, 1.))
116 }
117
118 /// Sets the background color to yellow for debugging when building UI.
119 fn debug_bg_yellow(self) -> Self {
120 self.bg(hsla(60. / 360., 1., 0.5, 1.))
121 }
122
123 /// Sets the background color to cyan for debugging when building UI.
124 fn debug_bg_cyan(self) -> Self {
125 self.bg(hsla(160. / 360., 1., 0.5, 1.))
126 }
127
128 /// Sets the background color to magenta for debugging when building UI.
129 fn debug_bg_magenta(self) -> Self {
130 self.bg(hsla(300. / 360., 1., 0.5, 1.))
131 }
132}
133
134impl<E: Styled> StyledExt for E {}