feat: replace sidebar tabs with a single collapsible list
This commit is contained in:
@@ -10,6 +10,7 @@ use crate::avatar::Avatar;
|
||||
use crate::button::Button;
|
||||
use crate::menu::PopupMenu;
|
||||
use crate::nav::Nav;
|
||||
use crate::nav_item::NavItem;
|
||||
use crate::popover::{Popover, PopoverState};
|
||||
|
||||
/// Builds the items of a popup menu on each render.
|
||||
@@ -44,6 +45,8 @@ impl DropdownMenu for Avatar {}
|
||||
|
||||
impl DropdownMenu for Nav {}
|
||||
|
||||
impl DropdownMenu for NavItem {}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct DropdownMenuPopover<T: Selectable + IntoElement + 'static> {
|
||||
id: ElementId,
|
||||
|
||||
@@ -2,23 +2,26 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
AnyElement, App, ClickEvent, ElementId, InteractiveElement, IntoElement, ParentElement,
|
||||
RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement, Styled, Window,
|
||||
div,
|
||||
AnyElement, App, ClickEvent, ElementId, InteractiveElement, Interactivity, IntoElement,
|
||||
ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement,
|
||||
Styled, Window, div,
|
||||
};
|
||||
use theme::ActiveTheme;
|
||||
|
||||
use crate::{StyledExt, h_flex};
|
||||
use crate::{Selectable, StyledExt, h_flex};
|
||||
|
||||
/// A single navigation entry in a sidebar.
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[derive(IntoElement)]
|
||||
pub struct NavItem {
|
||||
id: ElementId,
|
||||
interactivity: Interactivity,
|
||||
style: StyleRefinement,
|
||||
icon: AnyElement,
|
||||
label: SharedString,
|
||||
suffix: Option<AnyElement>,
|
||||
selected: bool,
|
||||
clickable: bool,
|
||||
on_click: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App)>>,
|
||||
}
|
||||
|
||||
@@ -28,16 +31,30 @@ impl NavItem {
|
||||
label: impl Into<SharedString>,
|
||||
icon: impl IntoElement,
|
||||
) -> Self {
|
||||
let id = id.into();
|
||||
let mut interactivity = Interactivity::default();
|
||||
interactivity.element_id = Some(id.clone());
|
||||
|
||||
Self {
|
||||
id: id.into(),
|
||||
id,
|
||||
interactivity,
|
||||
style: StyleRefinement::default(),
|
||||
icon: icon.into_any_element(),
|
||||
label: label.into(),
|
||||
suffix: None,
|
||||
selected: false,
|
||||
clickable: false,
|
||||
on_click: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks the item as clickable even when it has no `on_click` handler, so it
|
||||
/// still shows the hover affordance. Used by items whose click opens a menu.
|
||||
pub fn clickable(mut self, clickable: bool) -> Self {
|
||||
self.clickable = clickable;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn suffix(mut self, suffix: impl IntoElement) -> Self {
|
||||
self.suffix = Some(suffix.into_any_element());
|
||||
self
|
||||
@@ -52,6 +69,23 @@ impl NavItem {
|
||||
}
|
||||
}
|
||||
|
||||
impl Selectable for NavItem {
|
||||
fn selected(mut self, selected: bool) -> Self {
|
||||
self.selected = selected;
|
||||
self
|
||||
}
|
||||
|
||||
fn is_selected(&self) -> bool {
|
||||
self.selected
|
||||
}
|
||||
}
|
||||
|
||||
impl InteractiveElement for NavItem {
|
||||
fn interactivity(&mut self) -> &mut Interactivity {
|
||||
&mut self.interactivity
|
||||
}
|
||||
}
|
||||
|
||||
impl Styled for NavItem {
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.style
|
||||
@@ -60,7 +94,7 @@ impl Styled for NavItem {
|
||||
|
||||
impl RenderOnce for NavItem {
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let clickable = self.on_click.is_some();
|
||||
let clickable = self.on_click.is_some() || self.clickable;
|
||||
|
||||
h_flex()
|
||||
.id(self.id)
|
||||
@@ -86,6 +120,9 @@ impl RenderOnce for NavItem {
|
||||
.when(clickable, |this| {
|
||||
this.cursor_pointer()
|
||||
.hover(|this| this.bg(cx.theme().ghost_element_hover))
|
||||
.when(self.selected, |this| {
|
||||
this.bg(cx.theme().ghost_element_active)
|
||||
})
|
||||
})
|
||||
.when_some(self.on_click, |this, handler| {
|
||||
this.on_click(move |event, window, cx| handler(event, window, cx))
|
||||
|
||||
Reference in New Issue
Block a user