git_ui: New panel design (#25821)
This PR updates the ui of the git panel. It removes the header from the panel and unifies the repository, branch and commit controls in the bottom section. It also adds a secondary menu to the primary button giving access to a variety of actions for managing local and remote changes:  Known issues (will be fixed in a later pr) - Spinner showing git operation progress was removed, will be re-added - Clicking expand with the panel editor focused will commit (due to shared action name. Already tracked) Before | After  (Also adds `component`, `linkme` to cargo-machete ignore as they are used in the `IntoComponent` proc-macro and will always be incorrectly flagged as unused) Release Notes: - N/A --------- Co-authored-by: Cole Miller <m@cole-miller.net> Co-authored-by: Cole Miller <53574922+cole-miller@users.noreply.github.com> Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
parent
8a22a07d14
commit
9d8a163f5b
26 changed files with 832 additions and 372 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -5395,6 +5395,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"buffer_diff",
|
||||
"collections",
|
||||
"component",
|
||||
"db",
|
||||
"editor",
|
||||
"feature_flags",
|
||||
|
@ -5404,6 +5405,7 @@ dependencies = [
|
|||
"gpui",
|
||||
"itertools 0.14.0",
|
||||
"language",
|
||||
"linkme",
|
||||
"menu",
|
||||
"multi_buffer",
|
||||
"panel",
|
||||
|
@ -5415,6 +5417,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"smallvec",
|
||||
"strum",
|
||||
"theme",
|
||||
"time",
|
||||
|
|
|
@ -749,4 +749,4 @@ should_implement_trait = { level = "allow" }
|
|||
let_underscore_future = "allow"
|
||||
|
||||
[workspace.metadata.cargo-machete]
|
||||
ignored = ["bindgen", "cbindgen", "prost_build", "serde"]
|
||||
ignored = ["bindgen", "cbindgen", "prost_build", "serde", "component", "linkme"]
|
||||
|
|
6
assets/icons/git_branch_small.svg
Normal file
6
assets/icons/git_branch_small.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 3.25C4.02614 3.25 4.25 3.02614 4.25 2.75C4.25 2.47386 4.02614 2.25 3.75 2.25C3.47386 2.25 3.25 2.47386 3.25 2.75C3.25 3.02614 3.47386 3.25 3.75 3.25ZM3.75 4.25C4.57843 4.25 5.25 3.57843 5.25 2.75C5.25 1.92157 4.57843 1.25 3.75 1.25C2.92157 1.25 2.25 1.92157 2.25 2.75C2.25 3.57843 2.92157 4.25 3.75 4.25Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.25 3.25C8.52614 3.25 8.75 3.02614 8.75 2.75C8.75 2.47386 8.52614 2.25 8.25 2.25C7.97386 2.25 7.75 2.47386 7.75 2.75C7.75 3.02614 7.97386 3.25 8.25 3.25ZM8.25 4.25C9.07843 4.25 9.75 3.57843 9.75 2.75C9.75 1.92157 9.07843 1.25 8.25 1.25C7.42157 1.25 6.75 1.92157 6.75 2.75C6.75 3.57843 7.42157 4.25 8.25 4.25Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 9.75C4.02614 9.75 4.25 9.52614 4.25 9.25C4.25 8.97386 4.02614 8.75 3.75 8.75C3.47386 8.75 3.25 8.97386 3.25 9.25C3.25 9.52614 3.47386 9.75 3.75 9.75ZM3.75 10.75C4.57843 10.75 5.25 10.0784 5.25 9.25C5.25 8.42157 4.57843 7.75 3.75 7.75C2.92157 7.75 2.25 8.42157 2.25 9.25C2.25 10.0784 2.92157 10.75 3.75 10.75Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.25 3.75H4.25V5.59609C4.67823 5.35824 5.24991 5.25 6 5.25H7.25017C7.5262 5.25 7.75 5.02625 7.75 4.75V3.75H8.75V4.75C8.75 5.57832 8.07871 6.25 7.25017 6.25H6C5.14559 6.25 4.77639 6.41132 4.59684 6.56615C4.42571 6.71373 4.33877 6.92604 4.25 7.30651V8.25H3.25V3.75Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -18,7 +18,7 @@ pub trait Component {
|
|||
}
|
||||
|
||||
pub trait ComponentPreview: Component {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement;
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement;
|
||||
}
|
||||
|
||||
#[distributed_slice]
|
||||
|
@ -32,7 +32,7 @@ pub static COMPONENT_DATA: LazyLock<RwLock<ComponentRegistry>> =
|
|||
|
||||
pub struct ComponentRegistry {
|
||||
components: Vec<(Option<&'static str>, &'static str, Option<&'static str>)>,
|
||||
previews: HashMap<&'static str, fn(&mut Window, &App) -> AnyElement>,
|
||||
previews: HashMap<&'static str, fn(&mut Window, &mut App) -> AnyElement>,
|
||||
}
|
||||
|
||||
impl ComponentRegistry {
|
||||
|
@ -62,7 +62,10 @@ pub fn register_component<T: Component>() {
|
|||
}
|
||||
|
||||
pub fn register_preview<T: ComponentPreview>() {
|
||||
let preview_data = (T::name(), T::preview as fn(&mut Window, &App) -> AnyElement);
|
||||
let preview_data = (
|
||||
T::name(),
|
||||
T::preview as fn(&mut Window, &mut App) -> AnyElement,
|
||||
);
|
||||
COMPONENT_DATA
|
||||
.write()
|
||||
.previews
|
||||
|
@ -77,7 +80,7 @@ pub struct ComponentMetadata {
|
|||
name: SharedString,
|
||||
scope: Option<SharedString>,
|
||||
description: Option<SharedString>,
|
||||
preview: Option<fn(&mut Window, &App) -> AnyElement>,
|
||||
preview: Option<fn(&mut Window, &mut App) -> AnyElement>,
|
||||
}
|
||||
|
||||
impl ComponentMetadata {
|
||||
|
@ -93,7 +96,7 @@ impl ComponentMetadata {
|
|||
self.description.clone()
|
||||
}
|
||||
|
||||
pub fn preview(&self) -> Option<fn(&mut Window, &App) -> AnyElement> {
|
||||
pub fn preview(&self) -> Option<fn(&mut Window, &mut App) -> AnyElement> {
|
||||
self.preview
|
||||
}
|
||||
}
|
||||
|
@ -235,6 +238,7 @@ pub struct ComponentExampleGroup {
|
|||
pub title: Option<SharedString>,
|
||||
pub examples: Vec<ComponentExample>,
|
||||
pub grow: bool,
|
||||
pub vertical: bool,
|
||||
}
|
||||
|
||||
impl RenderOnce for ComponentExampleGroup {
|
||||
|
@ -270,6 +274,7 @@ impl RenderOnce for ComponentExampleGroup {
|
|||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.when(self.vertical, |this| this.flex_col())
|
||||
.items_start()
|
||||
.w_full()
|
||||
.gap_6()
|
||||
|
@ -287,6 +292,7 @@ impl ComponentExampleGroup {
|
|||
title: None,
|
||||
examples,
|
||||
grow: false,
|
||||
vertical: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,6 +302,7 @@ impl ComponentExampleGroup {
|
|||
title: Some(title.into()),
|
||||
examples,
|
||||
grow: false,
|
||||
vertical: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,6 +311,12 @@ impl ComponentExampleGroup {
|
|||
self.grow = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Lay the group out vertically.
|
||||
pub fn vertical(mut self) -> Self {
|
||||
self.vertical = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a single example
|
||||
|
|
|
@ -93,7 +93,7 @@ impl ComponentPreview {
|
|||
&self,
|
||||
ix: usize,
|
||||
window: &mut Window,
|
||||
cx: &Context<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let component = self.get_component(ix);
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ actions!(
|
|||
Pull,
|
||||
Fetch,
|
||||
Commit,
|
||||
ExpandCommitEditor,
|
||||
]
|
||||
);
|
||||
action_with_deprecated_aliases!(git, RestoreFile, ["editor::RevertFile"]);
|
||||
|
|
|
@ -74,6 +74,12 @@ impl UpstreamTracking {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<UpstreamTrackingStatus> for UpstreamTracking {
|
||||
fn from(status: UpstreamTrackingStatus) -> Self {
|
||||
UpstreamTracking::Tracked(status)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct UpstreamTrackingStatus {
|
||||
pub ahead: u32,
|
||||
|
|
|
@ -20,6 +20,7 @@ test-support = ["multi_buffer/test-support"]
|
|||
anyhow.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
collections.workspace = true
|
||||
component.workspace = true
|
||||
db.workspace = true
|
||||
editor.workspace = true
|
||||
feature_flags.workspace = true
|
||||
|
@ -29,6 +30,7 @@ git.workspace = true
|
|||
gpui.workspace = true
|
||||
itertools.workspace = true
|
||||
language.workspace = true
|
||||
linkme.workspace = true
|
||||
menu.workspace = true
|
||||
multi_buffer.workspace = true
|
||||
panel.workspace = true
|
||||
|
@ -40,6 +42,7 @@ serde.workspace = true
|
|||
serde_derive.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
smallvec.workspace = true
|
||||
strum.workspace = true
|
||||
theme.workspace = true
|
||||
time.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::branch_picker::{self, BranchList};
|
||||
use crate::git_panel::{commit_message_editor, GitPanel};
|
||||
use git::Commit;
|
||||
use git::{Commit, ExpandCommitEditor};
|
||||
use panel::{panel_button, panel_editor_style, panel_filled_button};
|
||||
use project::Project;
|
||||
use ui::{prelude::*, KeybindingHint, PopoverButton, Tooltip, TriggerablePopover};
|
||||
|
@ -110,14 +110,17 @@ struct RestoreDock {
|
|||
|
||||
impl CommitModal {
|
||||
pub fn register(workspace: &mut Workspace, _: &mut Window, _cx: &mut Context<Workspace>) {
|
||||
workspace.register_action(|workspace, _: &Commit, window, cx| {
|
||||
workspace.register_action(|workspace, _: &ExpandCommitEditor, window, cx| {
|
||||
let Some(git_panel) = workspace.panel::<GitPanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let (can_commit, conflict) = git_panel.update(cx, |git_panel, _cx| {
|
||||
let (can_commit, conflict) = git_panel.update(cx, |git_panel, cx| {
|
||||
let can_commit = git_panel.can_commit();
|
||||
let conflict = git_panel.has_unstaged_conflicts();
|
||||
if can_commit {
|
||||
git_panel.set_modal_open(true, cx);
|
||||
}
|
||||
(can_commit, conflict)
|
||||
});
|
||||
if !can_commit {
|
||||
|
@ -131,6 +134,7 @@ impl CommitModal {
|
|||
prompt.await.ok();
|
||||
})
|
||||
.detach();
|
||||
return;
|
||||
}
|
||||
|
||||
let dock = workspace.dock_at_position(git_panel.position(window, cx));
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -79,7 +79,7 @@ pub fn panel_editor_container(_window: &mut Window, cx: &mut App) -> Div {
|
|||
.bg(cx.theme().colors().editor_background)
|
||||
}
|
||||
|
||||
pub fn panel_editor_style(monospace: bool, window: &mut Window, cx: &mut App) -> EditorStyle {
|
||||
pub fn panel_editor_style(monospace: bool, window: &Window, cx: &App) -> EditorStyle {
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
|
||||
let font_size = TextSize::Small.rems(cx).to_pixels(window.rem_size());
|
||||
|
|
|
@ -220,7 +220,7 @@ impl RenderOnce for AvatarAvailabilityIndicator {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Avatar {
|
||||
fn preview(_window: &mut Window, cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
|
||||
let example_avatar = "https://avatars.githubusercontent.com/u/1714999?v=4";
|
||||
|
||||
v_flex()
|
||||
|
|
|
@ -458,7 +458,7 @@ impl RenderOnce for Button {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Button {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
|
|
@ -202,7 +202,7 @@ impl RenderOnce for IconButton {
|
|||
}
|
||||
|
||||
impl ComponentPreview for IconButton {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
|
|
@ -144,7 +144,7 @@ impl RenderOnce for ToggleButton {
|
|||
}
|
||||
|
||||
impl ComponentPreview for ToggleButton {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
|
|
@ -90,7 +90,7 @@ impl RenderOnce for ContentGroup {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for ContentGroup {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
example_group(vec![
|
||||
single_example(
|
||||
"Default",
|
||||
|
|
|
@ -61,7 +61,7 @@ impl RenderOnce for Facepile {
|
|||
}
|
||||
|
||||
impl ComponentPreview for Facepile {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
let faces: [&'static str; 6] = [
|
||||
"https://avatars.githubusercontent.com/u/326587?s=60&v=4",
|
||||
"https://avatars.githubusercontent.com/u/2280405?s=60&v=4",
|
||||
|
|
|
@ -218,6 +218,7 @@ pub enum IconName {
|
|||
Github,
|
||||
Globe,
|
||||
GitBranch,
|
||||
GitBranchSmall,
|
||||
Hash,
|
||||
HistoryRerun,
|
||||
Indicator,
|
||||
|
@ -492,7 +493,7 @@ impl RenderOnce for IconWithIndicator {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Icon {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
|
|
@ -26,7 +26,7 @@ impl RenderOnce for DecoratedIcon {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for DecoratedIcon {
|
||||
fn preview(_window: &mut Window, cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
|
||||
let decoration_x = IconDecoration::new(
|
||||
IconDecorationKind::X,
|
||||
cx.theme().colors().surface_background,
|
||||
|
|
|
@ -207,7 +207,7 @@ impl RenderOnce for KeybindingHint {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for KeybindingHint {
|
||||
fn preview(window: &mut Window, cx: &App) -> AnyElement {
|
||||
fn preview(window: &mut Window, cx: &mut App) -> AnyElement {
|
||||
let enter_fallback = gpui::KeyBinding::new("enter", menu::Confirm, None);
|
||||
let enter = KeyBinding::for_action(&menu::Confirm, window, cx)
|
||||
.unwrap_or(KeyBinding::new(enter_fallback, cx));
|
||||
|
|
|
@ -199,7 +199,7 @@ mod label_preview {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Label {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
|
|
@ -173,7 +173,7 @@ impl RenderOnce for Tab {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Tab {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![example_group_with_title(
|
||||
|
|
|
@ -153,7 +153,7 @@ where
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Table {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
|
|
@ -510,7 +510,7 @@ impl RenderOnce for SwitchWithLabel {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Checkbox {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
@ -595,7 +595,7 @@ impl ComponentPreview for Checkbox {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Switch {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
|
@ -658,7 +658,7 @@ impl ComponentPreview for Switch {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for CheckboxWithLabel {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![example_group_with_title(
|
||||
|
|
|
@ -224,7 +224,7 @@ impl Render for LinkPreview {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Tooltip {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
example_group(vec![single_example(
|
||||
"Text only",
|
||||
Button::new("delete-example", "Delete")
|
||||
|
|
|
@ -235,7 +235,7 @@ impl Headline {
|
|||
|
||||
// View this component preview using `workspace: open component-preview`
|
||||
impl ComponentPreview for Headline {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.children(vec![
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue