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