Make list_item toggleable, improve optional left_icon on list item

Co-Authored-By: Julia <30666851+ForLoveOfCats@users.noreply.github.com>
This commit is contained in:
Nate Butler 2023-09-19 11:52:35 -04:00
parent 7e300079ce
commit 748ad5f05a
4 changed files with 73 additions and 30 deletions

View file

@ -47,3 +47,9 @@ pub enum SelectedState {
PartiallySelected, PartiallySelected,
Selected, Selected,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ToggleState {
Toggled,
NotToggled,
}

View file

@ -1,4 +1,4 @@
use crate::prelude::InteractionState; use crate::prelude::{InteractionState, ToggleState};
use crate::theme::theme; use crate::theme::theme;
use crate::ui::{icon, IconAsset, Label}; use crate::ui::{icon, IconAsset, Label};
use gpui2::geometry::rems; use gpui2::geometry::rems;
@ -12,6 +12,7 @@ pub struct ListItem {
left_icon: Option<IconAsset>, left_icon: Option<IconAsset>,
indent_level: f32, indent_level: f32,
state: InteractionState, state: InteractionState,
toggle: Option<ToggleState>,
} }
pub fn list_item(label: Label) -> ListItem { pub fn list_item(label: Label) -> ListItem {
@ -20,6 +21,7 @@ pub fn list_item(label: Label) -> ListItem {
indent_level: 0.0, indent_level: 0.0,
left_icon: None, left_icon: None,
state: InteractionState::default(), state: InteractionState::default(),
toggle: None,
} }
} }
@ -28,10 +30,17 @@ impl ListItem {
self.indent_level = indent_level; self.indent_level = indent_level;
self self
} }
pub fn set_toggle(mut self, toggle: ToggleState) -> Self {
self.toggle = Some(toggle);
self
}
pub fn left_icon(mut self, left_icon: Option<IconAsset>) -> Self { pub fn left_icon(mut self, left_icon: Option<IconAsset>) -> Self {
self.left_icon = left_icon; self.left_icon = left_icon;
self self
} }
pub fn state(mut self, state: InteractionState) -> Self { pub fn state(mut self, state: InteractionState) -> Self {
self.state = state; self.state = state;
self self
@ -40,7 +49,7 @@ impl ListItem {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
let mut el = div() div()
.fill(theme.middle.base.default.background) .fill(theme.middle.base.default.background)
.hover() .hover()
.fill(theme.middle.base.hovered.background) .fill(theme.middle.base.hovered.background)
@ -53,13 +62,14 @@ impl ListItem {
.ml(rems(0.75 * self.indent_level.clone())) .ml(rems(0.75 * self.indent_level.clone()))
.flex() .flex()
.gap_2() .gap_2()
.items_center(), .items_center()
); .children(match self.toggle {
Some(ToggleState::NotToggled) => Some(icon(IconAsset::ChevronRight)),
if self.left_icon.is_some() { Some(ToggleState::Toggled) => Some(icon(IconAsset::ChevronDown)),
el = el.child(icon(self.left_icon.clone().unwrap())) None => None,
} })
.children(self.left_icon.map(|i| icon(i)))
el.child(self.label.clone()) .child(self.label.clone()),
)
} }
} }

View file

