Merge branch 'gpui2' into zed2

Marshall Bowers created

Change summary

crates/gpui2/src/styled.rs                   | 34 ++++++++++++++++++++++
crates/storybook2/src/story_selector.rs      |  5 +++
crates/storybook2/src/storybook2.rs          | 31 +++++++++++---------
crates/ui2/src/components/assistant_panel.rs | 12 +++---
crates/ui2/src/components/buffer_search.rs   |  2 
crates/ui2/src/components/chat_panel.rs      |  4 +-
crates/ui2/src/components/editor_pane.rs     |  6 +-
crates/ui2/src/components/icon_button.rs     |  7 ++-
crates/ui2/src/components/list.rs            |  8 +++-
crates/ui2/src/components/modal.rs           |  2 
crates/ui2/src/components/multi_buffer.rs    |  2 
crates/ui2/src/components/status_bar.rs      | 16 +++++-----
crates/ui2/src/components/tab_bar.rs         |  8 ++--
crates/ui2/src/components/terminal.rs        |  4 +-
crates/ui2/src/components/title_bar.rs       | 12 +++---
crates/ui2/src/components/toolbar.rs         |  6 +-
crates/ui2/src/components/workspace.rs       |  2 
crates/ui2/src/elements/details.rs           | 12 +++++++
crates/ui2/src/story.rs                      |  2 
19 files changed, 115 insertions(+), 60 deletions(-)

Detailed changes

crates/gpui2/src/styled.rs 🔗

@@ -137,6 +137,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to align flex items to the start of the container's cross axis.
+    /// [Docs](https://tailwindcss.com/docs/align-items#start)
     fn items_start(mut self) -> Self
     where
         Self: Sized,
@@ -145,6 +147,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to align flex items to the end of the container's cross axis.
+    /// [Docs](https://tailwindcss.com/docs/align-items#end)
     fn items_end(mut self) -> Self
     where
         Self: Sized,
@@ -153,6 +157,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to align flex items along the center of the container's cross axis.
+    /// [Docs](https://tailwindcss.com/docs/align-items#center)
     fn items_center(mut self) -> Self
     where
         Self: Sized,
@@ -161,6 +167,9 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to justify flex items along the container's main axis
+    /// such that there is an equal amount of space between each item.
+    /// [Docs](https://tailwindcss.com/docs/justify-content#space-between)
     fn justify_between(mut self) -> Self
     where
         Self: Sized,
@@ -169,6 +178,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to justify flex items along the center of the container's main axis.
+    /// [Docs](https://tailwindcss.com/docs/justify-content#center)
     fn justify_center(mut self) -> Self
     where
         Self: Sized,
@@ -177,6 +188,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to justify flex items against the start of the container's main axis.
+    /// [Docs](https://tailwindcss.com/docs/justify-content#start)
     fn justify_start(mut self) -> Self
     where
         Self: Sized,
@@ -185,6 +198,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to justify flex items against the end of the container's main axis.
+    /// [Docs](https://tailwindcss.com/docs/justify-content#end)
     fn justify_end(mut self) -> Self
     where
         Self: Sized,
@@ -193,6 +208,9 @@ pub trait Styled {
         self
     }
 
+    /// Sets the element to justify items along the container's main axis such
+    /// that there is an equal amount of space on each side of each item.
+    /// [Docs](https://tailwindcss.com/docs/justify-content#space-around)
     fn justify_around(mut self) -> Self
     where
         Self: Sized,
@@ -201,6 +219,7 @@ pub trait Styled {
         self
     }
 
+    /// Sets the background color of the element.
     fn bg<F>(mut self, fill: F) -> Self
     where
         F: Into<Fill>,
@@ -210,6 +229,7 @@ pub trait Styled {
         self
     }
 
+    /// Sets the border color of the element.
     fn border_color<C>(mut self, border_color: C) -> Self
     where
         C: Into<Hsla>,
@@ -219,6 +239,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the box shadow of the element.
+    /// [Docs](https://tailwindcss.com/docs/box-shadow)
     fn shadow(mut self) -> Self
     where
         Self: Sized,
@@ -240,6 +262,8 @@ pub trait Styled {
         self
     }
 
+    /// Clears the box shadow of the element.
+    /// [Docs](https://tailwindcss.com/docs/box-shadow)
     fn shadow_none(mut self) -> Self
     where
         Self: Sized,
@@ -248,6 +272,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the box shadow of the element.
+    /// [Docs](https://tailwindcss.com/docs/box-shadow)
     fn shadow_sm(mut self) -> Self
     where
         Self: Sized,
