This commit is contained in:
2026-09-05 17:23:58 +07:00
parent 7ff09502b9
commit 9b6b615da2
2 changed files with 55 additions and 24 deletions
+41 -21
View File
@@ -11,7 +11,7 @@ use gpui::prelude::*;
use gpui::{ use gpui::{
Action, Anchor, AnyElement, App, ClipboardItem, Context, Entity, EventEmitter, FocusHandle, Action, Anchor, AnyElement, App, ClipboardItem, Context, Entity, EventEmitter, FocusHandle,
Focusable, PathPromptOptions, Pixels, Render, SharedString, Size, Subscription, Task, Focusable, PathPromptOptions, Pixels, Render, SharedString, Size, Subscription, Task,
WeakEntity, Window, div, px, relative, size, WeakEntity, Window, div, px, relative, size, transparent_white,
}; };
use gpui_base::{Button as BaseButton, Disableable, Popover}; use gpui_base::{Button as BaseButton, Disableable, Popover};
use gpui_component::alert::Alert; use gpui_component::alert::Alert;
@@ -1985,26 +1985,51 @@ impl RepoDetailView {
let path = status.path.clone(); let path = status.path.clone();
let commits = if status.ahead == 1 { let commits = if status.ahead == 1 {
"1 commit".to_owned() SharedString::from("1 commit")
} else { } else {
format!("{} commits", status.ahead) SharedString::from(format!("{} commits", status.ahead))
}; };
let message = SharedString::from(format!(
"{} has {} ready to push in {}",
status.branch,
commits,
status.path.display()
));
Some( Some(
h_flex() h_flex()
.px_4() .p_4()
.gap_2() .gap_2()
.w_full() .w_full()
.items_center() .items_center()
.justify_between() .justify_between()
.child(div().text_sm().child(message)) .bg(cx.theme().muted)
.child(
h_flex()
.gap_2()
.text_sm()
.text_color(cx.theme().info)
.child(
h_flex()
.px_1()
.rounded(cx.theme().radius)
.border_1()
.border_color(cx.theme().info)
.bg(cx.theme().info.mix_oklab(transparent_white(), 0.04))
.text_xs()
.font_semibold()
.font_family(cx.theme().mono_font_family.clone())
.child(status.branch),
)
.child("has")
.child(
h_flex()
.px_1()
.rounded(cx.theme().radius)
.border_1()
.border_color(cx.theme().info)
.bg(cx.theme().info.mix_oklab(transparent_white(), 0.04))
.text_xs()
.font_semibold()
.font_family(cx.theme().mono_font_family.clone())
.child(commits),
)
.child("ready to push"),
)
.child( .child(
h_flex() h_flex()
.gap_1() .gap_1()
@@ -2023,6 +2048,7 @@ impl RepoDetailView {
.child( .child(
Button::new("close-repo") Button::new("close-repo")
.icon(IconName::Close) .icon(IconName::Close)
.tooltip("Dismiss")
.small() .small()
.ghost() .ghost()
.disabled(self.pushing) .disabled(self.pushing)
@@ -2309,9 +2335,7 @@ impl Render for RepoDetailView {
.image_cache(gpui::retain_all("repo")) .image_cache(gpui::retain_all("repo"))
.id("repo") .id("repo")
.size_full() .size_full()
.when_some(banner, |this, banner| { .when_some(banner, |this, banner| this.child(banner))
this.child(v_flex().gap_1().py_4().bg(cx.theme().muted).child(banner))
})
.child(self.render_header(cx)) .child(self.render_header(cx))
.when_some(self.error.clone(), |this, error| { .when_some(self.error.clone(), |this, error| {
this.child( this.child(
@@ -2339,6 +2363,7 @@ impl Render for RepoDetailView {
} }
/// Read the worktree state of `repo`, no network. /// Read the worktree state of `repo`, no network.
///
/// Entries, README, refs and HEAD commit. /// Entries, README, refs and HEAD commit.
fn load_repo_data(repo: &Repository) -> Result<RepoData, Error> { fn load_repo_data(repo: &Repository) -> Result<RepoData, Error> {
let entries = signed_git::worktree_entries(repo)?; let entries = signed_git::worktree_entries(repo)?;
@@ -2375,9 +2400,6 @@ fn load_repo_data(repo: &Repository) -> Result<RepoData, Error> {
} }
/// The `nostr://...` clone URL of an announcement, NIP-34. /// The `nostr://...` clone URL of an announcement, NIP-34.
/// The owner as a NIP-05 identifier when known, npub otherwise.
/// The first announced relay is a hint, plus the repository identifier.
/// `nip05` is the owner's NIP-05 identifier from the profile store, already blank-filtered.
fn nostr_clone_url(announcement: &Announcement, nip05: Option<&str>) -> SharedString { fn nostr_clone_url(announcement: &Announcement, nip05: Option<&str>) -> SharedString {
let owner = announcement.owner; let owner = announcement.owner;
let user = nip05 let user = nip05
@@ -2396,6 +2418,7 @@ fn nostr_clone_url(announcement: &Announcement, nip05: Option<&str>) -> SharedSt
} }
/// The forked-from row of the detail header. /// The forked-from row of the detail header.
///
/// Clickable link to the upstream repository when the `u` tag references a NIP-34 repo. /// Clickable link to the upstream repository when the `u` tag references a NIP-34 repo.
/// Plain text when it only carries a git URL. /// Plain text when it only carries a git URL.
fn fork_row(announcement: &Announcement, cx: &mut Context<RepoDetailView>) -> Option<AnyElement> { fn fork_row(announcement: &Announcement, cx: &mut Context<RepoDetailView>) -> Option<AnyElement> {
@@ -2443,9 +2466,6 @@ fn fork_row(announcement: &Announcement, cx: &mut Context<RepoDetailView>) -> Op
} }
/// Open `announcement` as a repository panel in the dock's center. /// Open `announcement` as a repository panel in the dock's center.
/// Returns the new detail view.
/// Shared by the explore list, the sidebar and fork links.
/// Every entry point opens repositories identically.
pub(crate) fn open_repo_panel( pub(crate) fn open_repo_panel(
dock_area: &WeakEntity<DockArea>, dock_area: &WeakEntity<DockArea>,
announcement: &Announcement, announcement: &Announcement,
+14 -3
View File
@@ -11,10 +11,9 @@ use dock::{
use gpui::prelude::*; use gpui::prelude::*;
use gpui::{ use gpui::{
AnyElement, App, Context, Div, EventEmitter, FocusHandle, Focusable, ObjectFit, Render, AnyElement, App, Context, Div, EventEmitter, FocusHandle, Focusable, ObjectFit, Render,
SharedString, Subscription, WeakEntity, Window, div, img, px, uniform_list, SharedString, Subscription, WeakEntity, Window, div, img, px, relative, uniform_list, white,
}; };
use gpui_base::Button as BaseButton; use gpui_base::Button as BaseButton;
use gpui_component::badge::Badge;
use gpui_component::button::{Button, ButtonVariants}; use gpui_component::button::{Button, ButtonVariants};
use gpui_component::input::InputState; use gpui_component::input::InputState;
use gpui_component::{ActiveTheme, Icon, IconName, Sizable, StyledExt, h_flex, v_flex}; use gpui_component::{ActiveTheme, Icon, IconName, Sizable, StyledExt, h_flex, v_flex};
@@ -400,7 +399,19 @@ impl SidebarPanel {
let mut row = NavItem::new(format!("repo:{}", announcement.id), name, avatar); let mut row = NavItem::new(format!("repo:{}", announcement.id), name, avatar);
if unpushed > 0 { if unpushed > 0 {
row = row.suffix(Badge::new().count(unpushed).xsmall()); row = row.suffix(
v_flex()
.flex_shrink_0()
.size_4()
.items_center()
.justify_center()
.rounded_full()
.line_height(relative(1.))
.bg(cx.theme().red_light)
.text_color(white())
.text_size(px(8.))
.child(SharedString::from(unpushed.to_string())),
);
} }
row.on_click( row.on_click(