MODAL

Conrad Irwin created

Change summary

crates/go_to_line2/src/go_to_line.rs          |  11 +
crates/gpui2/src/styled.rs                    |  19 --
crates/ui2/src/components.rs                  |   2 
crates/ui2/src/components/elevated_surface.rs |  28 +++++
crates/ui2/src/elevation.rs                   |  27 ++++
crates/workspace2/src/modal_layer.rs          |  49 ++++++--
styles/src/style_tree/assistant.ts            | 114 +++++++++++++++++---
styles/src/style_tree/status_bar.ts           |  18 +-
styles/src/themes/rose-pine/rose-pine-dawn.ts |   2 
9 files changed, 206 insertions(+), 64 deletions(-)

Detailed changes

crates/go_to_line2/src/go_to_line.rs 🔗

@@ -1,4 +1,8 @@
-use gpui::{actions, div, px, red, AppContext, Div, Render, Styled, ViewContext, VisualContext};
+use gpui::{
+    actions, div, px, red, AppContext, Div, ParentElement, Render, Styled, ViewContext,
+    VisualContext,
+};
+use ui::modal;
 use workspace::ModalRegistry;
 
 actions!(Toggle);
@@ -27,9 +31,8 @@ pub struct GoToLine;
 impl Render for GoToLine {
     type Element = Div<Self>;
 
-    fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
-        dbg!("rendering GoToLine");
-        div().bg(red()).w(px(100.0)).h(px(100.0))
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        modal(cx).child(div().bg(red()).w(px(100.0)).h(px(100.0)))
     }
 }
 

crates/gpui2/src/styled.rs 🔗

@@ -4,7 +4,7 @@ use crate::{
     SharedString, StyleRefinement, Visibility,
 };
 use crate::{BoxShadow, TextStyleRefinement};
-use smallvec::smallvec;
+use smallvec::{smallvec, SmallVec};
 
 pub trait Styled {
     fn style(&mut self) -> &mut StyleRefinement;
@@ -290,24 +290,11 @@ pub trait Styled {
 
     /// Sets the box shadow of the element.
     /// [Docs](https://tailwindcss.com/docs/box-shadow)
-    fn shadow(mut self) -> Self
+    fn shadow(mut self, shadows: SmallVec<[BoxShadow; 2]>) -> Self
     where
         Self: Sized,
     {
-        self.style().box_shadow = Some(smallvec![
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(1.)),
-                blur_radius: px(3.),
-                spread_radius: px(0.),
-            },
-            BoxShadow {
-                color: hsla(0., 0., 0., 0.1),
-                offset: point(px(0.), px(1.)),
-                blur_radius: px(2.),
-                spread_radius: px(-1.),
-            }
-        ]);
+        self.style().box_shadow = Some(shadows);
         self
     }
 

crates/ui2/src/components.rs 🔗

@@ -3,6 +3,7 @@ mod button;
 mod checkbox;
 mod context_menu;
 mod details;
+mod elevated_surface;
 mod facepile;
 mod icon;
 mod icon_button;
@@ -30,6 +31,7 @@ pub use button::*;
 pub use checkbox::*;
 pub use context_menu::*;
 pub use details::*;
+pub use elevated_surface::*;
 pub use facepile::*;
 pub use icon::*;
 pub use icon_button::*;

crates/ui2/src/components/elevated_surface.rs 🔗

@@ -0,0 +1,28 @@
+use gpui::{div, hsla, point, px, BoxShadow, Div};
+
+use crate::{prelude::*, v_stack};
+
+/// Create an elevated surface.
+///
+/// Must be used inside of a relative parent element
+pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<V>) -> Div<V> {
+    let colors = cx.theme().colors();
+
+    // let shadow = BoxShadow {
+    //     color: hsla(0., 0., 0., 0.1),
+    //     offset: point(px(0.), px(1.)),
+    //     blur_radius: px(3.),
+    //     spread_radius: px(0.),
+    // };
+
+    v_stack()
+        .rounded_lg()
+        .bg(colors.elevated_surface_background)
+        .border()
+        .border_color(colors.border)
+        .shadow(level.shadow())
+}
+
+pub fn modal<V>(cx: &mut ViewContext<V>) -> Div<V> {
+    elevated_surface(ElevationIndex::ModalSurfaces, cx)
+}

crates/ui2/src/elevation.rs 🔗

