workspace.rs

  1use gpui3::{
  2    div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, View,
  3    ViewContext, WindowContext,
  4};
  5use ui::prelude::*;
  6use ui::{themed, Panel, Stack};
  7
  8use crate::{
  9    collab_panel::{collab_panel, CollabPanel},
 10    themes::rose_pine_dawn,
 11};
 12
 13pub struct Workspace {
 14    left_panel: View<CollabPanel, Self>,
 15    right_panel: View<CollabPanel, Self>,
 16}
 17
 18pub fn workspace(cx: &mut WindowContext) -> RootView<Workspace> {
 19    view(cx.entity(|cx| Workspace::new(cx)), Workspace::render)
 20}
 21
 22impl Workspace {
 23    fn new(cx: &mut ViewContext<Self>) -> Self {
 24        Self {
 25            left_panel: collab_panel(cx),
 26            right_panel: collab_panel(cx),
 27        }
 28    }
 29
 30    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
 31        themed(rose_pine_dawn(), cx, |cx| {
 32            let theme = theme(cx);
 33
 34            div()
 35                .size_full()
 36                .v_stack()
 37                .fill(theme.lowest.base.default.background)
 38                .child(Panel::new(
 39                    ScrollState::default(),
 40                    |_, _| {
 41                        vec![div()
 42                            .font("Courier")
 43                            .text_color(gpui3::hsla(1., 1., 1., 1.))
 44                            .child("Hello world")
 45                            .into_any()]
 46                    },
 47                    Box::new(()),
 48                ))
 49                .child(
 50                    div()
 51                        .size_full()
 52                        .h_stack()
 53                        .gap_3()
 54                        .children((0..4).map(|i| {
 55                            div().size_full().flex().fill(gpui3::hsla(
 56                                0. + (i as f32 / 7.),
 57                                0. + (i as f32 / 5.),
 58                                0.5,
 59                                1.,
 60                            ))
 61                        })),
 62                )
 63                .child(
 64                    div()
 65                        .size_full()
 66                        .flex()
 67                        .fill(theme.middle.negative.default.background),
 68                )
 69        })
 70
 71        // themed(rose_pine_dawn(), cx, |cx| {
 72        //     div()
 73        //         .size_full()
 74        //         .flex()
 75        //         .flex_col()
 76        //         .font("Courier")
 77        //         .gap_0()
 78        //         .justify_start()
 79        //         .items_start()
 80        //         .text_color(theme.lowest.base.default.foreground)
 81        //         .fill(theme.middle.base.default.background)
 82        //         .child(titlebar(cx))
 83        //         .child(
 84        //             div()
 85        //                 .flex_1()
 86        //                 .w_full()
 87        //                 .flex()
 88        //                 .flex_row()
 89        //                 .overflow_hidden()
 90        //                 .child(self.left_panel.clone())
 91        //                 .child(div().h_full().flex_1())
 92        //                 .child(self.right_panel.clone()),
 93        //         )
 94        //         .child(statusbar::statusbar(cx))
 95        // })
 96    }
 97}
 98
 99struct Titlebar;
