Detailed changes
@@ -41,7 +41,8 @@ use language_model::{
use menu::{Confirm, SecondaryConfirm, SelectFirst, SelectLast, SelectNext, SelectPrevious};
use multi_buffer::ExcerptInfo;
use panel::{
- panel_editor_container, panel_editor_style, panel_filled_button, panel_icon_button, PanelHeader,
+ panel_button, panel_editor_container, panel_editor_style, panel_filled_button,
+ panel_icon_button, PanelHeader,
};
use project::{
git::{GitEvent, Repository},
@@ -103,13 +104,13 @@ enum TrashCancel {
}
fn git_panel_context_menu(
- focus_handle: Option<FocusHandle>,
+ focus_handle: FocusHandle,
window: &mut Window,
cx: &mut App,
) -> Entity<ContextMenu> {
ContextMenu::build(window, cx, |context_menu, _, _| {
context_menu
- .when_some(focus_handle, |el, focus_handle| el.context(focus_handle))
+ .context(focus_handle)
.action("Stage All", StageAll.boxed_clone())
.action("Unstage All", UnstageAll.boxed_clone())
.separator()
@@ -2309,6 +2310,18 @@ impl GitPanel {
self.has_staged_changes()
}
+ fn render_overflow_menu(&self, id: impl Into<ElementId>) -> impl IntoElement {
+ let focus_handle = self.focus_handle.clone();
+ PopoverMenu::new(id.into())
+ .trigger(
+ IconButton::new("overflow-menu-trigger", IconName::EllipsisVertical)
+ .icon_size(IconSize::Small)
+ .icon_color(Color::Muted),
+ )
+ .menu(move |window, cx| Some(git_panel_context_menu(focus_handle.clone(), window, cx)))
+ .anchor(Corner::TopRight)
+ }
+
pub(crate) fn render_generate_commit_message_button(
&self,
cx: &Context<Self>,
@@ -2458,9 +2471,17 @@ impl GitPanel {
tooltip = "git add --all ."
}
+ let change_string = match self.entry_count {
+ 0 => "No Changes".to_string(),
+ 1 => "1 Change".to_string(),
+ _ => format!("{} Changes", self.entry_count),
+ };
+
self.panel_header_container(window, cx)
+ .px_2()
.child(
- Button::new("diff", "Open Diff")
+ panel_button(change_string)
+ .color(Color::Muted)
.tooltip(Tooltip::for_action_title_in(
"Open diff",
&Diff,
@@ -2473,8 +2494,9 @@ impl GitPanel {
}),
)
.child(div().flex_grow()) // spacer
+ .child(self.render_overflow_menu("overflow_menu"))
.child(
- Button::new("stage-unstage-all", text)
+ panel_filled_button(text)
.tooltip(Tooltip::for_action_title_in(
tooltip,
action.as_ref(),
@@ -2631,15 +2653,14 @@ impl GitPanel {
.items_center()
.py_2()
.px(px(8.))
- // .bg(cx.theme().colors().background)
- // .border_t_1()
.border_color(cx.theme().colors().border)
.gap_1p5()
.child(
div()
.flex_grow()
.overflow_hidden()
- .max_w(relative(0.6))
+ .items_center()
+ .max_w(relative(0.85))
.h_full()
.child(
Label::new(commit.subject.clone())
@@ -2946,7 +2967,7 @@ impl GitPanel {
window: &mut Window,
cx: &mut Context<Self>,
) {
- let context_menu = git_panel_context_menu(Some(self.focus_handle.clone()), window, cx);
+ let context_menu = git_panel_context_menu(self.focus_handle.clone(), window, cx);
self.set_context_menu(context_menu, position, window, cx);
}
@@ -2993,6 +3014,9 @@ impl GitPanel {
let marked = self.marked_entries.contains(&ix);
let status_style = GitPanelSettings::get_global(cx).status_style;
let status = entry.status;
+ let modifiers = self.current_modifiers;
+ let shift_held = modifiers.shift;
+
let has_conflict = status.is_conflicted();
let is_modified = status.is_modified();
let is_deleted = status.is_deleted();
@@ -3078,7 +3102,7 @@ impl GitPanel {
.px(rems(0.75)) // ~12px
.overflow_hidden()
.flex_none()
- .gap(DynamicSpacing::Base04.rems(cx))
+ .gap_1p5()
.bg(base_bg)
.hover(|this| this.bg(hover_bg))
.active(|this| this.bg(active_bg))
@@ -3123,6 +3147,7 @@ impl GitPanel {
.flex_none()
.occlude()
.cursor_pointer()
+ .ml_neg_0p5()
.child(
Checkbox::new(checkbox_id, is_staged)
.disabled(!has_write_access)
@@ -3144,17 +3169,35 @@ impl GitPanel {
})
})
.tooltip(move |window, cx| {
- let tooltip_name = if entry_staging.is_fully_staged() {
- "Unstage"
+ let is_staged = entry_staging.is_fully_staged();
+
+ let action = if is_staged { "Unstage" } else { "Stage" };
+ let tooltip_name = if shift_held {
+ format!("{} section", action)
} else {
- "Stage"
+ action.to_string()
};
- Tooltip::for_action(tooltip_name, &ToggleStaged, window, cx)
+ let meta = if shift_held {
+ format!(
+ "Release shift to {} single entry",
+ action.to_lowercase()
+ )
+ } else {
+ format!("Shift click to {} section", action.to_lowercase())
+ };
+
+ Tooltip::with_meta(
+ tooltip_name,
+ Some(&ToggleStaged),
+ meta,
+ window,
+ cx,
+ )
}),
),
)
- .child(git_status_icon(status, cx))
+ .child(git_status_icon(status))
.child(
h_flex()
.items_center()
@@ -3456,27 +3499,11 @@ impl PanelRepoFooter {
git_panel: None,
}
}
-
- fn render_overflow_menu(&self, id: impl Into<ElementId>, cx: &App) -> impl IntoElement {
- let focus_handle = self
- .git_panel
- .as_ref()
- .map(|git_panel| git_panel.focus_handle(cx));
- PopoverMenu::new(id.into())
- .trigger(
- IconButton::new("overflow-menu-trigger", IconName::EllipsisVertical)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted),
- )
- .menu(move |window, cx| Some(git_panel_context_menu(focus_handle.clone(), window, cx)))
- .anchor(Corner::TopRight)
- }
}
impl RenderOnce for PanelRepoFooter {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let active_repo = self.active_repository.clone();
- let overflow_menu_id: SharedString = format!("overflow-menu-{}", active_repo).into();
let repo_selector_trigger = Button::new("repo-selector", active_repo)
.style(ButtonStyle::Transparent)
.size(ButtonSize::None)
@@ -3565,7 +3592,11 @@ impl RenderOnce for PanelRepoFooter {
div().child(
Icon::new(IconName::GitBranchSmall)
.size(IconSize::Small)
- .color(Color::Muted),
+ .color(if single_repo {
+ Color::Disabled
+ } else {
+ Color::Muted
+ }),
),
)
.child(repo_selector)
@@ -3584,7 +3615,6 @@ impl RenderOnce for PanelRepoFooter {
.gap_1()
.flex_shrink_0()
.children(spinner)
- .child(self.render_overflow_menu(overflow_menu_id, cx))
.when_some(branch, |this, branch| {
let mut focus_handle = None;
if let Some(git_panel) = self.git_panel.as_ref() {
@@ -1,13 +1,13 @@
use ::settings::Settings;
use git::{
repository::{Branch, Upstream, UpstreamTracking, UpstreamTrackingStatus},
- status::FileStatus,
+ status::{FileStatus, StatusCode, UnmergedStatus, UnmergedStatusCode},
};
use git_panel_settings::GitPanelSettings;
use gpui::{App, Entity, FocusHandle};
use project::Project;
use project_diff::ProjectDiff;
-use ui::{ActiveTheme, Color, Icon, IconName, IntoElement, SharedString};
+use ui::prelude::*;
use workspace::Workspace;
mod askpass_modal;
@@ -86,30 +86,8 @@ pub fn init(cx: &mut App) {
.detach();
}
-// TODO: Add updated status colors to theme
-pub fn git_status_icon(status: FileStatus, cx: &App) -> impl IntoElement {
- let (icon_name, color) = if status.is_conflicted() {
- (
- IconName::Warning,
- cx.theme().colors().version_control_conflict,
- )
- } else if status.is_deleted() {
- (
- IconName::SquareMinus,
- cx.theme().colors().version_control_deleted,
- )
- } else if status.is_modified() {
- (
- IconName::SquareDot,
- cx.theme().colors().version_control_modified,
- )
- } else {
- (
- IconName::SquarePlus,
- cx.theme().colors().version_control_added,
- )
- };
- Icon::new(icon_name).color(Color::Custom(color))
+pub fn git_status_icon(status: FileStatus) -> impl IntoElement {
+ GitStatusIcon::new(status)
}
fn can_push_and_pull(project: &Entity<Project>, cx: &App) -> bool {
@@ -465,3 +443,79 @@ mod remote_button {
}
}
}
+
+#[derive(IntoElement, IntoComponent)]
+#[component(scope = "Version Control")]
+pub struct GitStatusIcon {
+ status: FileStatus,
+}
+
+impl GitStatusIcon {
+ pub fn new(status: FileStatus) -> Self {
+ Self { status }
+ }
+}
+
+impl RenderOnce for GitStatusIcon {
+ fn render(self, _window: &mut ui::Window, cx: &mut App) -> impl IntoElement {
+ let status = self.status;
+
+ let (icon_name, color) = if status.is_conflicted() {
+ (
+ IconName::Warning,
+ cx.theme().colors().version_control_conflict,
+ )
+ } else if status.is_deleted() {
+ (
+ IconName::SquareMinus,
+ cx.theme().colors().version_control_deleted,
+ )
+ } else if status.is_modified() {
+ (
+ IconName::SquareDot,
+ cx.theme().colors().version_control_modified,
+ )
+ } else {
+ (
+ IconName::SquarePlus,
+ cx.theme().colors().version_control_added,
+ )
+ };
+
+ Icon::new(icon_name).color(Color::Custom(color))
+ }
+}
+
+// View this component preview using `workspace: open component-preview`
+impl ComponentPreview for GitStatusIcon {
+ fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
+ fn tracked_file_status(code: StatusCode) -> FileStatus {
+ FileStatus::Tracked(git::status::TrackedStatus {
+ index_status: code,
+ worktree_status: code,
+ })
+ }
+
+ let modified = tracked_file_status(StatusCode::Modified);
+ let added = tracked_file_status(StatusCode::Added);
+ let deleted = tracked_file_status(StatusCode::Deleted);
+ let conflict = UnmergedStatus {
+ first_head: UnmergedStatusCode::Updated,
+ second_head: UnmergedStatusCode::Updated,
+ }
+ .into();
+
+ v_flex()
+ .gap_6()
+ .children(vec![example_group(vec![
+ single_example("Modified", GitStatusIcon::new(modified).into_any_element()),
+ single_example("Added", GitStatusIcon::new(added).into_any_element()),
+ single_example("Deleted", GitStatusIcon::new(deleted).into_any_element()),
+ single_example(
+ "Conflicted",
+ GitStatusIcon::new(conflict).into_any_element(),
+ ),
+ ])])
+ .into_any_element()
+ }
+}
@@ -18,8 +18,6 @@ pub trait PanelHeader: workspace::Panel {
.w_full()
.px_1()
.flex_none()
- .border_b_1()
- .border_color(cx.theme().colors().border)
}
}
@@ -136,14 +136,10 @@ impl ThemeColors {
terminal_ansi_dim_white: neutral().light().step_11(),
link_text_hover: orange().light().step_10(),
version_control_added: ADDED_COLOR,
- version_control_added_background: ADDED_COLOR.opacity(0.1),
version_control_deleted: REMOVED_COLOR,
- version_control_deleted_background: REMOVED_COLOR.opacity(0.1),
version_control_modified: MODIFIED_COLOR,
- version_control_modified_background: MODIFIED_COLOR.opacity(0.1),
version_control_renamed: MODIFIED_COLOR,
version_control_conflict: orange().light().step_12(),
- version_control_conflict_background: orange().light().step_12().opacity(0.1),
version_control_ignored: gray().light().step_12(),
}
}
@@ -253,14 +249,10 @@ impl ThemeColors {
terminal_ansi_dim_white: neutral().dark().step_10(),
link_text_hover: orange().dark().step_10(),
version_control_added: ADDED_COLOR,
- version_control_added_background: ADDED_COLOR.opacity(0.1),
version_control_deleted: REMOVED_COLOR,
- version_control_deleted_background: REMOVED_COLOR.opacity(0.1),
version_control_modified: MODIFIED_COLOR,
- version_control_modified_background: MODIFIED_COLOR.opacity(0.1),
version_control_renamed: MODIFIED_COLOR,
version_control_conflict: orange().dark().step_12(),
- version_control_conflict_background: orange().dark().step_12().opacity(0.1),
version_control_ignored: gray().dark().step_12(),
}
}
@@ -190,14 +190,10 @@ pub(crate) fn zed_default_dark() -> Theme {
editor_foreground: hsla(218. / 360., 14. / 100., 71. / 100., 1.),
link_text_hover: blue,
version_control_added: ADDED_COLOR,
- version_control_added_background: ADDED_COLOR.opacity(0.1),
version_control_deleted: REMOVED_COLOR,
- version_control_deleted_background: REMOVED_COLOR.opacity(0.1),
version_control_modified: MODIFIED_COLOR,
- version_control_modified_background: MODIFIED_COLOR.opacity(0.1),
version_control_renamed: MODIFIED_COLOR,
version_control_conflict: crate::orange().light().step_12(),
- version_control_conflict_background: crate::orange().light().step_12().opacity(0.1),
version_control_ignored: crate::gray().light().step_12(),
},
status: StatusColors {
@@ -557,26 +557,14 @@ pub struct ThemeColorsContent {
#[serde(rename = "version_control.added")]
pub version_control_added: Option<String>,
- /// Added version control background color.
- #[serde(rename = "version_control.added_background")]
- pub version_control_added_background: Option<String>,
-
/// Deleted version control color.
#[serde(rename = "version_control.deleted")]
pub version_control_deleted: Option<String>,
- /// Deleted version control background color.
- #[serde(rename = "version_control.deleted_background")]
- pub version_control_deleted_background: Option<String>,
-
/// Modified version control color.
#[serde(rename = "version_control.modified")]
pub version_control_modified: Option<String>,
- /// Modified version control background color.
- #[serde(rename = "version_control.modified_background")]
- pub version_control_modified_background: Option<String>,
-
/// Renamed version control color.
#[serde(rename = "version_control.renamed")]
pub version_control_renamed: Option<String>,
@@ -585,10 +573,6 @@ pub struct ThemeColorsContent {
#[serde(rename = "version_control.conflict")]
pub version_control_conflict: Option<String>,
- /// Conflict version control background color.
- #[serde(rename = "version_control.conflict_background")]
- pub version_control_conflict_background: Option<String>,
-
/// Ignored version control color.
#[serde(rename = "version_control.ignored")]
pub version_control_ignored: Option<String>,
@@ -1000,26 +984,14 @@ impl ThemeColorsContent {
.version_control_added
.as_ref()
.and_then(|color| try_parse_color(color).ok()),
- version_control_added_background: self
- .version_control_added_background
- .as_ref()
- .and_then(|color| try_parse_color(color).ok()),
version_control_deleted: self
.version_control_deleted
.as_ref()
.and_then(|color| try_parse_color(color).ok()),
- version_control_deleted_background: self
- .version_control_deleted_background
- .as_ref()
- .and_then(|color| try_parse_color(color).ok()),
version_control_modified: self
.version_control_modified
.as_ref()
.and_then(|color| try_parse_color(color).ok()),
- version_control_modified_background: self
- .version_control_modified_background
- .as_ref()
- .and_then(|color| try_parse_color(color).ok()),
version_control_renamed: self
.version_control_renamed
.as_ref()
@@ -1028,10 +1000,6 @@ impl ThemeColorsContent {
.version_control_conflict
.as_ref()
.and_then(|color| try_parse_color(color).ok()),
- version_control_conflict_background: self
- .version_control_conflict_background
- .as_ref()
- .and_then(|color| try_parse_color(color).ok()),
version_control_ignored: self
.version_control_ignored
.as_ref()
@@ -246,22 +246,14 @@ pub struct ThemeColors {
/// Represents an added entry or hunk in vcs, like git.
pub version_control_added: Hsla,
- /// Represents the line background of an added entry or hunk in vcs, like git.
- pub version_control_added_background: Hsla,
/// Represents a deleted entry in version control systems.
pub version_control_deleted: Hsla,
- /// Represents the background color for deleted entries in version control systems.
- pub version_control_deleted_background: Hsla,
/// Represents a modified entry in version control systems.
pub version_control_modified: Hsla,
- /// Represents the background color for modified entries in version control systems.
- pub version_control_modified_background: Hsla,
/// Represents a renamed entry in version control systems.
pub version_control_renamed: Hsla,
/// Represents a conflicting entry in version control systems.
pub version_control_conflict: Hsla,
- /// Represents the background color for conflicting entries in version control systems.
- pub version_control_conflict_background: Hsla,
/// Represents an ignored entry in version control systems.
pub version_control_ignored: Hsla,
}
@@ -366,14 +358,10 @@ pub enum ThemeColorField {
TerminalAnsiDimWhite,
LinkTextHover,
VersionControlAdded,
- VersionControlAddedBackground,
VersionControlDeleted,
- VersionControlDeletedBackground,
VersionControlModified,
- VersionControlModifiedBackground,
VersionControlRenamed,
VersionControlConflict,
- VersionControlConflictBackground,
VersionControlIgnored,
}
@@ -485,20 +473,10 @@ impl ThemeColors {
ThemeColorField::TerminalAnsiDimWhite => self.terminal_ansi_dim_white,
ThemeColorField::LinkTextHover => self.link_text_hover,
ThemeColorField::VersionControlAdded => self.version_control_added,
- ThemeColorField::VersionControlAddedBackground => self.version_control_added_background,
ThemeColorField::VersionControlDeleted => self.version_control_deleted,
- ThemeColorField::VersionControlDeletedBackground => {
- self.version_control_deleted_background
- }
ThemeColorField::VersionControlModified => self.version_control_modified,
- ThemeColorField::VersionControlModifiedBackground => {
- self.version_control_modified_background
- }
ThemeColorField::VersionControlRenamed => self.version_control_renamed,
ThemeColorField::VersionControlConflict => self.version_control_conflict,
- ThemeColorField::VersionControlConflictBackground => {
- self.version_control_conflict_background
- }
ThemeColorField::VersionControlIgnored => self.version_control_ignored,
}
}
@@ -6,9 +6,7 @@ use crate::{
prelude::*, Color, DynamicSpacing, ElevationIndex, IconPosition, KeyBinding,
KeybindingPosition, TintColor,
};
-use crate::{
- ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label, LineHeightStyle,
-};
+use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label};
use super::button_icon::ButtonIcon;
@@ -448,7 +446,6 @@ impl RenderOnce for Button {
.color(label_color)
.size(self.label_size.unwrap_or_default())
.when_some(self.alpha, |this, alpha| this.alpha(alpha))
- .line_height_style(LineHeightStyle::UiLabel)
.when(self.truncate, |this| this.truncate()),
)
.children(self.key_binding),
@@ -1,6 +1,5 @@
use gpui::{
- div, hsla, prelude::*, AnyElement, AnyView, CursorStyle, ElementId, Hsla, IntoElement, Styled,
- Window,
+ div, hsla, prelude::*, AnyElement, AnyView, ElementId, Hsla, IntoElement, Styled, Window,
};
use std::sync::Arc;
@@ -141,14 +140,14 @@ impl Checkbox {
match self.style.clone() {
ToggleStyle::Ghost => cx.theme().colors().border,
- ToggleStyle::ElevationBased(elevation) => elevation.on_elevation_bg(cx),
+ ToggleStyle::ElevationBased(_) => cx.theme().colors().border,
ToggleStyle::Custom(color) => color.opacity(0.3),
}
}
/// container size
- pub fn container_size(cx: &App) -> Rems {
- DynamicSpacing::Base20.rems(cx)
+ pub fn container_size() -> Pixels {
+ px(20.0)
}
}
@@ -157,21 +156,21 @@ impl RenderOnce for Checkbox {
let group_id = format!("checkbox_group_{:?}", self.id);
let color = if self.disabled {
Color::Disabled
- } else if self.placeholder {
- Color::Placeholder
} else {
Color::Selected
};
let icon = match self.toggle_state {
- ToggleState::Selected => Some(if self.placeholder {
- Icon::new(IconName::Circle)
- .size(IconSize::XSmall)
- .color(color)
- } else {
- Icon::new(IconName::Check)
- .size(IconSize::Small)
- .color(color)
- }),
+ ToggleState::Selected => {
+ if self.placeholder {
+ None
+ } else {
+ Some(
+ Icon::new(IconName::Check)
+ .size(IconSize::Small)
+ .color(color),
+ )
+ }
+ }
ToggleState::Indeterminate => {
Some(Icon::new(IconName::Dash).size(IconSize::Small).color(color))
}
@@ -180,8 +179,9 @@ impl RenderOnce for Checkbox {
let bg_color = self.bg_color(cx);
let border_color = self.border_color(cx);
+ let hover_border_color = border_color.alpha(0.7);
- let size = Self::container_size(cx);
+ let size = Self::container_size();
let checkbox = h_flex()
.id(self.id.clone())
@@ -195,22 +195,27 @@ impl RenderOnce for Checkbox {
.flex_none()
.justify_center()
.items_center()
- .m(DynamicSpacing::Base04.px(cx))
- .size(DynamicSpacing::Base16.rems(cx))
+ .m_1()
+ .size_4()
.rounded_xs()
.bg(bg_color)
.border_1()
.border_color(border_color)
- .when(self.disabled, |this| {
- this.cursor(CursorStyle::OperationNotAllowed)
- })
+ .when(self.disabled, |this| this.cursor_not_allowed())
.when(self.disabled, |this| {
this.bg(cx.theme().colors().element_disabled.opacity(0.6))
})
.when(!self.disabled, |this| {
- this.group_hover(group_id.clone(), |el| {
- el.bg(cx.theme().colors().element_hover)
- })
+ this.group_hover(group_id.clone(), |el| el.border_color(hover_border_color))
+ })
+ .when(self.placeholder, |this| {
+ this.child(
+ div()
+ .flex_none()
+ .rounded_full()
+ .bg(color.color(cx).alpha(0.5))
+ .size(px(4.)),
+ )
})
.children(icon),
);
@@ -522,6 +527,12 @@ impl ComponentPreview for Checkbox {
Checkbox::new("checkbox_unselected", ToggleState::Unselected)
.into_any_element(),
),
+ single_example(
+ "Placeholder",
+ Checkbox::new("checkbox_indeterminate", ToggleState::Selected)
+ .placeholder(true)
+ .into_any_element(),
+ ),
single_example(
"Indeterminate",
Checkbox::new("checkbox_indeterminate", ToggleState::Indeterminate)