diff --git a/crates/git_graph/src/git_graph.rs b/crates/git_graph/src/git_graph.rs index 370da2a8394f396138d5584d661488f75c3cf1ba..1d06ecb1c49fd05c2412c75c1cc6dd36eff84d9a 100644 --- a/crates/git_graph/src/git_graph.rs +++ b/crates/git_graph/src/git_graph.rs @@ -1184,11 +1184,33 @@ impl GitGraph { git_store.repositories().get(&self.repo_id).cloned() } - fn render_chip(&self, name: &SharedString, accent_color: gpui::Hsla) -> impl IntoElement { + /// Checks whether a ref name from git's `%D` decoration + /// format refers to the currently checked-out branch. + fn is_head_ref(ref_name: &str, head_branch_name: &Option) -> bool { + head_branch_name.as_ref().is_some_and(|head| { + ref_name == head.as_ref() || ref_name.strip_prefix("HEAD -> ") == Some(head.as_ref()) + }) + } + + fn render_chip( + &self, + name: &SharedString, + accent_color: gpui::Hsla, + is_head: bool, + ) -> impl IntoElement { Chip::new(name.clone()) .label_size(LabelSize::Small) - .bg_color(accent_color.opacity(0.1)) - .border_color(accent_color.opacity(0.5)) + .truncate() + .map(|chip| { + if is_head { + chip.icon(IconName::Check) + .bg_color(accent_color.opacity(0.25)) + .border_color(accent_color.opacity(0.5)) + } else { + chip.bg_color(accent_color.opacity(0.08)) + .border_color(accent_color.opacity(0.25)) + } + }) } fn render_table_rows( @@ -1199,6 +1221,14 @@ impl GitGraph { ) -> Vec> { let repository = self.get_repository(cx); + let head_branch_name: Option = repository.as_ref().and_then(|repo| { + repo.read(cx) + .snapshot() + .branch + .as_ref() + .map(|branch| SharedString::from(branch.name().to_string())) + }); + let row_height = self.row_height; // We fetch data outside the visible viewport to avoid loading entries when @@ -1311,13 +1341,13 @@ impl GitGraph { .gap_2() .overflow_hidden() .children((!commit.data.ref_names.is_empty()).then(|| { - h_flex().gap_1().children( - commit - .data - .ref_names - .iter() - .map(|name| self.render_chip(name, accent_color)), - ) + h_flex().gap_1().children(commit.data.ref_names.iter().map( + |name| { + let is_head = + Self::is_head_ref(name.as_ref(), &head_branch_name); + self.render_chip(name, accent_color, is_head) + }, + )) })) .child(subject_label), ) @@ -1652,7 +1682,7 @@ impl GitGraph { .px_1p5() .gap_1() .border_1() - .border_color(color.border) + .border_color(color.border_variant) .rounded_md() .bg(color.toolbar_background) .on_action(cx.listener(Self::confirm_search)) @@ -1784,6 +1814,13 @@ impl GitGraph { let full_sha: SharedString = commit_entry.data.sha.to_string().into(); let ref_names = commit_entry.data.ref_names.clone(); + let head_branch_name: Option = repository + .read(cx) + .snapshot() + .branch + .as_ref() + .map(|branch| SharedString::from(branch.name().to_string())); + let accent_colors = cx.theme().accents(); let accent_color = accent_colors .0 @@ -1855,7 +1892,7 @@ impl GitGraph { v_flex() .min_w(px(300.)) .h_full() - .bg(cx.theme().colors().surface_background) + .bg(cx.theme().colors().editor_background) .flex_basis(DefiniteLength::Fraction( self.commit_details_split_state.read(cx).right_ratio(), )) @@ -1898,9 +1935,10 @@ impl GitGraph { ) .children((!ref_names.is_empty()).then(|| { h_flex().gap_1().flex_wrap().justify_center().children( - ref_names - .iter() - .map(|name| self.render_chip(name, accent_color)), + ref_names.iter().map(|name| { + let is_head = Self::is_head_ref(name.as_ref(), &head_branch_name); + self.render_chip(name, accent_color, is_head) + }), ) })) .child( @@ -2059,6 +2097,8 @@ impl GitGraph { .child( h_flex() .gap_1() + .w_full() + .justify_between() .child( Label::new(format!("{} Changed Files", changed_files_count)) .size(LabelSize::Small) @@ -2110,7 +2150,7 @@ impl GitGraph { h_flex().p_1p5().w_full().child( Button::new("view-commit", "View Commit") .full_width() - .style(ButtonStyle::Outlined) + .style(ButtonStyle::OutlinedGhost) .on_click(cx.listener(|this, _, window, cx| { this.open_selected_commit_view(window, cx); })), diff --git a/crates/ui/src/components/chip.rs b/crates/ui/src/components/chip.rs index 06dc7e6afa6fa8723985913dfece4205e360511e..bcb21fb379c1d587a58e29e87635765f694e41df 100644 --- a/crates/ui/src/components/chip.rs +++ b/crates/ui/src/components/chip.rs @@ -15,9 +15,12 @@ pub struct Chip { label: SharedString, label_color: Color, label_size: LabelSize, + icon: Option, + icon_color: Color, bg_color: Option, border_color: Option, height: Option, + truncate: bool, tooltip: Option AnyView + 'static>>, } @@ -28,9 +31,12 @@ impl Chip { label: label.into(), label_color: Color::Default, label_size: LabelSize::XSmall, + icon: None, + icon_color: Color::Default, bg_color: None, border_color: None, height: None, + truncate: false, tooltip: None, } } @@ -47,6 +53,18 @@ impl Chip { self } + /// Sets an icon to display before the label. + pub fn icon(mut self, icon: IconName) -> Self { + self.icon = Some(icon); + self + } + + /// Sets the color of the icon. + pub fn icon_color(mut self, color: Color) -> Self { + self.icon_color = color; + self + } + /// Sets a custom background color for the callout content. pub fn bg_color(mut self, color: Hsla) -> Self { self.bg_color = Some(color); @@ -65,6 +83,12 @@ impl Chip { self } + /// Allows the chip to shrink and truncate its label when space is limited. + pub fn truncate(mut self) -> Self { + self.truncate = true; + self + } + pub fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self { self.tooltip = Some(Box::new(tooltip)); self @@ -81,13 +105,22 @@ impl RenderOnce for Chip { h_flex() .when_some(self.height, |this, h| this.h(h)) - .flex_none() + .when(self.truncate, |this| this.min_w_0()) + .when(!self.truncate, |this| this.flex_none()) + .gap_0p5() .px_1() .border_1() .rounded_sm() .border_color(border_color) .bg(bg_color) .overflow_hidden() + .when_some(self.icon, |this, icon| { + this.child( + Icon::new(icon) + .size(IconSize::XSmall) + .color(self.icon_color), + ) + }) .child( Label::new(self.label.clone()) .size(self.label_size)