1use std::marker::PhantomData;
2
3use gpui3::{img, svg, SharedString};
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, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
27 let theme = theme(cx);
28 let color = ThemeColor::new(cx);
29
30 v_stack()
31 .h_full()
32 .bg(color.surface)
33 .child(
34 v_stack()
35 .w_full()
36 .overflow_y_scroll(self.scroll_state.clone())
37 .child(
38 div()
39 .bg(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 .set_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<SharedString>,
104 expanded: bool,
105 theme: &Theme,
106 ) -> impl Element<ViewState = 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 .text_color(theme.middle.variant.default.foreground),
125 ),
126 )
127 }
128
129 fn list_item(
130 &self,
131 avatar_uri: impl Into<SharedString>,
132 label: impl Into<SharedString>,
133 theme: &Theme,
134 ) -> impl Element<ViewState = S> {
135 div()
136 .h_7()
137 .px_2()
138 .flex()
139 .items_center()
140 .hover(|style| style.bg(theme.lowest.variant.hovered.background))
141 // .active(|style| style.fill(theme.lowest.variant.pressed.background))
142 .child(
143 div()
144 .flex()
145 .items_center()
146 .gap_1()
147 .text_sm()
148 .child(
149 img().uri(avatar_uri).size_3p5().rounded_full().bg(theme
150 .middle
151 .positive
152 .default
153 .foreground),
154 )
155 .child(label.into()),
156 )
157 }
158}
159
160#[cfg(feature = "stories")]
161pub use stories::*;
162
163#[cfg(feature = "stories")]
164mod stories {
165 use crate::Story;
166
167 use super::*;
168
169 #[derive(Element)]
170 pub struct CollabPanelStory<S: 'static + Send + Sync + Clone> {
171 state_type: PhantomData<S>,
172 }
173
174 impl<S: 'static + Send + Sync + Clone> CollabPanelStory<S> {
175 pub fn new() -> Self {
176 Self {
177 state_type: PhantomData,
178 }
179 }
180
181 fn render(
182 &mut self,
183 _view: &mut S,
184 cx: &mut ViewContext<S>,
185 ) -> impl Element<ViewState = S> {
186 Story::container(cx)
187 .child(Story::title_for::<_, CollabPanel<S>>(cx))
188 .child(Story::label(cx, "Default"))
189 .child(CollabPanel::new(ScrollState::default()))
190 }
191 }
192}