1use gpui3::{
2 div, img, svg, view, AppContext, Context, Element, Interactive, IntoAnyElement, MouseButton,
3 ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
4 WindowContext,
5};
6use ui::{theme, Theme};
7
8pub struct CollabPanel {
9 scroll_state: ScrollState,
10}
11
12pub fn collab_panel<S: 'static>(cx: &mut WindowContext) -> View<CollabPanel, S> {
13 view(cx.entity(|cx| CollabPanel::new(cx)), CollabPanel::render)
14}
15
16impl CollabPanel {
17 fn new(_: &mut AppContext) -> Self {
18 CollabPanel {
19 scroll_state: ScrollState::default(),
20 }
21 }
22}
23
24impl CollabPanel {
25 fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
26 let theme = theme(cx);
27
28 // Panel
29 div()
30 .w_64()
31 .h_full()
32 .flex()
33 .flex_col()
34 .font("Courier")
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 .on_click(MouseButton::Left, |_, _, _| {
49 dbg!("click!");
50 })
51 .fill(theme.lowest.base.default.background)
52 .pb_1()
53 .border_color(theme.lowest.base.default.border)
54 .border_b()
55 //:: https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
56 // .group()
57 // List Section Header
58 .child(self.list_section_header("#CRDB 🗃️", true, &theme))
59 // List Item Large
60 .child(self.list_item(
61 "http://github.com/maxbrunsfeld.png?s=50",
62 "maxbrunsfeld",
63 &theme,
64 )),
65 )
66 .child(
67 div()
68 .py_2()
69 .flex()
70 .flex_col()
71 .child(self.list_section_header("CHANNELS", true, &theme)),
72 )
73 .child(
74 div()
75 .py_2()
76 .flex()
77 .flex_col()
78 .child(self.list_section_header("CONTACTS", true, &theme))
79 .children(
80 std::iter::repeat_with(|| {
81 vec![
82 self.list_item(
83 "http://github.com/as-cii.png?s=50",
84 "as-cii",
85 &theme,
86 ),
87 self.list_item(
88 "http://github.com/nathansobo.png?s=50",
89 "nathansobo",
90 &theme,
91 ),
92 self.list_item(
93 "http://github.com/maxbrunsfeld.png?s=50",
94 "maxbrunsfeld",
95 &theme,
96 ),
97 ]
98 })
99 .take(5)
100 .flatten(),
101 ),
102 ),
103 )
104 .child(
105 div()
106 .h_7()
107 .px_2()
108 .border_t()
109 .border_color(theme.middle.variant.default.border)
110 .flex()
111 .items_center()
112 .child(
113 div()
114 .text_sm()
115 .text_color(theme.middle.variant.default.foreground)
116 .child("Find..."),
117 ),
118 )
119 }
120
121 fn list_section_header(
122 &self,
123 label: impl IntoAnyElement<Self>,
124 expanded: bool,
125 theme: &Theme,
126 ) -> impl Element<State = Self> {
127 div()
128 .h_7()
129 .px_2()
130 .flex()
131 .justify_between()
132 .items_center()
133 .hover()
134 .fill(theme.lowest.base.active.background)
135 .child(div().flex().gap_1().text_sm().child(label))
136 .child(
137 div().flex().h_full().gap_1().items_center().child(
138 svg()
139 .path(if expanded {
140 "icons/caret_down.svg"
141 } else {
142 "icons/caret_up.svg"
143 })
144 .w_3p5()
145 .h_3p5()
146 .fill(theme.middle.variant.default.foreground),
147 ),
148 )
149 }
150
151 fn list_item(
152 &self,
153 avatar_uri: impl Into<SharedString>,
154 label: impl IntoAnyElement<Self>,
155 theme: &Theme,
156 ) -> impl Element<State = Self> {
157 div()
158 .h_7()
159 .px_2()
160 .flex()
161 .items_center()
162 .hover()
163 .fill(theme.lowest.variant.hovered.background)
164 // .active()
165 // .fill(theme.lowest.variant.pressed.background)
166 .child(
167 div()
168 .flex()
169 .items_center()
170 .gap_1()
171 .text_sm()
172 .child(
173 img()
174 .uri(avatar_uri)
175 .size_3p5()
176 .rounded_full()
177 .fill(theme.middle.positive.default.foreground)
178 .shadow_md(),
179 )
180 .child(label),
181 )
182 }
183}