1use gpui::*;
2use ui::{prelude::*, Checkbox, Divider, DividerColor, ElevationIndex};
3use workspace::dock::{DockPosition, Panel, PanelEvent};
4use workspace::Workspace;
5
6pub fn init(cx: &mut AppContext) {
7 cx.observe_new_views(
8 |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
9 workspace.register_action(|workspace, _: &ToggleFocus, cx| {
10 workspace.toggle_panel_focus::<GitPanel>(cx);
11 });
12 },
13 )
14 .detach();
15}
16
17actions!(git_panel, [Deploy, ToggleFocus]);
18
19#[derive(Clone)]
20pub struct GitPanel {
21 _workspace: WeakView<Workspace>,
22 focus_handle: FocusHandle,
23 width: Option<Pixels>,
24}
25
26impl GitPanel {
27 pub fn load(
28 workspace: WeakView<Workspace>,
29 cx: AsyncWindowContext,
30 ) -> Task<Result<View<Self>>> {
31 cx.spawn(|mut cx| async move {
32 workspace.update(&mut cx, |workspace, cx| {
33 let workspace_handle = workspace.weak_handle();
34
35 cx.new_view(|cx| Self::new(workspace_handle, cx))
36 })
37 })
38 }
39
40 pub fn new(workspace: WeakView<Workspace>, cx: &mut ViewContext<Self>) -> Self {
41 Self {
42 _workspace: workspace,
43 focus_handle: cx.focus_handle(),
44 width: Some(px(360.)),
45 }
46 }
47
48 pub fn render_panel_header(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
49 h_flex()
50 .h(px(32.))
51 .items_center()
52 .px_3()
53 .bg(ElevationIndex::Surface.bg(cx))
54 .child(
55 h_flex()
56 .gap_1()
57 .child(Checkbox::new("all-changes", true.into()).disabled(true))
58 .child(div().text_buffer(cx).text_ui_sm(cx).child("0 changes")),
59 )
60 .child(div().flex_grow())
61 .child(
62 h_flex()
63 .gap_1()
64 .child(
65 IconButton::new("discard-changes", IconName::Undo)
66 .icon_size(IconSize::Small)
67 .disabled(true),
68 )
69 .child(
70 Button::new("stage-all", "Stage All")
71 .label_size(LabelSize::Small)
72 .layer(ElevationIndex::ElevatedSurface)
73 .size(ButtonSize::Compact)
74 .style(ButtonStyle::Filled)
75 .disabled(true),
76 ),
77 )
78 }
79
80 pub fn render_commit_editor(&self, cx: &ViewContext<Self>) -> impl IntoElement {
81 div().w_full().h(px(140.)).px_2().pt_1().pb_2().child(
82 v_flex()
83 .h_full()
84 .py_2p5()
85 .px_3()
86 .bg(cx.theme().colors().editor_background)
87 .font_buffer(cx)
88 .text_ui_sm(cx)
89 .text_color(cx.theme().colors().text_muted)
90 .child("Add a message")
91 .gap_1()
92 .child(div().flex_grow())
93 .child(
94 h_flex().child(div().gap_1().flex_grow()).child(
95 Button::new("commit", "Commit")
96 .label_size(LabelSize::Small)
97 .layer(ElevationIndex::ElevatedSurface)
98 .size(ButtonSize::Compact)
99 .style(ButtonStyle::Filled)
100 .disabled(true),
101 ),
102 )
103 .cursor(CursorStyle::OperationNotAllowed)
104 .opacity(0.5),
105 )
106 }
107}
108
109impl Render for GitPanel {
110 fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
111 v_flex()
112 .key_context("GitPanel")
113 .font_buffer(cx)
114 .py_1()
115 .id("git_panel")
116 .track_focus(&self.focus_handle)
117 .size_full()
118 .overflow_hidden()
119 .bg(ElevationIndex::Surface.bg(cx))
120 .child(self.render_panel_header(cx))
121 .child(
122 h_flex()
123 .items_center()
124 .h(px(8.))
125 .child(Divider::horizontal_dashed().color(DividerColor::Border)),
126 )
127 .child(div().flex_1())
128 .child(
129 h_flex()
130 .items_center()
131 .h(px(8.))
132 .child(Divider::horizontal_dashed().color(DividerColor::Border)),
133 )
134 .child(self.render_commit_editor(cx))
135 }
136}
137
138impl FocusableView for GitPanel {
139 fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle {
140 self.focus_handle.clone()
141 }
142}
143
144impl EventEmitter<PanelEvent> for GitPanel {}
145
146impl Panel for GitPanel {
147 fn persistent_name() -> &'static str {
148 "GitPanel"
149 }
150
151 fn position(&self, _cx: &gpui::WindowContext) -> DockPosition {
152 DockPosition::Left
153 }
154
155 fn position_is_valid(&self, position: DockPosition) -> bool {
156 matches!(position, DockPosition::Left | DockPosition::Right)
157 }
158
159 fn set_position(&mut self, _position: DockPosition, _cx: &mut ViewContext<Self>) {}
160
161 fn size(&self, _cx: &gpui::WindowContext) -> Pixels {
162 self.width.unwrap_or(px(360.))
163 }
164
165 fn set_size(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>) {
166 self.width = size;
167 cx.notify();
168 }
169
170 fn icon(&self, _cx: &gpui::WindowContext) -> Option<ui::IconName> {
171 Some(ui::IconName::GitBranch)
172 }
173
174 fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> {
175 Some("Git Panel")
176 }
177
178 fn toggle_action(&self) -> Box<dyn Action> {
179 Box::new(ToggleFocus)
180 }
181}