100
101pub fn titlebar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
102    let ref mut this = Titlebar;
103    let theme = theme(cx);
104    div()
105        .flex()
106        .items_center()
107        .justify_between()
108        .w_full()
109        .h_8()
110        .fill(theme.lowest.base.default.background)
111        .child(this.left_group(cx))
112        .child(this.right_group(cx))
113}
114
115impl Titlebar {
116    fn render<V: 'static + Send + Sync>(
117        &mut self,
118        cx: &mut ViewContext<V>,
119    ) -> impl Element<State = V> {
120        let theme = theme(cx);
121        div()
122            .flex()
123            .items_center()
124            .justify_between()
125            .w_full()
126            .h_8()
127            .fill(theme.lowest.base.default.background)
128            .child(self.left_group(cx))
129            .child(self.right_group(cx))
130    }
131
132    fn left_group<S: 'static + Send + Sync>(
133        &mut self,
134        cx: &mut ViewContext<S>,
135    ) -> impl Element<State = S> {
136        let theme = theme(cx);
137        div()
138            .flex()
139            .items_center()
140            .h_full()
141            .gap_4()
142            .px_2()
143            // === Traffic Lights === //
144            .child(
145                div()
146                    .flex()
147                    .items_center()
148                    .gap_2()
149                    .child(
150                        div()
151                            .w_3()
152                            .h_3()
153                            .rounded_full()
154                            .fill(theme.lowest.positive.default.foreground),
155                    )
156                    .child(
157                        div()
158                            .w_3()
159                            .h_3()
160                            .rounded_full()
161                            .fill(theme.lowest.warning.default.foreground),
162                    )
163                    .child(
164                        div()
165                            .w_3()
166                            .h_3()
167                            .rounded_full()
168                            .fill(theme.lowest.negative.default.foreground),
169                    ),
170            )
171            // === Project Info === //
172            .child(
173                div()
174                    .flex()
175                    .items_center()
176                    .gap_1()
177                    .child(
178                        div()
179                            .h_full()
180                            .flex()
181                            .items_center()
182                            .justify_center()
183                            .px_2()
184                            .rounded_md()
185                            .hover()
186                            .fill(theme.lowest.base.hovered.background)
187                            // .active()
188                            // .fill(theme.lowest.base.pressed.background)
189                            .child(div().text_sm().child("project")),
190                    )
191                    .child(
192                        div()
193                            .h_full()
194                            .flex()
195                            .items_center()
196                            .justify_center()
197                            .px_2()
198                            .rounded_md()
199                            .text_color(theme.lowest.variant.default.foreground)
200                            .hover()
201                            .fill(theme.lowest.base.hovered.background)
202                            // .active()
203                            // .fill(theme.lowest.base.pressed.background)
204                            .child(
205                                div()
206                                    .text_sm()
207                                    .text_decoration_1()
208                                    .text_decoration_wavy()
209                                    .child("branch"),
210                            ),
211                    ),
212            )
213    }
214
215    fn right_group<S: 'static + Send + Sync>(
216        &mut self,
217        cx: &mut ViewContext<S>,
218    ) -> impl Element<State = S> {
219        let theme = theme(cx);
220        div()
221            .flex()
222            .items_center()
223            .h_full()
224            .gap_3()
225            .px_2()
226            // === Actions === //
227            .child(
228                div().child(
229                    div().flex().items_center().gap_1().child(
230                        div().size_4().flex().items_center().justify_center().child(
231                            svg()
232                                .path("icons/exit.svg")
233                                .size_4()
234                                .fill(theme.lowest.base.default.foreground),
235                        ),
236                    ),
237                ),
238            )
239            .child(div().w_px().h_3().fill(theme.lowest.base.default.border))
240            // === Comms === //
241            .child(
242                div().child(
243                    div()
244                        .flex()
245                        .items_center()
246                        .gap_px()
247                        .child(
248                            div()
249                                .px_2()
250                                .py_1()
251                                .rounded_md()
252                                .h_full()
253                                .flex()
254                                .items_center()
255                                .justify_center()
256                                .hover()
257                                .fill(theme.lowest.base.hovered.background)
258                                // .active()
259                                // .fill(theme.lowest.base.pressed.background)
260                                .child(
261                                    svg()
262                                        .path("icons/mic.svg")
263                                        .size_3p5()
264                                        .fill(theme.lowest.base.default.foreground),
265                                ),
266                        )
267                        .child(
268                            div()
269                                .px_2()
270                                .py_1()
271                                .rounded_md()
272                                .h_full()
273                                .flex()
274                                .items_center()
275                                .justify_center()
276                                .hover()
277                                .fill(theme.lowest.base.hovered.background)
278                                // .active()
279                                // .fill(theme.lowest.base.pressed.background)
280                                .child(
281                                    svg()
282                                        .path("icons/speaker-loud.svg")
283                                        .size_3p5()
284                                        .fill(theme.lowest.base.default.foreground),
285                                ),
286                        )
287                        .child(
288                            div()
289                                .px_2()
290                                .py_1()
291                                .rounded_md()
292                                .h_full()
293                                .flex()
294                                .items_center()
295                                .justify_center()
296                                .hover()
297                                .fill(theme.lowest.base.hovered.background)
298                                // .active()
299                                // .fill(theme.lowest.base.pressed.background)
300                                .child(
301                                    svg()
302                                        .path("icons/desktop.svg")
303                                        .size_3p5()
304                                        .fill(theme.lowest.base.default.foreground),
305                                ),
306                        ),
307                ),
308            )
309            .child(div().w_px().h_3().fill(theme.lowest.base.default.border))
310            // User Group
311            .child(
312                div().child(
313                    div()
314                        .px_1()
315                        .py_1()
316                        .flex()
317                        .items_center()
318                        .justify_center()
319                        .rounded_md()
320                        .gap_0p5()
321                        .hover()
322                        .fill(theme.lowest.base.hovered.background)
323                        // .active()
324                        // .fill(theme.lowest.base.pressed.background)
325                        .child(
326                            img()
327                                .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
328                                .size_4()
329                                .rounded_md()
330                                .fill(theme.middle.on.default.foreground),
331                        )
332                        .child(
333                            svg()
334                                .path("icons/caret_down.svg")
335                                .w_2()
336                                .h_2()
337                                .fill(theme.lowest.variant.default.foreground),
338                        ),
339                ),
340            )
341    }
342}
343
344// ================================================================================ //
345
346mod statusbar {
347
348    use super::*;
349
350    pub fn statusbar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
351        let theme = theme(cx);
352        div()
353            .flex()
354            .items_center()
355            .justify_between()
356            .w_full()
357            .h_8()
358            .fill(theme.lowest.base.default.background)
359        // .child(left_group(cx))
360        // .child(right_group(cx))
361    }
362
363    fn left_group<V: 'static + Send + Sync>(cx: &mut ViewContext<V>) -> impl Element<State = V> {
364        let theme = theme(cx);
365        div()
366            .flex()
367            .items_center()
368            .h_full()
369            .gap_4()
370            .px_2()
371            // === Tools === //
372            .child(
373                div()
374                    .flex()
375                    .items_center()
376                    .gap_1()
377                    .child(
378                        div()
379                            .w_6()
380                            .h_full()
381                            .flex()
382                            .items_center()
383                            .justify_center()
384                            .child(
385                                svg()
386                                    .path("icons/project.svg")
387                                    .w_4()
388                                    .h_4()
389                                    .fill(theme.lowest.base.default.foreground),
390                            ),
391                    )
392                    .child(
393                        div()
394                            .w_6()
395                            .h_full()
396                            .flex()
397                            .items_center()
398                            .justify_center()
399                            .child(
400                                svg()
401                                    .path("icons/conversations.svg")
402                                    .w_4()
403                                    .h_4()
404                                    .fill(theme.lowest.base.default.foreground),
405                            ),
406                    )
407                    .child(
408                        div()
409                            .w_6()
410                            .h_full()
411                            .flex()
412                            .items_center()
413                            .justify_center()
414                            .child(
415                                svg()
416                                    .path("icons/file_icons/notebook.svg")
417                                    .w_4()
418                                    .h_4()
419                                    .fill(theme.lowest.accent.default.foreground),
420                            ),
421                    ),
422            )
423            // === Diagnostics === //
424            .child(
425                div()
426                    .flex()
427                    .items_center()
428                    .gap_2()
429                    .child(
430                        div()
431                            .h_full()
432                            .flex()
433                            .items_center()
434                            .justify_center()
435                            .gap_0p5()
436                            .px_1()
437                            .text_color(theme.lowest.variant.default.foreground)
438                            .hover()
439                            .fill(theme.lowest.base.hovered.background)
440                            // .active()
441                            // .fill(theme.lowest.base.pressed.background)
442                            .child(
443                                svg()
444                                    .path("icons/error.svg")
445                                    .w_4()
446                                    .h_4()
447                                    .fill(theme.lowest.negative.default.foreground),
448                            )
449                            .child(div().text_sm().child("2")),
450                    )
451                    .child(
452                        div()
453                            .text_sm()
454                            .text_color(theme.lowest.variant.default.foreground)
455                            .child("Something is wrong"),
456                    ),
457            )
458    }
459
460    fn right_group<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
461        let theme = theme(cx);
462        div()
463            .flex()
464            .items_center()
465            .h_full()
466            .gap_4()
467            .px_2()
468            // === Tools === //
469            .child(
470                div()
471                    .flex()
472                    .items_center()
473                    .gap_1()
474                    .child(
475                        div()
476                            .w_6()
477                            .h_full()
478                            .flex()
479                            .items_center()
480                            .justify_center()
481                            .child(
482                                svg()
483                                    .path("icons/check_circle.svg")
484                                    .w_4()
485                                    .h_4()
486                                    .fill(theme.lowest.base.default.foreground),
487                            ),
488                    )
489                    .child(
490                        div()
491                            .w_6()
492                            .h_full()
493                            .flex()
494                            .items_center()
495                            .justify_center()
496                            .child(
497                                svg()
498                                    .path("icons/copilot.svg")
499                                    .w_4()
500                                    .h_4()
501                                    .fill(theme.lowest.accent.default.foreground),
502                            ),
503                    ),
504            )
505    }
506}