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 .id("list_item")
137 .h_7()
138 .px_2()
139 .flex()
140 .items_center()
141 .hover(|style| style.bg(theme.lowest.variant.hovered.background))
142 .active(|style| style.bg(theme.lowest.variant.pressed.background))
143 .child(
144 div()
145 .flex()
146 .items_center()
147 .gap_1()
148 .text_sm()
149 .child(
150 img().uri(avatar_uri).size_3p5().rounded_full().bg(theme
151 .middle
152 .positive
153 .default
154 .foreground),
155 )
156 .child(label.into()),
157 )
158 }
159}
160
161#[cfg(feature = "stories")]
162pub use stories::*;
163
164#[cfg(feature = "stories")]
165mod stories {
166 use crate::Story;
167
168 use super::*;
169
170 #[derive(Element)]
171 pub struct CollabPanelStory<S: 'static + Send + Sync + Clone> {
172 state_type: PhantomData<S>,
173 }
174
175 impl<S: 'static + Send + Sync + Clone> CollabPanelStory<S> {
176 pub fn new() -> Self {
177 Self {
178 state_type: PhantomData,
179 }
180 }
181
182 fn render(
183 &mut self,
184 _view: &mut S,
185 cx: &mut ViewContext<S>,
186 ) -> impl Element<ViewState = S> {
187 Story::container(cx)
188 .child(Story::title_for::<_, CollabPanel<S>>(cx))
189 .child(Story::label(cx, "Default"))
190 .child(CollabPanel::new(ScrollState::default()))
191 }
192 }
193}