@@ -261,6 +287,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the box shadow of the element.
+    /// [Docs](https://tailwindcss.com/docs/box-shadow)
     fn shadow_md(mut self) -> Self
     where
         Self: Sized,
@@ -282,6 +310,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the box shadow of the element.
+    /// [Docs](https://tailwindcss.com/docs/box-shadow)
     fn shadow_lg(mut self) -> Self
     where
         Self: Sized,
@@ -303,6 +333,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the box shadow of the element.
+    /// [Docs](https://tailwindcss.com/docs/box-shadow)
     fn shadow_xl(mut self) -> Self
     where
         Self: Sized,
@@ -324,6 +356,8 @@ pub trait Styled {
         self
     }
 
+    /// Sets the box shadow of the element.
+    /// [Docs](https://tailwindcss.com/docs/box-shadow)
     fn shadow_2xl(mut self) -> Self
     where
         Self: Sized,

crates/storybook2/src/story_selector.rs 🔗

@@ -71,6 +71,7 @@ pub enum ComponentStory {
     Keybinding,
     LanguageSelector,
     MultiBuffer,
+    NotificationsPanel,
     Palette,
     Panel,
     ProjectPanel,
@@ -132,6 +133,10 @@ impl ComponentStory {
                 ui::MultiBufferStory::new().into_any()
             })
             .into_any(),
+            Self::NotificationsPanel => view(cx.entity(|cx| ()), |_, _| {
+                ui::NotificationsPanelStory::new().into_any()
+            })
+            .into_any(),
             Self::Palette => view(cx.entity(|cx| ()), |_, _| {
                 ui::PaletteStory::new().into_any()
             })

crates/storybook2/src/storybook2.rs 🔗

@@ -10,8 +10,8 @@ use std::sync::Arc;
 
 use clap::Parser;
 use gpui2::{
-    div, px, size, view, AnyView, Bounds, Context, Element, ViewContext, WindowBounds,
-    WindowOptions,
+    div, px, size, view, AnyView, AppContext, AssetSource, Bounds, Context, Element, ViewContext,
+    WindowBounds, WindowOptions,
 };
 use log::LevelFilter;
 use simplelog::SimpleLogger;
