collab_panel.rs

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