From d79d2c7a27aeca8ca4bed3da5fdc497d4cca9060 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Fri, 13 Nov 2026 09:24:22 +0700 Subject: [PATCH] update gpui-native-kit and adopt file icon roles --- Cargo.lock | 28 +++--- Cargo.toml | 2 +- crates/signed_app/src/app/mod.rs | 17 ++++ crates/signed_app/src/explore/mod.rs | 4 +- crates/signed_app/src/identity/passphrase.rs | 5 +- crates/signed_app/src/pull_requests/new.rs | 2 +- crates/signed_app/src/repo/commit_diff.rs | 2 +- crates/signed_app/src/repo/files.rs | 2 +- crates/signed_app/src/repo/mod.rs | 2 +- crates/signed_app/src/sidebar/helpers.rs | 6 +- crates/signed_app/src/sidebar/mod.rs | 94 +++++++++----------- docs/gpui-native-kit-gaps.md | 11 +-- 12 files changed, 87 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e547cd..1639f46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1579,7 +1579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3059,7 +3059,7 @@ dependencies = [ [[package]] name = "gpui-native-core" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "cpal", "flume 0.12.0", @@ -3074,7 +3074,7 @@ dependencies = [ [[package]] name = "gpui-native-data" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "gpui", "gpui-native-core", @@ -3086,7 +3086,7 @@ dependencies = [ [[package]] name = "gpui-native-editor" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "gpui", "gpui-native-core", @@ -3105,7 +3105,7 @@ dependencies = [ [[package]] name = "gpui-native-icons" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "anyhow", "gpui", @@ -3114,7 +3114,7 @@ dependencies = [ [[package]] name = "gpui-native-kit" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "gpui", "gpui-native-core", @@ -3128,7 +3128,7 @@ dependencies = [ [[package]] name = "gpui-native-layout" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "gpui", "gpui-native-core", @@ -3141,7 +3141,7 @@ dependencies = [ [[package]] name = "gpui-native-theme" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "anyhow", "async-channel", @@ -3162,7 +3162,7 @@ dependencies = [ [[package]] name = "gpui-native-utils" version = "0.1.0" -source = "git+https://git.reya.info/reya/gpui-native-kit?rev=dad833f998fecc0d828e716f3cbf0342d499db81#dad833f998fecc0d828e716f3cbf0342d499db81" +source = "git+https://git.reya.info/reya/gpui-native-kit?rev=c3e3c37731e389d858712369e47eec9c205cdfbe#c3e3c37731e389d858712369e47eec9c205cdfbe" dependencies = [ "gpui", "gpui-native-theme", @@ -5939,7 +5939,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6437,7 +6437,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6505,7 +6505,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -7381,7 +7381,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -8574,7 +8574,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 09115d3..623e1af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ gpui = { git = "https://github.com/zed-industries/zed", rev = "f8cfc7ed9e57503de gpui_platform = { git = "https://github.com/zed-industries/zed", rev = "f8cfc7ed9e57503def9479138894f3139f5400cc", features = ["font-kit"] } reqwest_client = { git = "https://github.com/zed-industries/zed", rev = "f8cfc7ed9e57503def9479138894f3139f5400cc" } -gpui-native-kit = { git = "https://git.reya.info/reya/gpui-native-kit", rev = "dad833f998fecc0d828e716f3cbf0342d499db81", features = ["layout", "editor"] } +gpui-native-kit = { git = "https://git.reya.info/reya/gpui-native-kit", rev = "c3e3c37731e389d858712369e47eec9c205cdfbe", features = ["layout", "editor"] } settings = { path = "crates/settings" } signed_app = { path = "crates/signed_app" } diff --git a/crates/signed_app/src/app/mod.rs b/crates/signed_app/src/app/mod.rs index f0f58ee..0515787 100644 --- a/crates/signed_app/src/app/mod.rs +++ b/crates/signed_app/src/app/mod.rs @@ -76,6 +76,22 @@ impl AppRoot { apply_appearance(&settings, cx); })); + subscriptions.push(cx.observe(&dock, |this, dock, cx| { + let Some(panel) = dock.read(cx).active_panel() else { + return; + }; + + if !panel.starts_with("repo:") && !panel.starts_with("repo-local:") { + return; + } + + this.layout.update(cx, |layout, cx| { + if !layout.is_right_sidebar_visible() { + layout.set_right_sidebar_visible(true, cx); + } + }); + })); + window.defer(cx, move |_window, cx| { if backend.read(cx).passphrase_required() { identity::helpers::open_passphrase(cx); @@ -128,6 +144,7 @@ impl Render for AppRoot { .child( Shell::new("signed-shell", self.layout.clone()) .left_sidebar(self.sidebar.read(cx).build(cx)) + .right_sidebar(div()) .center( Dock::new("signed-dock", self.dock.clone()) .window_controls(true) diff --git a/crates/signed_app/src/explore/mod.rs b/crates/signed_app/src/explore/mod.rs index 33a13b7..d472a1b 100644 --- a/crates/signed_app/src/explore/mod.rs +++ b/crates/signed_app/src/explore/mod.rs @@ -127,11 +127,11 @@ impl ExploreView { Segmented::new("explore-filter", self.filter) .options(vec![ SegmentedOption::new(RepoFilter::All, "All") - .icon(Icon::named(CustomIconName::Grid).small().color(muted)), + .icon(Icon::named(IconRole::Grid).small().color(muted)), SegmentedOption::new(RepoFilter::Popular, "Popular") .icon(Icon::named(CustomIconName::Trending).small().color(muted)), SegmentedOption::new(RepoFilter::Recent, "Recent") - .icon(Icon::named(CustomIconName::Recent).small().color(muted)), + .icon(Icon::named(IconRole::Clock).small().color(muted)), ]) .on_change(move |filter, _, cx| { if let Err(error) = weak.update(cx, |this, cx| { diff --git a/crates/signed_app/src/identity/passphrase.rs b/crates/signed_app/src/identity/passphrase.rs index 14235ad..5060e27 100644 --- a/crates/signed_app/src/identity/passphrase.rs +++ b/crates/signed_app/src/identity/passphrase.rs @@ -1,4 +1,3 @@ -use assets::CustomIconName; use gpui::prelude::FluentBuilder as _; use gpui::{ AnyElement, App, AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, @@ -8,7 +7,7 @@ use gpui_native_kit::button::Button; use gpui_native_kit::common::v_flex; use gpui_native_kit::dialog::Dialog; use gpui_native_kit::field::Field; -use gpui_native_kit::icons::Icon; +use gpui_native_kit::icons::{Icon, IconRole}; use gpui_native_kit::input::{Input, InputState, InputStateEvent}; use signed_state::Backend; @@ -116,7 +115,7 @@ impl Render for PassphraseDialog { let unlock: AnyElement = Button::new("unlock") .label("Unlock") - .icon(Icon::named(CustomIconName::Unlock)) + .icon(Icon::named(IconRole::Unlock)) .loading(busy) .disabled(busy) .on_click(move |_, _, cx| { diff --git a/crates/signed_app/src/pull_requests/new.rs b/crates/signed_app/src/pull_requests/new.rs index 7da3b2d..fdd6a01 100644 --- a/crates/signed_app/src/pull_requests/new.rs +++ b/crates/signed_app/src/pull_requests/new.rs @@ -341,7 +341,7 @@ impl NewPullRequestView { .when_some(refresh_fork, |this, fork| { this.child( Button::new("refresh-fork") - .icon(Icon::named(CustomIconName::Refresh)) + .icon(Icon::named(IconRole::Refresh)) .on_click(cx.listener(move |this, _, window, cx| { this.choose_fork(fork.clone(), window, cx); })), diff --git a/crates/signed_app/src/repo/commit_diff.rs b/crates/signed_app/src/repo/commit_diff.rs index 21e9e9a..e016682 100644 --- a/crates/signed_app/src/repo/commit_diff.rs +++ b/crates/signed_app/src/repo/commit_diff.rs @@ -157,7 +157,7 @@ impl DiffPane { if row.expandable { item.icon(Icon::named(IconRole::Folder)) } else { - item + item.icon(Icon::named(IconRole::File)) } }) .collect() diff --git a/crates/signed_app/src/repo/files.rs b/crates/signed_app/src/repo/files.rs index 9676f04..a203b1c 100644 --- a/crates/signed_app/src/repo/files.rs +++ b/crates/signed_app/src/repo/files.rs @@ -272,7 +272,7 @@ impl RepoFilesView { if row.expandable { item.icon(Icon::named(IconRole::Folder)) } else { - item + item.icon(Icon::named(IconRole::File)) } }) .collect() diff --git a/crates/signed_app/src/repo/mod.rs b/crates/signed_app/src/repo/mod.rs index 5c2d842..7cfa0b0 100644 --- a/crates/signed_app/src/repo/mod.rs +++ b/crates/signed_app/src/repo/mod.rs @@ -1019,7 +1019,7 @@ impl RepoDetailView { .gap_1() .child( Button::new("sync-banner") - .icon(Icon::named(CustomIconName::Refresh)) + .icon(Icon::named(IconRole::Refresh)) .label("Sync now") .small() .loading(pushing) diff --git a/crates/signed_app/src/sidebar/helpers.rs b/crates/signed_app/src/sidebar/helpers.rs index c21583d..ca53981 100644 --- a/crates/signed_app/src/sidebar/helpers.rs +++ b/crates/signed_app/src/sidebar/helpers.rs @@ -2,7 +2,6 @@ use std::time::{SystemTime, UNIX_EPOCH}; use gpui::{AnyElement, App, IntoElement, SharedString}; use gpui_native_kit::avatar::Avatar; -use gpui_native_kit::common::Sizable as _; use metadata::ProfileDirectory; use signed_state::{Nip34Binding, ResolvedLocalRepo}; @@ -36,9 +35,7 @@ pub(super) fn local_avatar( cx: &App, ) -> AnyElement { let Some(owner) = entry.nip34.as_ref().and_then(|binding| binding.owner) else { - return Avatar::new(entry.path.to_string_lossy()) - .small() - .into_any_element(); + return Avatar::new(entry.path.to_string_lossy()).into_any_element(); }; let profile = directory.read(cx).profile(&owner, cx); @@ -46,6 +43,5 @@ pub(super) fn local_avatar( Avatar::new(owner) .name(profile.name()) .picture(profile.picture()) - .small() .into_any_element() } diff --git a/crates/signed_app/src/sidebar/mod.rs b/crates/signed_app/src/sidebar/mod.rs index 2141b94..6bcddf4 100644 --- a/crates/signed_app/src/sidebar/mod.rs +++ b/crates/signed_app/src/sidebar/mod.rs @@ -9,7 +9,7 @@ use gpui::{ use gpui_native_kit::avatar::Avatar; use gpui_native_kit::badge::{Badge, BadgeVariant}; use gpui_native_kit::button::{Button, ButtonVariant}; -use gpui_native_kit::common::{Sizable as _, h_flex, v_flex}; +use gpui_native_kit::common::{h_flex, v_flex}; use gpui_native_kit::data::sidebar::{Sidebar, SidebarEntry}; use gpui_native_kit::icons::{Icon, IconRole}; use gpui_native_kit::layout::dock::DockState; @@ -28,6 +28,7 @@ use signed_state::{ use crate::explore::ExploreView; use crate::inbox::InboxView; use crate::repo::dialogs; +use crate::shared::log_dropped; use crate::{identity, settings}; mod helpers; @@ -232,56 +233,49 @@ impl SidebarView { .footer(self.render_footer(cx)) .entries(move |_, cx| { let muted = cx.theme().colors.muted_foreground; + let mut entries = vec![ SidebarEntry::row("inbox", "Inbox") - .prefix(Icon::named(CustomIconName::Inbox).small().color(muted)), + .prefix(Icon::named(CustomIconName::Inbox).color(muted)), SidebarEntry::row("browse", "Browse") - .prefix(Icon::named(CustomIconName::Globe).small().color(muted)), + .prefix(Icon::named(CustomIconName::Globe).color(muted)), SidebarEntry::row("search", "Search") - .prefix(Icon::named(IconRole::Search).small().color(muted)), - SidebarEntry::header("All Repositories"), + .prefix(Icon::named(IconRole::Search).color(muted)), + SidebarEntry::header("Repositories"), ]; for announcement in announcements.iter() { + let addr = announcement.addr(); let owner = directory.read(cx).profile(&announcement.owner, cx); + + let count = unpushed.get(&addr).copied().unwrap_or(0); + let unsynced = sync_directory.read(cx).unsynced(&addr, cx); + let name = announcement .name .as_deref() .map(SharedString::from) .unwrap_or_else(|| SharedString::from(announcement.id.clone())); - let addr = announcement.addr(); - let mut row = SidebarEntry::row( - SharedString::from(format!("repo:{}", announcement.id)), - name, - ) - .prefix( - Avatar::new(announcement.owner) - .name(owner.name()) - .picture(owner.picture()) - .small(), - ); - let count = unpushed.get(&addr).copied().unwrap_or(0); - let unsynced = sync_directory.read(cx).unsynced(&addr, cx); + let mut row = SidebarEntry::row(format!("repo:{}", announcement.id), name) + .prefix( + Avatar::new(announcement.owner) + .name(owner.name()) + .picture(owner.picture()), + ); if count > 0 || unsynced > 0 { let mut badges = h_flex().gap_1(); if count > 0 { badges = badges.child( - Badge::new( - SharedString::from(format!("unpushed:{addr}")), - count.to_string(), - ) - .variant(BadgeVariant::Danger), + Badge::new(format!("unpushed:{addr}"), count.to_string()) + .variant(BadgeVariant::Warning), ); } if unsynced > 0 { badges = badges.child( - Badge::new( - SharedString::from(format!("unsynced:{addr}")), - unsynced.to_string(), - ) - .variant(BadgeVariant::Accent), + Badge::new(format!("unsynced:{addr}"), unsynced.to_string()) + .variant(BadgeVariant::Accent), ); } row = row.suffix(badges); @@ -301,31 +295,19 @@ impl SidebarView { Nip34Kind::Cloned => ("Cloned", "Cloned but not initialized"), Nip34Kind::ToolingOnly => ("Tooling", "Grasp tooling only"), }; - Badge::new( - SharedString::from(format!("local-badge:{}", entry.path.display())), - label, - ) - .tooltip(Tooltip::text(note)) - .into_any_element() + Badge::new(format!("lbadge:{}", entry.path.display()), label) + .tooltip(Tooltip::text(note)) + .into_any_element() } - None => Badge::new( - SharedString::from(format!( - "local-unpublished:{}", - entry.path.display() - )), - "Unpublished", - ) - .variant(BadgeVariant::Warning) - .into_any_element(), + None => Badge::new(format!("un-{}", entry.path.display()), "Unpublished") + .variant(BadgeVariant::Outline) + .into_any_element(), }; entries.push( - SidebarEntry::row( - SharedString::from(format!("local-repo:{}", entry.path.display())), - entry.name(), - ) - .prefix(local_avatar(entry, &directory, cx)) - .suffix(suffix), + SidebarEntry::row(format!("lrepo:{}", entry.path.display()), entry.name()) + .prefix(local_avatar(entry, &directory, cx)) + .suffix(suffix), ); } @@ -417,6 +399,7 @@ impl SidebarView { let id = SharedString::from(format!("repo-local:{}", path.display())); let dock = self.dock.clone(); let dock_for_build = dock.clone(); + crate::shared::panels::open( &dock, id, @@ -438,9 +421,6 @@ impl SidebarView { fn render_footer(&self, _cx: &App) -> impl IntoElement { let guide_weak = self.weak.clone(); - let settings_click = |_: &gpui::ClickEvent, _: &mut Window, cx: &mut gpui::App| { - settings::open(cx); - }; v_flex() .p_2() @@ -448,19 +428,25 @@ impl SidebarView { .w_full() .child( Button::new("guide") + .icon(IconRole::Info) .label("Guide") + .side(gpui_native_kit::button::ButtonSide::Left) .variant(ButtonVariant::Ghost) .on_click(move |_, window, cx| { - crate::shared::log_dropped(guide_weak.update(cx, |this, cx| { + log_dropped(guide_weak.update(cx, |this, cx| { this.open_explore(window, cx); })); }), ) .child( Button::new("settings") + .icon(IconRole::Settings) .label("Settings") + .side(gpui_native_kit::button::ButtonSide::Left) .variant(ButtonVariant::Ghost) - .on_click(settings_click), + .on_click(|_, _, cx| { + settings::open(cx); + }), ) } diff --git a/docs/gpui-native-kit-gaps.md b/docs/gpui-native-kit-gaps.md index b09db63..fee3e0d 100644 --- a/docs/gpui-native-kit-gaps.md +++ b/docs/gpui-native-kit-gaps.md @@ -19,8 +19,8 @@ modifying the kit or reimplementing a parallel mechanism. plain text. 6. **Hunk-only diffs.** Kit `DiffViewState` needs the full old and new texts; `CommitDiff` carries hunks only. The custom hunk rows are retained. -7. **Tree data.** The kit tree is flat with caller-managed expansion, and has no - file glyph; folders use the folder role. +7. **Tree data.** The kit tree is flat with caller-managed expansion. + Folder rows use `IconRole::Folder` and file rows use `IconRole::File`. 8. **Dynamic dock panels.** `DockState` has no unregister or `open_view` API. Per-repository/per-entity panels register a builder keyed by a unique id and stay in the builder map. No dock persistence, zoom, or bottom/right @@ -34,6 +34,7 @@ modifying the kit or reimplementing a parallel mechanism. into labels. 12. **Combobox trigger.** `Combobox` has no custom trigger renderer; branch/tag selectors lose the leading git icon and custom caret. -13. **Icons.** The built-in role set is limited. App-specific glyphs remain in - `assets::CustomIconName` through `IconNamed`; kit icons are unpainted - unless given a color. +13. **Icons.** The kit provides common platform roles plus Settings, Help, + Refresh, File, Folder, and similar glyphs. App-specific git, issue, and + pull-request glyphs remain in `assets::CustomIconName` through `IconNamed`; + kit icons are unpainted unless given a color.