@@ -53,6 +53,8 @@ fn main() {
 
     let asset_source = Arc::new(Assets);
     gpui2::App::production(asset_source).run(move |cx| {
+        load_embedded_fonts(cx).unwrap();
+
         let selector =
             story_selector.unwrap_or(StorySelector::Component(ComponentStory::Workspace));
 
@@ -101,15 +103,16 @@ impl StoryWrapper {
     }
 }
 
-// fn load_embedded_fonts(platform: &dyn gpui2::Platform) {
-//     let font_paths = Assets.list("fonts");
-//     let mut embedded_fonts = Vec::new();
-//     for font_path in &font_paths {
-//         if font_path.ends_with(".ttf") {
-//             let font_path = &*font_path;
-//             let font_bytes = Assets.load(font_path).unwrap().to_vec();
-//             embedded_fonts.push(Arc::from(font_bytes));
-//         }
-//     }
-//     platform.fonts().add_fonts(&embedded_fonts).unwrap();
-// }
+fn load_embedded_fonts(cx: &AppContext) -> gpui2::Result<()> {
+    let font_paths = Assets.list(&"fonts".into())?;
+    let mut embedded_fonts = Vec::new();
+    for font_path in &font_paths {
+        if font_path.ends_with(".ttf") {
+            let font_path = &*font_path;
+            let font_bytes = Assets.load(font_path)?.to_vec();
+            embedded_fonts.push(Arc::from(font_bytes));
+        }
+    }
+
+    cx.text_system().add_fonts(&embedded_fonts)
+}

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

@@ -45,7 +45,7 @@ impl<S: 'static + Send + Sync> AssistantPanel<S> {
                         .child(
                             div()
                                 .flex()
-                                .child(IconButton::new(Icon::Menu))
+                                .child(IconButton::new("menu", Icon::Menu))
                                 .child(Label::new("New Conversation")),
                         )
                         .child(
@@ -53,11 +53,11 @@ impl<S: 'static + Send + Sync> AssistantPanel<S> {
                                 .flex()
                                 .items_center()
                                 .gap_px()
-                                .child(IconButton::new(Icon::SplitMessage))
-                                .child(IconButton::new(Icon::Quote))
-                                .child(IconButton::new(Icon::MagicWand))
-                                .child(IconButton::new(Icon::Plus))
-                                .child(IconButton::new(Icon::Maximize)),
+                                .child(IconButton::new("split_message", Icon::SplitMessage))
+                                .child(IconButton::new("quote", Icon::Quote))
+                                .child(IconButton::new("magic_wand", Icon::MagicWand))
+                                .child(IconButton::new("plus", Icon::Plus))
+                                .child(IconButton::new("maximize", Icon::Maximize)),
                         ),
                 )
                 // Chat Body

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

@@ -32,7 +32,7 @@ impl BufferSearch {
 
         h_stack().bg(color.toolbar).p_2().child(
             h_stack().child(Input::new("Search")).child(
-                IconButton::<Self>::new(Icon::Replace)
+                IconButton::<Self>::new("replace", Icon::Replace)
                     .when(self.is_replace_open, |this| this.color(IconColor::Accent))
                     .on_click(|buffer_search, cx| {
                         buffer_search.toggle_replace(cx);

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

@@ -45,8 +45,8 @@ impl<S: 'static + Send + Sync> ChatPanel<S> {
                             .flex()
                             .items_center()
                             .gap_px()
-                            .child(IconButton::new(Icon::File))
-                            .child(IconButton::new(Icon::AudioOn)),
+                            .child(IconButton::new("file", Icon::File))
+                            .child(IconButton::new("audio_on", Icon::AudioOn)),
                     ),
             )
             .child(

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

@@ -61,15 +61,15 @@ impl EditorPane {
                 Toolbar::new()
                     .left_item(Breadcrumb::new(self.path.clone(), self.symbols.clone()))
                     .right_items(vec![
-                        IconButton::new(Icon::InlayHint),
-                        IconButton::<Self>::new(Icon::MagnifyingGlass)
+                        IconButton::new("toggle_inlay_hints", Icon::InlayHint),
+                        IconButton::<Self>::new("buffer_search", Icon::MagnifyingGlass)
                             .when(self.is_buffer_search_open, |this| {
                                 this.color(IconColor::Accent)
                             })
                             .on_click(|editor, cx| {
                                 editor.toggle_buffer_search(cx);
                             }),
-                        IconButton::new(Icon::MagicWand),
+                        IconButton::new("inline_assist", Icon::MagicWand),
                     ]),
             )
             .children(Some(self.buffer_search.clone()).filter(|_| self.is_buffer_search_open))

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

@@ -19,6 +19,7 @@ impl<S: 'static + Send + Sync> Default for IconButtonHandlers<S> {
 #[derive(Element)]
 pub struct IconButton<S: 'static + Send + Sync> {
     state_type: PhantomData<S>,
+    id: ElementId,
     icon: Icon,
     color: IconColor,
     variant: ButtonVariant,
@@ -27,9 +28,10 @@ pub struct IconButton<S: 'static + Send + Sync> {
 }
 
 impl<S: 'static + Send + Sync> IconButton<S> {
-    pub fn new(icon: Icon) -> Self {
+    pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self {
         Self {
             state_type: PhantomData,
+            id: id.into(),
             icon,
             color: IconColor::default(),
             variant: ButtonVariant::default(),
@@ -88,8 +90,7 @@ impl<S: 'static + Send + Sync> IconButton<S> {
         };
 
         let mut button = h_stack()
-            // TODO: We probably need a more robust method for differentiating `IconButton`s from one another.
-            .id(SharedString::from(format!("{:?}", self.icon)))
+            .id(self.id.clone())
             .justify_center()
             .rounded_md()
             .py(ui_size(cx, 0.25))

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

@@ -511,9 +511,11 @@ impl<S: 'static + Send + Sync> ListDetailsEntry<S> {
             .w_full()
             .line_height(relative(1.2))
             .child(Label::new(self.label.clone()).color(label_color))
-            .when(self.meta.is_some(), |this| {
-                this.child(Label::new(self.meta.clone().unwrap()).color(LabelColor::Muted))
-            })
+            .children(
+                self.meta
+                    .take()
+                    .map(|meta| Label::new(meta).color(LabelColor::Muted)),
+            )
             .child(
                 h_stack()
                     .gap_1()

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

@@ -60,7 +60,7 @@ impl<S: 'static + Send + Sync> Modal<S> {
                     .border_b()
                     .border_color(color.border)
                     .child(div().children(self.title.clone().map(|t| Label::new(t))))
-                    .child(IconButton::new(Icon::Close)),
+                    .child(IconButton::new("close", Icon::Close)),
             )
             .child(v_stack().p_1().children(self.children.drain(..)))
             .when(

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

@@ -34,7 +34,7 @@ impl<S: 'static + Send + Sync + Clone> MultiBuffer<S> {
                             .p_4()
                             .bg(color.editor_subheader)
                             .child(Label::new("main.rs"))
-                            .child(IconButton::new(Icon::ArrowUpRight)),
+                            .child(IconButton::new("arrow_up_right", Icon::ArrowUpRight)),
                     )
                     .child(buffer)
             }))

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

@@ -113,7 +113,7 @@ impl StatusBar {
             .items_center()
             .gap_1()
             .child(
-                IconButton::<Workspace>::new(Icon::FileTree)
+                IconButton::<Workspace>::new("project_panel", Icon::FileTree)
                     .when(workspace.is_project_panel_open(), |this| {
                         this.color(IconColor::Accent)
                     })
@@ -122,7 +122,7 @@ impl StatusBar {
                     }),
             )
             .child(
-                IconButton::<Workspace>::new(Icon::Hash)
+                IconButton::<Workspace>::new("collab_panel", Icon::Hash)
                     .when(workspace.is_collab_panel_open(), |this| {
                         this.color(IconColor::Accent)
                     })
@@ -131,7 +131,7 @@ impl StatusBar {
                     }),
             )
             .child(ToolDivider::new())
-            .child(IconButton::new(Icon::XCircle))
+            .child(IconButton::new("diagnostics", Icon::XCircle))
     }
 
     fn right_tools(
@@ -164,11 +164,11 @@ impl StatusBar {
                     .items_center()
                     .gap_1()
                     .child(
-                        IconButton::new(Icon::Copilot)
+                        IconButton::new("copilot", Icon::Copilot)
                             .on_click(|_, _| println!("Copilot clicked.")),
                     )
                     .child(
-                        IconButton::new(Icon::Envelope)
+                        IconButton::new("envelope", Icon::Envelope)
                             .on_click(|_, _| println!("Send Feedback clicked.")),
                     ),
             )
@@ -179,7 +179,7 @@ impl StatusBar {
                     .items_center()
                     .gap_1()
                     .child(
-                        IconButton::<Workspace>::new(Icon::Terminal)
+                        IconButton::<Workspace>::new("terminal", Icon::Terminal)
                             .when(workspace.is_terminal_open(), |this| {
                                 this.color(IconColor::Accent)
                             })
@@ -188,7 +188,7 @@ impl StatusBar {
                             }),
                     )
                     .child(
-                        IconButton::<Workspace>::new(Icon::MessageBubbles)
+                        IconButton::<Workspace>::new("chat_panel", Icon::MessageBubbles)
                             .when(workspace.is_chat_panel_open(), |this| {
                                 this.color(IconColor::Accent)
                             })
@@ -197,7 +197,7 @@ impl StatusBar {
                             }),
                     )
                     .child(
-                        IconButton::<Workspace>::new(Icon::Ai)
+                        IconButton::<Workspace>::new("assistant_panel", Icon::Ai)
                             .when(workspace.is_assistant_panel_open(), |this| {
                                 this.color(IconColor::Accent)
                             })

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

@@ -51,11 +51,11 @@ impl<S: 'static + Send + Sync + Clone> TabBar<S> {
                             .items_center()
                             .gap_px()
                             .child(
-                                IconButton::new(Icon::ArrowLeft)
+                                IconButton::new("arrow_left", Icon::ArrowLeft)
                                     .state(InteractionState::Enabled.if_enabled(can_navigate_back)),
                             )
                             .child(
-                                IconButton::new(Icon::ArrowRight).state(
+                                IconButton::new("arrow_right", Icon::ArrowRight).state(
                                     InteractionState::Enabled.if_enabled(can_navigate_forward),
                                 ),
                             ),
@@ -83,8 +83,8 @@ impl<S: 'static + Send + Sync + Clone> TabBar<S> {
                             .flex()
                             .items_center()
                             .gap_px()
-                            .child(IconButton::new(Icon::Plus))
-                            .child(IconButton::new(Icon::Split)),
+                            .child(IconButton::new("plus", Icon::Plus))
+                            .child(IconButton::new("split", Icon::Split)),
                     ),
             )
     }

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

