1use crate::prelude::{DisclosureControlVisibility, InteractionState, ToggleState};
2use crate::theme::theme;
3use crate::tokens::token;
4use crate::{icon, IconAsset, Label};
5use gpui2::style::{StyleHelpers, Styleable};
6use gpui2::{elements::div, IntoElement};
7use gpui2::{Element, ParentElement, ViewContext};
8
9#[derive(Element, Clone)]
10pub struct ListItem {
11 label: Label,
12 left_icon: Option<IconAsset>,
13 indent_level: u32,
14 state: InteractionState,
15 disclosure_control_style: DisclosureControlVisibility,
16 toggle: Option<ToggleState>,
17}
18
19pub fn list_item(label: Label) -> ListItem {
20 ListItem {
21 label,
22 indent_level: 0,
23 left_icon: None,
24 disclosure_control_style: DisclosureControlVisibility::default(),
25 state: InteractionState::default(),
26 toggle: None,
27 }
28}
29
30impl ListItem {
31 pub fn indent_level(mut self, indent_level: u32) -> Self {
32 self.indent_level = indent_level;
33 self
34 }
35
36 pub fn set_toggle(mut self, toggle: ToggleState) -> Self {
37 self.toggle = Some(toggle);
38 self
39 }
40
41 pub fn left_icon(mut self, left_icon: Option<IconAsset>) -> Self {
42 self.left_icon = left_icon;
43 self
44 }
45
46 pub fn state(mut self, state: InteractionState) -> Self {
47 self.state = state;
48 self
49 }
50
51 pub fn disclosure_control_style(
52 mut self,
53 disclosure_control_style: DisclosureControlVisibility,
54 ) -> Self {
55 self.disclosure_control_style = disclosure_control_style;
56 self
57 }
58
59 fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
60 let theme = theme(cx);
61 let token = token();
62 let mut disclosure_control = match self.toggle {
63 Some(ToggleState::NotToggled) => Some(div().child(icon(IconAsset::ChevronRight))),
64 Some(ToggleState::Toggled) => Some(div().child(icon(IconAsset::ChevronDown))),
65 None => Some(div()),
66 };
67
68 match self.disclosure_control_style {
69 DisclosureControlVisibility::OnHover => {
70 disclosure_control =
71 disclosure_control.map(|c| div().absolute().neg_left_5().child(c));
72 }
73 DisclosureControlVisibility::Always => {}
74 }
75
76 div()
77 .fill(theme.middle.base.default.background)
78 .hover()
79 .fill(theme.middle.base.hovered.background)
80 .active()
81 .fill(theme.middle.base.pressed.background)
82 .relative()
83 .py_1()
84 .child(
85 div()
86 .h_6()
87 .px_2()
88 // .ml(rems(0.75 * self.indent_level as f32))
89 .children((0..self.indent_level).map(|_| {
90 div()
91 .w(token.list_indent_depth)
92 .h_full()
93 .flex()
94 .justify_center()
95 .child(
96 div()
97 .ml_px()
98 .w_px()
99 .h_full()
100 .fill(theme.middle.base.default.border),
101 )
102 }))
103 .flex()
104 .gap_1()
105 .items_center()
106 .relative()
107 .children(disclosure_control)
108 .children(self.left_icon.map(|i| icon(i)))
109 .child(self.label.clone()),
110 )
111 }
112}