collab_panel.rs

  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}