1use std::marker::PhantomData;
2
3use gpui2::style::StyleHelpers;
4use gpui2::{elements::div, IntoElement};
5use gpui2::{Element, ParentElement, ViewContext};
6
7use crate::theme::{theme, Theme};
8use crate::{icon_button, text_button, tool_divider, IconAsset};
9
10#[derive(Default, PartialEq)]
11pub enum Tool {
12 #[default]
13 ProjectPanel,
14 CollaborationPanel,
15 Terminal,
16 Assistant,
17 Feedback,
18 Diagnostics,
19}
20
21struct ToolGroup {
22 active_index: Option<usize>,
23 tools: Vec<Tool>,
24}
25
26impl Default for ToolGroup {
27 fn default() -> Self {
28 ToolGroup {
29 active_index: None,
30 tools: vec![],
31 }
32 }
33}
34
35#[derive(Element)]
36pub struct StatusBar<V: 'static> {
37 view_type: PhantomData<V>,
38 left_tools: Option<ToolGroup>,
39 right_tools: Option<ToolGroup>,
40 bottom_tools: Option<ToolGroup>,
41}
42
43pub fn status_bar<V: 'static>() -> StatusBar<V> {
44 StatusBar {
45 view_type: PhantomData,
46 left_tools: None,
47 right_tools: None,
48 bottom_tools: None,
49 }
50}
51
52impl<V: 'static> StatusBar<V> {
53 pub fn left_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
54 self.left_tools = {
55 let mut tools = vec![tool];
56 tools.extend(self.left_tools.take().unwrap_or_default().tools);
57 Some(ToolGroup {
58 active_index,
59 tools,
60 })
61 };
62 self
63 }
64
65 pub fn right_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
66 self.right_tools = {
67 let mut tools = vec![tool];
68 tools.extend(self.left_tools.take().unwrap_or_default().tools);
69 Some(ToolGroup {
70 active_index,
71 tools,
72 })
73 };
74 self
75 }
76
77 pub fn bottom_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
78 self.bottom_tools = {
79 let mut tools = vec![tool];
80 tools.extend(self.left_tools.take().unwrap_or_default().tools);
81 Some(ToolGroup {
82 active_index,
83 tools,
84 })
85 };
86 self
87 }
88
89 fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
90 let theme = theme(cx);
91
92 div()
93 .py_0p5()
94 .px_1()
95 .flex()
96 .items_center()
97 .justify_between()
98 .w_full()
99 .fill(theme.lowest.base.default.background)
100 .child(self.left_tools(&theme))
101 .child(self.right_tools(&theme))
102 }
103
104 fn left_tools(&self, theme: &Theme) -> impl Element<V> {
105 div()
106 .flex()
107 .items_center()
108 .gap_1()
109 .child(icon_button().icon(IconAsset::FileTree))
110 .child(icon_button().icon(IconAsset::Hash))
111 .child(tool_divider())
112 .child(icon_button().icon(IconAsset::XCircle))
113 }
114 fn right_tools(&self, theme: &Theme) -> impl Element<V> {
115 div()
116 .flex()
117 .items_center()
118 .gap_2()
119 .child(
120 div()
121 .flex()
122 .items_center()
123 .gap_1()
124 .child(text_button("116:25"))
125 .child(text_button("Rust")),
126 )
127 .child(tool_divider())
128 .child(
129 div()
130 .flex()
131 .items_center()
132 .gap_1()
133 .child(icon_button().icon(IconAsset::Copilot))
134 .child(icon_button().icon(IconAsset::Envelope)),
135 )
136 .child(tool_divider())
137 .child(
138 div()
139 .flex()
140 .items_center()
141 .gap_1()
142 .child(icon_button().icon(IconAsset::Terminal))
143 .child(icon_button().icon(IconAsset::MessageBubbles))
144 .child(icon_button().icon(IconAsset::Ai)),
145 )
146 }
147}