1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use chrono::DateTime;
5use gpui3::{relative, rems, Size};
6
7use crate::prelude::*;
8use crate::{
9 hello_world_rust_editor_with_status_example, random_players_with_call_status, theme, v_stack,
10 ChatMessage, ChatPanel, EditorPane, Label, Livestream, Pane, PaneGroup, Panel,
11 PanelAllowedSides, PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar,
12 Toast, ToastOrigin,
13};
14
15#[derive(Element)]
16pub struct WorkspaceElement<S: 'static + Send + Sync + Clone> {
17 state_type: PhantomData<S>,
18 left_panel_scroll_state: ScrollState,
19 right_panel_scroll_state: ScrollState,
20 tab_bar_scroll_state: ScrollState,
21 bottom_panel_scroll_state: ScrollState,
22}
23
24impl<S: 'static + Send + Sync + Clone> WorkspaceElement<S> {
25 pub fn new() -> Self {
26 Self {
27 state_type: PhantomData,
28 left_panel_scroll_state: ScrollState::default(),
29 right_panel_scroll_state: ScrollState::default(),
30 tab_bar_scroll_state: ScrollState::default(),
31 bottom_panel_scroll_state: ScrollState::default(),
32 }
33 }
34
35 pub fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
36 let theme = theme(cx).clone();
37
38 let temp_size = rems(36.).into();
39
40 let root_group = PaneGroup::new_groups(
41 vec![
42 PaneGroup::new_panes(
43 vec![
44 Pane::new(
45 ScrollState::default(),
46 Size {
47 width: relative(1.).into(),
48 height: temp_size,
49 },
50 |_, payload| {
51 let theme = payload.downcast_ref::<Arc<Theme>>().unwrap();
52
53 vec![EditorPane::new(hello_world_rust_editor_with_status_example(
54 &theme,
55 ))
56 .into_any()]
57 },
58 Box::new(theme.clone()),
59 ),
60 Pane::new(
61 ScrollState::default(),
62 Size {
63 width: relative(1.).into(),
64 height: temp_size,
65 },
66 |_, _| vec![Terminal::new().into_any()],
67 Box::new(()),
68 ),
69 ],
70 SplitDirection::Vertical,
71 ),
72 PaneGroup::new_panes(
73 vec![Pane::new(
74 ScrollState::default(),
75 Size {
76 width: relative(1.).into(),
77 height: relative(1.).into(),
78 },
79 |_, payload| {
80 let theme = payload.downcast_ref::<Arc<Theme>>().unwrap();
81
82 vec![EditorPane::new(hello_world_rust_editor_with_status_example(
83 &theme,
84 ))
85 .into_any()]
86 },
87 Box::new(theme.clone()),
88 )],
89 SplitDirection::Vertical,
90 ),
91 ],
92 SplitDirection::Horizontal,
93 );
94
95 div()
96 .relative()
97 .size_full()
98 .flex()
99 .flex_col()
100 .font("Zed Sans Extended")
101 .gap_0()
102 .justify_start()
103 .items_start()
104 .text_color(theme.lowest.base.default.foreground)
105 .fill(theme.lowest.base.default.background)
106 .child(TitleBar::new(cx).set_livestream(Some(Livestream {
107 players: random_players_with_call_status(7),
108 channel: Some("gpui2-ui".to_string()),
109 })))
110 .child(
111 div()
112 .flex_1()
113 .w_full()
114 .flex()
115 .flex_row()
116 .overflow_hidden()
117 .border_t()
118 .border_b()
119 .border_color(theme.lowest.base.default.border)
120 .child(
121 Panel::new(
122 self.left_panel_scroll_state.clone(),
123 |_, payload| vec![ProjectPanel::new(ScrollState::default()).into_any()],
124 Box::new(()),
125 )
126 .side(PanelSide::Left),
127 )
128 .child(
129 v_stack()
130 .flex_1()
131 .h_full()
132 .child(
133 div()
134 .flex()
135 .flex_1()
136 // CSS Hack: Flex 1 has to have a set height to properly fill the space
137 // Or it will give you a height of 0
138 // Marshall: We may not need this anymore with `gpui3`. It seems to render
139 // fine without it.
140 .h_px()
141 .child(root_group),
142 )
143 .child(
144 Panel::new(
145 self.bottom_panel_scroll_state.clone(),
146 |_, _| vec![Terminal::new().into_any()],
147 Box::new(()),
148 )
149 .allowed_sides(PanelAllowedSides::BottomOnly)
150 .side(PanelSide::Bottom),
151 ),
152 )
153 .child(
154 Panel::new(
155 self.right_panel_scroll_state.clone(),
156 |_, payload| {
157 vec![ChatPanel::new(ScrollState::default())
158 .with_messages(vec![
159 ChatMessage::new(
160 "osiewicz".to_string(),
161 "is this thing on?".to_string(),
162 DateTime::parse_from_rfc3339(
163 "2023-09-27T15:40:52.707Z",
164 )
165 .unwrap()
166 .naive_local(),
167 ),
168 ChatMessage::new(
169 "maxdeviant".to_string(),
170 "Reading you loud and clear!".to_string(),
171 DateTime::parse_from_rfc3339(
172 "2023-09-28T15:40:52.707Z",
173 )
174 .unwrap()
175 .naive_local(),
176 ),
177 ])
178 .into_any()]
179 },
180 Box::new(()),
181 )
182 .side(PanelSide::Right),
183 ),
184 )
185 .child(StatusBar::new())
186 .child(Toast::new(
187 ToastOrigin::Bottom,
188 |_, _| vec![Label::new("A toast").into_any()],
189 Box::new(()),
190 ))
191 .child(Toast::new(
192 ToastOrigin::BottomRight,
193 |_, _| vec![Label::new("Another toast").into_any()],
194 Box::new(()),
195 ))
196 }
197}