@@ -1,3 +1,6 @@
+use gpui::{hsla, point, px, BoxShadow};
+use smallvec::{smallvec, SmallVec};
+
 #[doc = include_str!("elevation.md")]
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum Elevation {
@@ -17,8 +20,8 @@ pub enum ElevationIndex {
 }
 
 impl ElevationIndex {
-    pub fn usize(&self) -> usize {
-        match *self {
+    pub fn z_index(self) -> u32 {
+        match self {
             ElevationIndex::AppBackground => 0,
             ElevationIndex::UISurface => 100,
             ElevationIndex::ElevatedSurface => 200,
@@ -27,6 +30,26 @@ impl ElevationIndex {
             ElevationIndex::DraggedElement => 900,
         }
     }
+
+    pub fn shadow(self) -> SmallVec<[BoxShadow; 2]> {
+        match self {
+            ElevationIndex::AppBackground => smallvec![],
+
+            ElevationIndex::UISurface => 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.),
+            }],
+        }
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]

crates/workspace2/src/modal_layer.rs 🔗

@@ -1,8 +1,8 @@
 use std::{any::TypeId, sync::Arc};
 
 use gpui::{
-    div, AnyView, AppContext, DispatchPhase, Div, ParentElement, Render, StatelessInteractive,
-    View, ViewContext,
+    div, AnyView, AppContext, Component, DispatchPhase, Div, ParentElement, Render,
+    StatelessInteractive, Styled, View, ViewContext,
 };
 
 use crate::Workspace;
@@ -69,22 +69,47 @@ impl ModalLayer {
         Self { open_modal: None }
     }
 
-    pub fn render(&self, workspace: &Workspace, cx: &ViewContext<Workspace>) -> Div<Workspace> {
-        let mut div = div();
+    // Workspace
+    // - ModalLayer parent
+    // - - container
+    // - - - modal
+    // - - - content of the modal
+    // - - content of the workspace
 
-        // div, c workspace.toggle_modal()div.on_action()) {
-        //
-        // }
+    // app
+    // workspace
+    // container some layer that contains all modals and is 100% wide and high
+    // modal (this has a shadow, some witdht)
+    // whatever
 
-        // for (type_id, action) in cx.global::<ModalRegistry>().registered_modals.iter() {
-        //     div = div.useful_on_action(*type_id, action)
-        // }
+    pub fn render(&self, workspace: &Workspace, cx: &ViewContext<Workspace>) -> Div<Workspace> {
+        let mut parent = div().relative();
 
         for (_, action) in cx.global::<ModalRegistry>().registered_modals.iter() {
-            div = (action)(div);
+            parent = (action)(parent);
         }
 
-        div.children(self.open_modal.clone())
+        parent.when_some(self.open_modal.as_ref(), |parent, open_modal| {
+            let container1 = div()
+                .absolute()
+                .size_full()
+                .top_0()
+                .left_0()
+                .right_0()
+                .bottom_0();
+
+            // transparent layer
+            let container2 = div()
+                .flex()
+                .h_96()
+                .justify_center()
+                .size_full()
+                .relative()
+                .top_20()
+                .z_index(400);
+
+            parent.child(container1.child(container2.child(open_modal.clone())))
+        })
     }
 }
 

styles/src/style_tree/assistant.ts 🔗

@@ -23,7 +23,7 @@ export default function assistant(): any {
     const theme = useTheme()
 
     const interactive_role = (
-        color: StyleSets
+        color: StyleSets,
     ): Interactive<RoleCycleButton> => {
         return interactive({
             base: {
@@ -94,7 +94,7 @@ export default function assistant(): any {
                     margin: { left: 8, right: 18 },
                     color: foreground(theme.highest, "positive"),
                     width: 12,
-                }
+                },
             },
             retrieve_context: toggleable({
                 base: interactive({
@@ -106,7 +106,8 @@ export default function assistant(): any {
                         background: background(theme.highest, "on"),
                         corner_radius: 2,
                         border: {
-                            width: 1., color: background(theme.highest, "on")
+                            width: 1,
+                            color: background(theme.highest, "on"),
                         },
                         margin: { left: 2 },
                         padding: {
@@ -118,17 +119,45 @@ export default function assistant(): any {
                     },
                     state: {
                         hovered: {
-                            ...text(theme.highest, "mono", "variant", "hovered"),
-                            background: background(theme.highest, "on", "hovered"),
+                            ...text(
+                                theme.highest,
+                                "mono",
+                                "variant",
+                                "hovered",
+                            ),
+                            background: background(
+                                theme.highest,
+                                "on",
+                                "hovered",
+                            ),
                             border: {
-                                width: 1., color: background(theme.highest, "on", "hovered")
+                                width: 1,
+                                color: background(
+                                    theme.highest,
+                                    "on",
+                                    "hovered",
+                                ),
                             },
                         },
                         clicked: {
-                            ...text(theme.highest, "mono", "variant", "pressed"),
-                            background: background(theme.highest, "on", "pressed"),
+                            ...text(
+                                theme.highest,
+                                "mono",
+                                "variant",
+                                "pressed",
+                            ),
+                            background: background(
+                                theme.highest,
+                                "on",
+                                "pressed",
+                            ),
                             border: {
-                                width: 1., color: background(theme.highest, "on", "pressed")
+                                width: 1,
+                                color: background(
+                                    theme.highest,
+                                    "on",
+                                    "pressed",
+                                ),
                             },
                         },
                     },
@@ -143,11 +172,19 @@ export default function assistant(): any {
                             border: border(theme.highest, "accent"),
                         },
                         hovered: {
-                            background: background(theme.highest, "accent", "hovered"),
+                            background: background(
+                                theme.highest,
+                                "accent",
+                                "hovered",
+                            ),
                             border: border(theme.highest, "accent", "hovered"),
                         },
                         clicked: {
-                            background: background(theme.highest, "accent", "pressed"),
+                            background: background(
+                                theme.highest,
+                                "accent",
+                                "pressed",
+                            ),
                             border: border(theme.highest, "accent", "pressed"),
                         },
                     },
@@ -163,7 +200,8 @@ export default function assistant(): any {
                         background: background(theme.highest, "on"),
                         corner_radius: 2,
                         border: {
-                            width: 1., color: background(theme.highest, "on")
+                            width: 1,
+                            color: background(theme.highest, "on"),
                         },
                         padding: {
                             left: 4,
@@ -174,17 +212,45 @@ export default function assistant(): any {
                     },
                     state: {
                         hovered: {
-                            ...text(theme.highest, "mono", "variant", "hovered"),
-                            background: background(theme.highest, "on", "hovered"),
+                            ...text(
+                                theme.highest,
+                                "mono",
+                                "variant",
+                                "hovered",
+                            ),
+                            background: background(
+                                theme.highest,
+                                "on",
+                                "hovered",
+                            ),
                             border: {
-                                width: 1., color: background(theme.highest, "on", "hovered")
+                                width: 1,
+                                color: background(
+                                    theme.highest,
+                                    "on",
+                                    "hovered",
+                                ),
                             },
                         },
                         clicked: {
-                            ...text(theme.highest, "mono", "variant", "pressed"),
-                            background: background(theme.highest, "on", "pressed"),
+                            ...text(
+                                theme.highest,
+                                "mono",
+                                "variant",
+                                "pressed",
+                            ),
+                            background: background(
+                                theme.highest,
+                                "on",
+                                "pressed",
+                            ),
                             border: {
-                                width: 1., color: background(theme.highest, "on", "pressed")
+                                width: 1,
+                                color: background(
+                                    theme.highest,
+                                    "on",
+                                    "pressed",
+                                ),
                             },
                         },
                     },
@@ -199,11 +265,19 @@ export default function assistant(): any {
                             border: border(theme.highest, "accent"),
                         },
                         hovered: {
-                            background: background(theme.highest, "accent", "hovered"),
+                            background: background(
+                                theme.highest,
+                                "accent",
+                                "hovered",
+                            ),
                             border: border(theme.highest, "accent", "hovered"),
                         },
                         clicked: {
-                            background: background(theme.highest, "accent", "pressed"),
+                            background: background(
+                                theme.highest,
+                                "accent",
+                                "pressed",
+                            ),
                             border: border(theme.highest, "accent", "pressed"),
                         },
                     },

styles/src/style_tree/status_bar.ts 🔗

@@ -78,33 +78,33 @@ export default function status_bar(): any {
                     padding: { top: 2, bottom: 2, left: 6, right: 6 },
                 },
                 container_warning: diagnostic_status_container,
-                container_error: diagnostic_status_container
+                container_error: diagnostic_status_container,
             },
             state: {
                 hovered: {
                     icon_color_ok: foreground(layer, "on"),
                     container_ok: {
-                        background: background(layer, "hovered")
+                        background: background(layer, "hovered"),
                     },
                     container_warning: {
-                        background: background(layer, "hovered")
+                        background: background(layer, "hovered"),
                     },
                     container_error: {
-                        background: background(layer, "hovered")
+                        background: background(layer, "hovered"),
                     },
                 },
                 clicked: {
                     icon_color_ok: foreground(layer, "on"),
                     container_ok: {
-                        background: background(layer, "pressed")
+                        background: background(layer, "pressed"),
                     },
                     container_warning: {
-                        background: background(layer, "pressed")
+                        background: background(layer, "pressed"),
                     },
                     container_error: {
-                        background: background(layer, "pressed")
-                    }
-                }
+                        background: background(layer, "pressed"),
+                    },
+                },
             },
         }),
         panel_buttons: {

styles/src/themes/rose-pine/rose-pine-dawn.ts 🔗

@@ -31,7 +31,7 @@ export const theme: ThemeConfig = {
                     color.muted,
                     color.subtle,
                     color.text,
-                ].reverse()
+                ].reverse(),
             )
             .domain([0, 0.35, 0.45, 0.65, 0.7, 0.8, 0.9, 1]),
         red: color_ramp(chroma(color.love)),