update sidebar

This commit is contained in:
2026-08-06 14:21:03 +07:00
parent 627abbdcaf
commit 6d5d154486
4 changed files with 319 additions and 290 deletions
+170
View File
@@ -0,0 +1,170 @@
use std::sync::Arc;
use gpui::prelude::*;
use gpui::{
App, Context, EventEmitter, FocusHandle, Focusable, Render, Subscription, WeakEntity, Window,
div,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{DockArea, DockPlacement, Panel, PanelEvent};
use gpui_component::input::InputState;
use gpui_component::{ActiveTheme, v_flex};
use signed_state::{Backend, BackendEvent};
use super::RepoListView;
mod import_identity_dialog;
mod onboarding_dialog;
use self::onboarding_dialog::OnboardingState;
/// Left-dock panel with navigation entries. Entries open content panels in
/// the dock area.
pub struct SidebarPanel {
focus_handle: FocusHandle,
dock_area: WeakEntity<DockArea>,
explore: Option<WeakEntity<RepoListView>>,
logged_in: bool,
_subscription: Subscription,
}
impl SidebarPanel {
pub fn new(dock_area: WeakEntity<DockArea>, cx: &mut Context<Self>) -> Self {
let backend = Backend::global(cx);
let logged_in = backend.read(cx).current_user().is_some();
let subscription = cx.subscribe(&backend, |this, backend, event, cx| {
match event {
BackendEvent::SignerChanged => {
this.logged_in = backend.read(cx).current_user().is_some();
}
BackendEvent::SignerRequired => {
this.logged_in = false;
}
_ => return,
}
cx.notify();
});
Self {
focus_handle: cx.focus_handle(),
dock_area,
explore: None,
logged_in,
_subscription: subscription,
}
}
/// Open the Explore (repository list) panel in the center of the dock
/// area. No-op if it's already open.
pub fn open_explore(&mut self, window: &mut Window, cx: &mut Context<Self>) {
if self
.explore
.as_ref()
.and_then(WeakEntity::upgrade)
.is_some()
{
return;
}
let panel = cx.new(|cx| RepoListView::new(window, cx));
self.explore = Some(panel.downgrade());
let _ = self.dock_area.update(cx, |dock_area, cx| {
dock_area.add_panel(Arc::new(panel), DockPlacement::Center, None, window, cx);
});
}
/// Show the Onboarding dialog.
fn open_onboarding(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let name_input = cx.new(|cx| InputState::new(window, cx).placeholder("Enter desired name"));
let pass_input = cx.new(|cx| {
InputState::new(window, cx)
.placeholder("Passphrase to protect your keys")
.masked(true)
});
let repass_input = cx.new(|cx| {
InputState::new(window, cx)
.placeholder("Repeat passphrase")
.masked(true)
});
let state = cx.new(|_| OnboardingState::default());
onboarding_dialog::open(name_input, pass_input, repass_input, state, window, cx);
}
/// Show the Import Identity dialog.
fn open_import(&mut self, window: &mut Window, cx: &mut Context<Self>) {
import_identity_dialog::open(window, cx);
}
}
impl Panel for SidebarPanel {
fn panel_name(&self) -> &'static str {
"sidebar"
}
fn title(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
}
fn closable(&self, _cx: &App) -> bool {
false
}
fn inner_padding(&self, _cx: &App) -> bool {
false
}
}
impl EventEmitter<PanelEvent> for SidebarPanel {}
impl Focusable for SidebarPanel {
fn focus_handle(&self, _cx: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl Render for SidebarPanel {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if self.logged_in {
v_flex().child(
Button::new("explore")
.label("Explore")
.w_full()
.on_click(cx.listener(|this, _, window, cx| this.open_explore(window, cx))),
)
} else {
v_flex()
.p_4()
.size_full()
.items_center()
.justify_center()
.gap_2()
.child(
div()
.text_sm()
.text_color(cx.theme().muted_foreground)
.child("Sign in to continue"),
)
.child(
Button::new("onboarding")
.label("Join now")
.primary()
.w_full()
.on_click(
cx.listener(|this, _ev, window, cx| this.open_onboarding(window, cx)),
),
)
.child(
Button::new("import-identity")
.label("Import identity")
.secondary()
.w_full()
.on_click(
cx.listener(|this, _ev, window, cx| this.open_import(window, cx)),
),
)
}
}
}