1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use crate::prelude::*;
5use crate::{get_workspace_state, Button, Icon, IconButton, IconColor, ToolDivider};
6
7#[derive(Default, PartialEq)]
8pub enum Tool {
9 #[default]
10 ProjectPanel,
11 CollaborationPanel,
12 Terminal,
13 Assistant,
14 Feedback,
15 Diagnostics,
16}
17
18struct ToolGroup {
19 active_index: Option<usize>,
20 tools: Vec<Tool>,
21}
22
23impl Default for ToolGroup {
24 fn default() -> Self {
25 ToolGroup {
26 active_index: None,
27 tools: vec![],
28 }
29 }
30}
31
32#[derive(Element)]
33pub struct StatusBar<S: 'static + Send + Sync + Clone> {
34 state_type: PhantomData<S>,
35 left_tools: Option<ToolGroup>,
36 right_tools: Option<ToolGroup>,
37 bottom_tools: Option<ToolGroup>,
38}
39
40impl<S: 'static + Send + Sync + Clone> StatusBar<S> {
41 pub fn new() -> Self {
42 Self {
43 state_type: PhantomData,
44 left_tools: None,
45 right_tools: None,
46 bottom_tools: None,
47 }
48 }
49
50 pub fn left_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
51 self.left_tools = {
52 let mut tools = vec![tool];
53 tools.extend(self.left_tools.take().unwrap_or_default().tools);
54 Some(ToolGroup {
55 active_index,
56 tools,
57 })
58 };
59 self
60 }
61
62 pub fn right_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
63 self.right_tools = {
64 let mut tools = vec![tool];
65 tools.extend(self.left_tools.take().unwrap_or_default().tools);
66 Some(ToolGroup {
67 active_index,
68 tools,
69 })
70 };
71 self
72 }
73
74 pub fn bottom_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
75 self.bottom_tools = {
76 let mut tools = vec![tool];
77 tools.extend(self.left_tools.take().unwrap_or_default().tools);
78 Some(ToolGroup {
79 active_index,
80 tools,
81 })
82 };
83 self
84 }
85
86 fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
87 let theme = theme(cx);
88
89 div()
90 .py_0p5()
91 .px_1()
92 .flex()
93 .items_center()
94 .justify_between()
95 .w_full()
96 .fill(theme.lowest.base.default.background)
97 .child(self.left_tools(&theme))
98 .child(self.right_tools(&theme))
99 }
100
101 fn left_tools(&self, theme: &Theme) -> impl Element<ViewState = S> {
102 let workspace_state = get_workspace_state();
103
104 div()
105 .flex()
106 .items_center()
107 .gap_1()
108 .child(
109 IconButton::new(Icon::FileTree)
110 .when(workspace_state.is_project_panel_open(), |this| {
111 this.color(IconColor::Accent)
112 })
113 .on_click(|_, cx| {
114 workspace_state.toggle_project_panel();
115 cx.notify();
116 }),
117 )
118 .child(
119 IconButton::new(Icon::Hash)
120 .when(workspace_state.is_collab_panel_open(), |this| {
121 this.color(IconColor::Accent)
122 })
123 .on_click(|_, cx| {
124 workspace_state.toggle_collab_panel();
125 cx.notify();
126 }),
127 )
128 .child(ToolDivider::new())
129 .child(IconButton::new(Icon::XCircle))
130 }
131
132 fn right_tools(&self, theme: &Theme) -> impl Element<ViewState = S> {
133 let workspace_state = get_workspace_state();
134
135 div()
136 .flex()
137 .items_center()
138 .gap_2()
139 .child(
140 div()
141 .flex()
142 .items_center()
143 .gap_1()
144 .child(Button::new("116:25"))
145 .child(Button::new("Rust").on_click(Arc::new(|_, cx| {
146 workspace_state.toggle_language_selector();
147 cx.notify();
148 }))),
149 )
150 .child(ToolDivider::new())
151 .child(
152 div()
153 .flex()
154 .items_center()
155 .gap_1()
156 .child(
157 IconButton::new(Icon::Copilot)
158 .on_click(|_, _| println!("Copilot clicked.")),
159 )
160 .child(
161 IconButton::new(Icon::Envelope)
162 .on_click(|_, _| println!("Send Feedback clicked.")),
163 ),
164 )
165 .child(ToolDivider::new())
166 .child(
167 div()
168 .flex()
169 .items_center()
170 .gap_1()
171 .child(
172 IconButton::new(Icon::Terminal)
173 .when(workspace_state.is_terminal_open(), |this| {
174 this.color(IconColor::Accent)
175 })
176 .on_click(|_, cx| {
177 workspace_state.toggle_terminal();
178 cx.notify();
179 }),
180 )
181 .child(
182 IconButton::new(Icon::MessageBubbles)
183 .when(workspace_state.is_chat_panel_open(), |this| {
184 this.color(IconColor::Accent)
185 })
186 .on_click(|_, cx| {
187 workspace_state.toggle_chat_panel();
188 cx.notify();
189 }),
190 )
191 .child(
192 IconButton::new(Icon::Ai)
193 .when(workspace_state.is_assistant_panel_open(), |this| {
194 this.color(IconColor::Accent)
195 })
196 .on_click(|_, cx| {
197 workspace_state.toggle_assistant_panel();
198 cx.notify();
199 }),
200 ),
201 )
202 }
203}