1use std::marker::PhantomData;
2
3use gpui2::elements::{img, svg};
4use gpui2::ArcCow;
5
6use crate::prelude::*;
7use crate::theme::{theme, Theme};
8use crate::{
9 static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon, List,
10 ListHeader, ToggleState,
11};
12
13#[derive(Element)]
14pub struct CollabPanel<V: 'static> {
15 view_type: PhantomData<V>,
16 scroll_state: ScrollState,
17}
18
19impl<V: 'static> CollabPanel<V> {
20 pub fn new(scroll_state: ScrollState) -> Self {
21 Self {
22 view_type: PhantomData,
23 scroll_state,
24 }
25 }
26
27 fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
28 let theme = theme(cx);
29
30 v_stack()
31 .w_64()
32 .h_full()
33 .fill(theme.middle.base.default.background)
34 .child(
35 v_stack()
36 .w_full()
37 .overflow_y_scroll(self.scroll_state.clone())
38 .child(
39 div()
40 .fill(theme.lowest.base.default.background)
41 .pb_1()
42 .border_color(theme.lowest.base.default.border)
43 .border_b()
44 .child(
45 List::new(static_collab_panel_current_call())
46 .header(
47 ListHeader::new("CRDB")
48 .left_icon(Icon::Hash.into())
49 .set_toggle(ToggleState::Toggled),
50 )
51 .set_toggle(ToggleState::Toggled),
52 ),
53 )
54 .child(
55 v_stack().py_1().child(
56 List::new(static_collab_panel_channels())
57 .header(
58 ListHeader::new("CHANNELS").set_toggle(ToggleState::Toggled),
59 )
60 .empty_message("No channels yet. Add a channel to get started.")
61 .set_toggle(ToggleState::Toggled),
62 ),
63 )
64 .child(
65 v_stack().py_1().child(
66 List::new(static_collab_panel_current_call())
67 .header(
68 ListHeader::new("CONTACTS – ONLINE")
69 .set_toggle(ToggleState::Toggled),
70 )
71 .set_toggle(ToggleState::Toggled),
72 ),
73 )
74 .child(
75 v_stack().py_1().child(
76 List::new(static_collab_panel_current_call())
77 .header(
78 ListHeader::new("CONTACTS – OFFLINE")
79 .set_toggle(ToggleState::NotToggled),
80 )
81 .set_toggle(ToggleState::NotToggled),
82 ),
83 ),
84 )
85 .child(
86 div()
87 .h_7()
88 .px_2()
89 .border_t()
90 .border_color(theme.middle.variant.default.border)
91 .flex()
92 .items_center()
93 .child(
94 div()
95 .text_sm()
96 .text_color(theme.middle.variant.default.foreground)
97 .child("Find..."),
98 ),
99 )
100 }
101
102 fn list_section_header(
103 &self,
104 label: impl Into<ArcCow<'static, str>>,
105 expanded: bool,
106 theme: &Theme,
107 ) -> impl Element<V> {
108 div()
109 .h_7()
110 .px_2()
111 .flex()
112 .justify_between()
113 .items_center()
114 .child(div().flex().gap_1().text_sm().child(label))
115 .child(
116 div().flex().h_full().gap_1().items_center().child(
117 svg()
118 .path(if expanded {
119 "icons/caret_down.svg"
120 } else {
121 "icons/caret_up.svg"
122 })
123 .w_3p5()
124 .h_3p5()
125 .fill(theme.middle.variant.default.foreground),
126 ),
127 )
128 }
129
130 fn list_item(
131 &self,
132 avatar_uri: impl Into<ArcCow<'static, str>>,
133 label: impl Into<ArcCow<'static, str>>,
134 theme: &Theme,
135 ) -> impl Element<V> {
136 div()
137 .h_7()
138 .px_2()
139 .flex()
140 .items_center()
141 .hover()
142 .fill(theme.lowest.variant.hovered.background)
143 .active()
144 .fill(theme.lowest.variant.pressed.background)
145 .child(
146 div()
147 .flex()
148 .items_center()
149 .gap_1()
150 .text_sm()
151 .child(
152 img()
153 .uri(avatar_uri)
154 .size_3p5()
155 .rounded_full()
156 .fill(theme.middle.positive.default.foreground),
157 )
158 .child(label),
159 )
160 }
161}