diff --git a/crates/gpui2_macros/src/style_helpers.rs b/crates/gpui2_macros/src/style_helpers.rs index e9e061722f..b1e93cc5b2 100644 --- a/crates/gpui2_macros/src/style_helpers.rs +++ b/crates/gpui2_macros/src/style_helpers.rs @@ -173,6 +173,7 @@ fn generate_custom_value_setter( method } +/// Returns a vec of (Property name, has 'auto' suffix, tokens for accessing the property, documentation) fn box_prefixes() -> Vec<(&'static str, bool, Vec, &'static str)> { vec![ ( @@ -188,24 +189,32 @@ fn box_prefixes() -> Vec<(&'static str, bool, Vec, &'static str)> vec![quote! {size.width}, quote! {size.height}], "Sets the width and height of the element." ), + // TODO: These don't use the same size ramp as the others + // see https://tailwindcss.com/docs/max-width ( "min_w", true, vec![quote! { min_size.width }], "Sets the minimum width of the element. [Docs](https://tailwindcss.com/docs/min-width)", ), + // TODO: These don't use the same size ramp as the others + // see https://tailwindcss.com/docs/max-width ( "min_h", true, vec![quote! { min_size.height }], "Sets the minimum height of the element. [Docs](https://tailwindcss.com/docs/min-height)", ), + // TODO: These don't use the same size ramp as the others + // see https://tailwindcss.com/docs/max-width ( "max_w", true, vec![quote! { max_size.width }], "Sets the maximum width of the element. [Docs](https://tailwindcss.com/docs/max-width)", ), + // TODO: These don't use the same size ramp as the others + // see https://tailwindcss.com/docs/max-width ( "max_h", true, @@ -336,6 +345,7 @@ fn box_prefixes() -> Vec<(&'static str, bool, Vec, &'static str)> ] } +/// Returns a vec of (Suffix size, tokens that correspond to this size, documentation) fn box_suffixes() -> Vec<(&'static str, TokenStream2, &'static str)> { vec![ ("0", quote! { px(0.) }, "0px"), diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 4686a2226e..2f495d7258 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -65,6 +65,7 @@ pub enum ComponentStory { ChatPanel, CollabPanel, CommandPalette, + Copilot, ContextMenu, Facepile, Keybinding, @@ -170,6 +171,10 @@ impl ComponentStory { ui::TrafficLightsStory::new().into_any() }) .into_any(), + Self::Copilot => view(cx.entity(|cx| ()), |_, _| { + ui::CopilotModalStory::new().into_any() + }) + .into_any(), Self::Workspace => ui::WorkspaceStory::view(cx).into_any(), } } diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index 1e749f6934..7a9cac01ca 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -6,12 +6,14 @@ mod chat_panel; mod collab_panel; mod command_palette; mod context_menu; +mod copilot; mod editor_pane; mod facepile; mod icon_button; mod keybinding; mod language_selector; mod list; +mod modal; mod multi_buffer; mod notification_toast; mod notifications_panel; @@ -40,12 +42,14 @@ pub use chat_panel::*; pub use collab_panel::*; pub use command_palette::*; pub use context_menu::*; +pub use copilot::*; pub use editor_pane::*; pub use facepile::*; pub use icon_button::*; pub use keybinding::*; pub use language_selector::*; pub use list::*; +pub use modal::*; pub use multi_buffer::*; pub use notification_toast::*; pub use notifications_panel::*; diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs new file mode 100644 index 0000000000..0659240892 --- /dev/null +++ b/crates/ui2/src/components/copilot.rs @@ -0,0 +1,63 @@ +use std::marker::PhantomData; + +use crate::{prelude::*, Button, Label, LabelColor, Modal}; + +#[derive(Element)] +pub struct CopilotModal { + id: ElementId, + state_type: PhantomData, +} + +impl CopilotModal { + pub fn new(id: impl Into) -> Self { + Self { + id: id.into(), + state_type: PhantomData, + } + } + + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + let color = ThemeColor::new(cx); + + div().id(self.id.clone()).child( + Modal::new("some-id") + .title("Connect Copilot to Zed") + .child(Label::new("You can update your settings or sign out from the Copilot menu in the status bar.").color(LabelColor::Muted)) + .primary_action(Button::new("Connect to Github").variant(ButtonVariant::Filled)), + ) + } +} + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use crate::Story; + + use super::*; + + #[derive(Element)] + pub struct CopilotModalStory { + state_type: PhantomData, + } + + impl CopilotModalStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render( + &mut self, + _view: &mut S, + cx: &mut ViewContext, + ) -> impl Element { + Story::container(cx) + .child(Story::title_for::<_, CopilotModal>(cx)) + .child(Story::label(cx, "Default")) + .child(CopilotModal::new("copilot-modal")) + } + } +} diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index fb5a248162..dea77d8718 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -518,13 +518,10 @@ impl ListDetailsEntry { this.child(Label::new(self.meta.clone().unwrap()).color(LabelColor::Muted)) }) .child( - h_stack().gap_1().justify_end().children( - self.actions - .take() - .unwrap_or_default() - .into_iter() - .map(|action| action), - ), + h_stack() + .gap_1() + .justify_end() + .children(self.actions.take().unwrap_or_default().into_iter()), ) } } diff --git a/crates/ui2/src/components/modal.rs b/crates/ui2/src/components/modal.rs new file mode 100644 index 0000000000..a8acaf41b4 --- /dev/null +++ b/crates/ui2/src/components/modal.rs @@ -0,0 +1,87 @@ +use std::marker::PhantomData; + +use gpui2::AnyElement; +use smallvec::SmallVec; + +use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label}; + +#[derive(Element)] +pub struct Modal { + id: ElementId, + state_type: PhantomData, + title: Option, + primary_action: Option>, + secondary_action: Option>, + children: SmallVec<[AnyElement; 2]>, +} + +impl Modal { + pub fn new(id: impl Into) -> Self { + Self { + id: id.into(), + state_type: PhantomData, + title: None, + primary_action: None, + secondary_action: None, + children: SmallVec::new(), + } + } + + pub fn title(mut self, title: impl Into) -> Self { + self.title = Some(title.into()); + self + } + + pub fn primary_action(mut self, action: Button) -> Self { + self.primary_action = Some(action); + self + } + + pub fn secondary_action(mut self, action: Button) -> Self { + self.secondary_action = Some(action); + self + } + + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + let color = ThemeColor::new(cx); + + v_stack() + .id(self.id.clone()) + .w_96() + // .rounded_xl() + .bg(color.background) + .border() + .border_color(color.border) + .shadow_2xl() + .child( + h_stack() + .justify_between() + .p_1() + .border_b() + .border_color(color.border) + .child(div().children(self.title.clone().map(|t| Label::new(t)))) + .child(IconButton::new(Icon::Close)), + ) + .child(v_stack().p_1().children(self.children.drain(..))) + .when( + self.primary_action.is_some() || self.secondary_action.is_some(), + |this| { + this.child( + h_stack() + .border_t() + .border_color(color.border) + .p_1() + .justify_end() + .children(self.secondary_action.take()) + .children(self.primary_action.take()), + ) + }, + ) + } +} + +impl ParentElement for Modal { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + &mut self.children + } +} diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 0604f4f3e6..9d7897cb24 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -146,7 +146,11 @@ impl Button { self.icon.map(|i| IconElement::new(i).color(icon_color)) } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + pub fn render( + &mut self, + _view: &mut S, + cx: &mut ViewContext, + ) -> impl Element { let icon_color = self.icon_color(); let border_color = self.border_color(cx); let settings = user_settings(cx); diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index bf3243f128..2b28240034 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -110,7 +110,7 @@ pub struct ThemeColor { /// The background color of an elevated surface, like a modal, tooltip or toast. pub elevated_surface: Hsla, pub surface: Hsla, - /// Window background color + /// Window background color of the base app pub background: Hsla, /// Default background for elements like filled buttons, /// text fields, checkboxes, radio buttons, etc. @@ -149,6 +149,7 @@ pub struct ThemeColor { pub title_bar: Hsla, pub toolbar: Hsla, pub tab_bar: Hsla, + /// The background of the editor pub editor: Hsla, pub editor_subheader: Hsla, pub editor_active_line: Hsla,