@@ -40,11 +40,11 @@ impl<S: 'static + Send + Sync + Clone> Terminal<S> {
                                 .items_center()
                                 .gap_px()
                                 .child(
-                                    IconButton::new(Icon::ArrowLeft).state(
+                                    IconButton::new("arrow_left", Icon::ArrowLeft).state(
                                         InteractionState::Enabled.if_enabled(can_navigate_back),
                                     ),
                                 )
-                                .child(IconButton::new(Icon::ArrowRight).state(
+                                .child(IconButton::new("arrow_right", Icon::ArrowRight).state(
                                     InteractionState::Enabled.if_enabled(can_navigate_forward),
                                 )),
                         ),

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

@@ -128,7 +128,7 @@ impl TitleBar {
                             .child(Button::new("nate/gpui2-ui-components")),
                     )
                     .children(player_list.map(|p| PlayerStack::new(p)))
-                    .child(IconButton::new(Icon::Plus)),
+                    .child(IconButton::new("plus", Icon::Plus)),
             )
             .child(
                 div()
@@ -140,8 +140,8 @@ impl TitleBar {
                             .flex()
                             .items_center()
                             .gap_1()
-                            .child(IconButton::new(Icon::FolderX))
-                            .child(IconButton::new(Icon::Exit)),
+                            .child(IconButton::new("folder_x", Icon::FolderX))
+                            .child(IconButton::new("exit", Icon::Exit)),
                     )
                     .child(ToolDivider::new())
                     .child(
@@ -151,17 +151,17 @@ impl TitleBar {
                             .items_center()
                             .gap_1()
                             .child(
-                                IconButton::<TitleBar>::new(Icon::Mic)
+                                IconButton::<TitleBar>::new("toggle_mic_status", Icon::Mic)
                                     .when(self.is_mic_muted(), |this| this.color(IconColor::Error))
                                     .on_click(|title_bar, cx| title_bar.toggle_mic_status(cx)),
                             )
                             .child(
-                                IconButton::<TitleBar>::new(Icon::AudioOn)
+                                IconButton::<TitleBar>::new("toggle_deafened", Icon::AudioOn)
                                     .when(self.is_deafened, |this| this.color(IconColor::Error))
                                     .on_click(|title_bar, cx| title_bar.toggle_deafened(cx)),
                             )
                             .child(
-                                IconButton::<TitleBar>::new(Icon::Screen)
+                                IconButton::<TitleBar>::new("toggle_screen_share", Icon::Screen)
                                     .when(
                                         self.screen_share_status == ScreenShareStatus::Shared,
                                         |this| this.color(IconColor::Accent),

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

@@ -130,9 +130,9 @@ mod stories {
                             ],
                         ))
                         .right_items(vec![
-                            IconButton::new(Icon::InlayHint),
-                            IconButton::new(Icon::MagnifyingGlass),
-                            IconButton::new(Icon::MagicWand),
+                            IconButton::new("toggle_inlay_hints", Icon::InlayHint),
+                            IconButton::new("buffer_search", Icon::MagnifyingGlass),
+                            IconButton::new("inline_assist", Icon::MagicWand),
                         ]),
                 )
         }

crates/ui2/src/elements/details.rs 🔗

@@ -38,6 +38,7 @@ impl<S: 'static + Send + Sync> Details<S> {
             .gap_0p5()
             .text_xs()
             .text_color(color.text)
+            .size_full()
             .child(self.text)
             .children(self.meta.map(|m| m))
             .children(self.actions.take().map(|a| a))
@@ -49,7 +50,7 @@ pub use stories::*;
 
 #[cfg(feature = "stories")]
 mod stories {
-    use crate::Story;
+    use crate::{Button, Story};
 
     use super::*;
 
@@ -79,6 +80,15 @@ mod stories {
                     Details::new("The quick brown fox jumps over the lazy dog")
                         .meta_text("Sphinx of black quartz, judge my vow."),
                 )
+                .child(Story::label(cx, "With meta and actions"))
+                .child(
+                    Details::new("The quick brown fox jumps over the lazy dog")
+                        .meta_text("Sphinx of black quartz, judge my vow.")
+                        .actions(ButtonGroup::new(vec![
+                            Button::new("Decline"),
+                            Button::new("Accept").variant(crate::ButtonVariant::Filled),
+                        ])),
+                )
         }
     }
 }

crates/ui2/src/story.rs 🔗

@@ -14,7 +14,7 @@ impl Story {
             .flex_col()
             .pt_2()
             .px_4()
-            .font("Zed Mono Extended")
+            .font("Zed Mono")
             .bg(color.background)
     }