collab_panel.rs

  1use crate::theme::{theme, Theme};
  2use gpui2::{
  3    elements::{div, div::ScrollState, img, svg},
  4    style::{StyleHelpers, Styleable},
  5    ArcCow, Element, IntoElement, ParentElement, ViewContext,
  6};
  7use std::marker::PhantomData;
  8
  9#[derive(Element)]
 10pub struct CollabPanelElement<V: 'static> {
 11    view_type: PhantomData<V>,
 12    scroll_state: ScrollState,
 13}
 14
 15// When I improve child view rendering, I'd like to have V implement a trait  that
 16// provides the scroll state, among other things.
 17pub fn collab_panel<V: 'static>(scroll_state: ScrollState) -> CollabPanelElement<V> {
 18    CollabPanelElement {
 19        view_type: PhantomData,
 20        scroll_state,
 21    }
 22}
 23
 24impl<V: 'static> CollabPanelElement<V> {
 25    fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
 26        let theme = theme(cx);
 27
 28        // Panel
 29        div()
 30            .w_64()
 31            .h_full()
 32            .flex()
 33            .flex_col()
 34            .font("Zed Sans Extended")
 35            .text_color(theme.middle.base.default.foreground)
 36            .border_color(theme.middle.base.default.border)
 37            .border()
 38            .fill(theme.middle.base.default.background)
 39            .child(
 40                div()
 41                    .w_full()
 42                    .flex()
 43                    .flex_col()
 44                    .overflow_y_scroll(self.scroll_state.clone())
 45                    // List Container
 46                    .child(
 47                        div()
 48                            .fill(theme.lowest.base.default.background)
 49                            .pb_1()
 50                            .border_color(theme.lowest.base.default.border)
 51                            .border_b()
 52                            //:: https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
 53                            // .group()
 54                            // List Section Header
 55                            .child(self.list_section_header("#CRDB", true, &theme))
 56                            // List Item Large
 57                            .child(self.list_item(
 58                                "http://github.com/maxbrunsfeld.png?s=50",
 59                                "maxbrunsfeld",
 60                                &theme,
 61                            )),
 62                    )
 63                    .child(
 64                        div()
 65                            .py_2()
 66                            .flex()
 67                            .flex_col()
 68                            .child(self.list_section_header("CHANNELS", true, &theme)),
 69                    )
 70                    .child(
 71                        div()
 72                            .py_2()
 73                            .flex()
 74                            .flex_col()
 75                            .child(self.list_section_header("CONTACTS", true, &theme))
 76                            .children(
 77                                std::iter::repeat_with(|| {
 78                                    vec![
 79                                        self.list_item(
 80                                            "http://github.com/as-cii.png?s=50",
 81                                            "as-cii",
 82                                            &theme,
 83                                        ),
 84                                        self.list_item(
 85                                            "http://github.com/nathansobo.png?s=50",
 86                                            "nathansobo",
 87                                            &theme,
 88                                        ),
 89                                        self.list_item(
 90                                            "http://github.com/maxbrunsfeld.png?s=50",
 91                                            "maxbrunsfeld",
 92                                            &theme,
 93                                        ),
 94                                    ]
 95                                })
 96                                .take(3)
 97                                .flatten(),
 98                            ),
 99                    ),
100            )
101            .child(
102                div()
103                    .h_7()
104                    .px_2()
105                    .border_t()
106                    .border_color(theme.middle.variant.default.border)
107                    .flex()
108                    .items_center()
109                    .child(
110                        div()
111                            .text_sm()
112                            .text_color(theme.middle.variant.default.foreground)
113                            .child("Find..."),
114                    ),
115            )
116    }
117
118    fn list_section_header(
119        &self,
120        label: impl Into<ArcCow<'static, str>>,
121        expanded: bool,
122        theme: &Theme,
123    ) -> impl Element<V> {
124        div()
125            .h_7()
126            .px_2()
127            .flex()
128            .justify_between()
129            .items_center()
130            .child(div().flex().gap_1().text_sm().child(label))
131            .child(
132                div().flex().h_full().gap_1().items_center().child(
133                    svg()
134                        .path(if expanded {
135                            "icons/caret_down.svg"
136                        } else {
137                            "icons/caret_up.svg"
138                        })
139                        .w_3p5()
140                        .h_3p5()
141                        .fill(theme.middle.variant.default.foreground),
142                ),
143            )
144    }
145
146    fn list_item(
147        &self,
148        avatar_uri: impl Into<ArcCow<'static, str>>,
149        label: impl Into<ArcCow<'static, str>>,
150        theme: &Theme,
151    ) -> impl Element<V> {
152        div()
153            .h_7()
154            .px_2()
155            .flex()
156            .items_center()
157            .hover()
158            .fill(theme.lowest.variant.hovered.background)
159            .active()
160            .fill(theme.lowest.variant.pressed.background)
161            .child(
162                div()
163                    .flex()
164                    .items_center()
165                    .gap_1()
166                    .text_sm()
167                    .child(
168                        img()
169                            .uri(avatar_uri)
170                            .size_3p5()
171                            .rounded_full()
172                            .fill(theme.middle.positive.default.foreground),
173                    )
174                    .child(label),
175            )
176    }
177}