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