@ -1,11 +1,13 @@
use std::borrow::Cow;
use crate::theme::theme; use crate::theme::theme;
use gpui2::elements::svg; use gpui2::elements::svg;
use gpui2::style::StyleHelpers; use gpui2::style::StyleHelpers;
use gpui2::IntoElement; use gpui2::IntoElement;
use gpui2::{Element, ViewContext}; use gpui2::{Element, ViewContext};
// Icon::Hash
// icon(IconAsset::Hash).color(IconColor::Warning)
// Icon::new(IconAsset::Hash).color(IconColor::Warning)
#[derive(Default, PartialEq, Copy, Clone)] #[derive(Default, PartialEq, Copy, Clone)]
pub enum IconAsset { pub enum IconAsset {
Ai, Ai,
@ -18,19 +20,29 @@ pub enum IconAsset {
File, File,
Folder, Folder,
FolderOpen, FolderOpen,
ChevronDown,
ChevronUp,
ChevronLeft,
ChevronRight,
} }
pub fn icon_asset(asset: IconAsset) -> impl Into<Cow<'static, str>> { impl IconAsset {
match asset { pub fn path(self) -> &'static str {
IconAsset::Ai => "icons/ai.svg", match self {
IconAsset::ArrowLeft => "icons/arrow_left.svg", IconAsset::Ai => "icons/ai.svg",
IconAsset::ArrowRight => "icons/arrow_right.svg", IconAsset::ArrowLeft => "icons/arrow_left.svg",
IconAsset::ArrowUpRight => "icons/arrow_up_right.svg", IconAsset::ArrowRight => "icons/arrow_right.svg",
IconAsset::Bolt => "icons/bolt.svg", IconAsset::ArrowUpRight => "icons/arrow_up_right.svg",
IconAsset::Hash => "icons/hash.svg", IconAsset::Bolt => "icons/bolt.svg",
IconAsset::File => "icons/file_icons/file.svg", IconAsset::Hash => "icons/hash.svg",
IconAsset::Folder => "icons/file_icons/folder.svg", IconAsset::ChevronDown => "icons/chevron_down.svg",
IconAsset::FolderOpen => "icons/file_icons/folder_open.svg", IconAsset::ChevronUp => "icons/chevron_up.svg",
IconAsset::ChevronLeft => "icons/chevron_left.svg",
IconAsset::ChevronRight => "icons/chevron_right.svg",
IconAsset::File => "icons/file_icons/file.svg",
IconAsset::Folder => "icons/file_icons/folder.svg",
IconAsset::FolderOpen => "icons/file_icons/folder_open.svg",
}
} }
} }
@ -43,12 +55,18 @@ pub fn icon(asset: IconAsset) -> Icon {
Icon { asset } Icon { asset }
} }
// impl Icon {
// pub fn new(asset: IconAsset) -> Icon {
// Icon { asset }
// }
// }
impl Icon { impl Icon {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
svg() svg()
.path(icon_asset(self.asset)) .path(self.asset.path())
.size_4() .size_4()
.fill(theme.lowest.base.default.foreground) .fill(theme.lowest.base.default.foreground)
} }

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
prelude::InteractionState, prelude::{InteractionState, ToggleState},
theme::theme, theme::theme,
ui::{input, label, list_item, IconAsset, LabelColor}, ui::{input, label, list_item, IconAsset, LabelColor},
}; };
@ -44,21 +44,30 @@ impl<V: 'static> ProjectPanel<V> {
div().flex().flex_col().children( div().flex().flex_col().children(
std::iter::repeat_with(|| { std::iter::repeat_with(|| {
vec![ vec![
list_item(label("sqlez").color(LabelColor::Modified))
.left_icon(IconAsset::FolderOpen.into())
.indent_level(0.0)
.set_toggle(ToggleState::NotToggled),
list_item(label("storybook").color(LabelColor::Modified)) list_item(label("storybook").color(LabelColor::Modified))
.left_icon(IconAsset::FolderOpen.into()) .left_icon(IconAsset::FolderOpen.into())
.indent_level(0.0), .indent_level(0.0)
.set_toggle(ToggleState::Toggled),
list_item(label("docs").color(LabelColor::Default)) list_item(label("docs").color(LabelColor::Default))
.left_icon(IconAsset::Folder.into()) .left_icon(IconAsset::Folder.into())
.indent_level(1.0), .indent_level(1.0)
.set_toggle(ToggleState::Toggled),
list_item(label("src").color(LabelColor::Modified)) list_item(label("src").color(LabelColor::Modified))
.left_icon(IconAsset::FolderOpen.into()) .left_icon(IconAsset::FolderOpen.into())
.indent_level(2.0), .indent_level(2.0)
.set_toggle(ToggleState::Toggled),
list_item(label("ui").color(LabelColor::Modified)) list_item(label("ui").color(LabelColor::Modified))
.left_icon(IconAsset::FolderOpen.into()) .left_icon(IconAsset::FolderOpen.into())
.indent_level(3.0), .indent_level(3.0)
.set_toggle(ToggleState::Toggled),
list_item(label("component").color(LabelColor::Created)) list_item(label("component").color(LabelColor::Created))
.left_icon(IconAsset::FolderOpen.into()) .left_icon(IconAsset::FolderOpen.into())
.indent_level(4.0), .indent_level(4.0)
.set_toggle(ToggleState::Toggled),
list_item(label("facepile.rs").color(LabelColor::Default)) list_item(label("facepile.rs").color(LabelColor::Default))
.left_icon(IconAsset::File.into()) .left_icon(IconAsset::File.into())
.indent_level(5.0), .indent_level(5.0),