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