From 180ba42456ed8d86164158b237ffc82f76998e54 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 14:54:44 -0500 Subject: [PATCH] WIP update popover_menu --- crates/collab_ui2/src/collab_titlebar_item.rs | 41 +++++------ crates/ui2/src/components/popover_menu.rs | 71 ++++++++++++++++--- 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index ab042d6f0d..d1d560fcdd 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -39,7 +39,7 @@ use project::{Project, RepositoryEntry}; use theme::ActiveTheme; use ui::{ h_stack, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, IconElement, - KeyBinding, Tooltip, + KeyBinding, PopoverMenu, Tooltip, }; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -289,28 +289,29 @@ impl Render for CollabTitlebarItem { this.when_some(user.avatar.clone(), |this, avatar| { // TODO: Finish implementing user menu popover // - // this.child( - // PopoverMenu::new( - // ButtonLike::new("user-menu") - // .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( - // IconElement::new(Icon::ChevronDown).color(Color::Muted), - // )) - // .style(ButtonStyle2::Subtle) - // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) - // .into_any_element(), - // ) - // .children(vec![div().w_96().h_96().bg(gpui::red())]), - // ) this.child( - ButtonLike::new("user-menu") - .child( - h_stack().gap_0p5().child(Avatar::data(avatar)).child( + PopoverMenu::new( + ButtonLike::new("user-menu") + .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( IconElement::new(Icon::ChevronDown).color(Color::Muted), - ), - ) - .style(ButtonStyle2::Subtle) - .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + )) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) + .into_any_element(), + ) + .anchor(gpui::AnchorCorner::TopRight) + .children(vec![div().w_96().h_96().bg(gpui::red())]), ) + // this.child( + // ButtonLike::new("user-menu") + // .child( + // h_stack().gap_0p5().child(Avatar::data(avatar)).child( + // IconElement::new(Icon::ChevronDown).color(Color::Muted), + // ), + // ) + // .style(ButtonStyle2::Subtle) + // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + // ) }) } else { this.child(Button::new("sign_in", "Sign in").on_click(move |_, cx| { diff --git a/crates/ui2/src/components/popover_menu.rs b/crates/ui2/src/components/popover_menu.rs index c00bfed921..9e393ffb34 100644 --- a/crates/ui2/src/components/popover_menu.rs +++ b/crates/ui2/src/components/popover_menu.rs @@ -1,33 +1,70 @@ -use gpui::{div, overlay, px, AnyElement, Div, ParentElement, RenderOnce, Styled, WindowContext}; +use gpui::{ + div, overlay, rems, AnchorCorner, AnyElement, Div, ParentElement, RenderOnce, Styled, + WindowContext, +}; use smallvec::SmallVec; use crate::{prelude::*, Popover}; -// 🚧 Under Construction - #[derive(IntoElement)] pub struct PopoverMenu { + /// The element that triggers the popover menu when clicked + /// Usually a button trigger: AnyElement, + /// The content of the popover menu + /// This will automatically be wrapped in a [Popover] element children: SmallVec<[AnyElement; 2]>, + /// The direction the popover menu will open by default + /// + /// When not enough space is available in the default direction, + /// the popover menu will follow the rules of [gpui2::elements::overlay] + anchor: AnchorCorner, + /// Whether the popover menu is currently open + show_menu: bool, } impl RenderOnce for PopoverMenu { type Rendered = Div; fn render(self, _cx: &mut WindowContext) -> Self::Rendered { + // Default offset = 4px padding + 1px border + let offset = 5. / 16.; + + let (top, right, bottom, left) = match self.anchor { + AnchorCorner::TopRight => (None, Some(-offset), Some(-offset), None), + AnchorCorner::TopLeft => (None, None, Some(-offset), Some(-offset)), + AnchorCorner::BottomRight => (Some(-offset), Some(-offset), None, None), + AnchorCorner::BottomLeft => (Some(-offset), None, None, Some(-offset)), + }; + div() + .flex() + .flex_none() .bg(gpui::green()) .relative() - .child(div().bg(gpui::blue()).child(self.trigger)) .child( - overlay() - .position(gpui::Point { - x: px(100.), - y: px(100.), - }) - .anchor(gpui::AnchorCorner::TopRight) - .child(Popover::new().children(self.children)), + div() + .flex_none() + .relative() + .bg(gpui::blue()) + .child(self.trigger), ) + .when(self.show_menu, |this| { + this.child( + div() + .absolute() + .size_0() + .when_some(top, |this, t| this.top(rems(t))) + .when_some(right, |this, r| this.right(rems(r))) + .when_some(bottom, |this, b| this.bottom(rems(b))) + .when_some(left, |this, l| this.left(rems(l))) + .child( + overlay() + .anchor(AnchorCorner::TopRight) + .child(Popover::new().children(self.children)), + ), + ) + }) } } @@ -36,8 +73,20 @@ impl PopoverMenu { Self { trigger, children: SmallVec::new(), + anchor: AnchorCorner::TopLeft, + show_menu: false, } } + + pub fn anchor(mut self, anchor: AnchorCorner) -> Self { + self.anchor = anchor; + self + } + + pub fn show_menu(mut self, show_menu: bool) -> Self { + self.show_menu = show_menu; + self + } } impl ParentElement for PopoverMenu {