add right sidebar auto-open to dock panels

This commit is contained in:
2026-11-02 20:26:49 +07:00
parent a6014b4ff3
commit 9d5cf5684f
4 changed files with 287 additions and 15 deletions
+119 -1
View File
@@ -3,8 +3,10 @@ use gpui::{
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Render, Styled as _,
TestAppContext, VisualTestContext, Window, div, point, px,
};
use gpui_native_layout::dock::{Dock, DockState, PanelDescriptor, SplitDirection};
use gpui_native_layout::dock::{Dock, DockSidebar, DockState, PanelDescriptor, SplitDirection};
use gpui_native_theme::Theme;
use std::cell::Cell;
use std::rc::Rc;
struct Panel {
tag: &'static str,
@@ -18,10 +20,28 @@ impl Render for Panel {
}
}
/// The right sidebar view a panel declares.
struct SidePanel {
tag: &'static str,
}
impl Render for SidePanel {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.size_full()
.debug_selector(move || format!("side-{}", self.tag))
}
}
fn descriptor(tag: &'static str) -> PanelDescriptor {
PanelDescriptor::new(tag, tag, move |_, cx| cx.new(|_| Panel { tag }).into())
}
fn descriptor_with_right_sidebar(tag: &'static str) -> PanelDescriptor {
PanelDescriptor::new(tag, tag, move |_, cx| cx.new(|_| Panel { tag }).into())
.right_sidebar(move |_, cx| cx.new(|_| SidePanel { tag }).into())
}
struct Harness {
dock: Entity<DockState>,
}
@@ -420,3 +440,101 @@ fn close_others_keeps_one_and_close_pane_empties() {
open(&mut visual, &dock, "inbox");
assert!(bounds(&mut visual, "test-dock-pane-0-tabs-tab-inbox").is_some());
}
struct SidebarHarness {
dock: Entity<DockState>,
}
impl Render for SidebarHarness {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.size_full()
.flex()
.flex_row()
.child(
div()
.flex_1()
.child(Dock::new("test-dock", self.dock.clone())),
)
.child(
div()
.w(px(160.))
.child(DockSidebar::new("test-dock-sidebar", self.dock.clone())),
)
}
}
fn sidebar_window(
cx: &mut TestAppContext,
) -> (Entity<DockState>, Rc<Cell<bool>>, VisualTestContext) {
cx.update(Theme::init);
let dock = cx.update(DockState::new);
let opened = Rc::new(Cell::new(false));
let opened_for_dock = opened.clone();
let dock_for_window = dock.clone();
let window = cx.add_window(move |_, _| SidebarHarness {
dock: dock_for_window,
});
dock.update(cx, |dock, _| {
dock.on_open_right_sidebar(move |cx| {
opened_for_dock.set(true);
let _ = cx;
});
});
let mut visual = VisualTestContext::from_window(window.into(), cx);
visual.update(|window, cx| window.draw(cx).clear(cx));
(dock, opened, visual)
}
#[test]
fn activating_a_panel_with_a_right_view_opens_the_sidebar() {
let mut cx = TestAppContext::single();
let (dock, opened, mut visual) = sidebar_window(&mut cx);
cx.update(|cx| {
dock.update(cx, |dock, cx| {
dock.register_panel(descriptor_with_right_sidebar("overview"), cx);
dock.register_panel(descriptor("inbox"), cx);
});
});
open(&mut visual, &dock, "overview");
assert!(
opened.get(),
"activation must ask the app to open the sidebar"
);
assert!(
bounds(&mut visual, "side-overview").is_some(),
"the sidebar shows the panel's own view"
);
// A panel without a right view leaves the sidebar showing the last one.
open(&mut visual, &dock, "inbox");
assert!(opened.get());
assert!(bounds(&mut visual, "side-overview").is_some());
}
#[test]
fn closing_the_displayed_tab_falls_back_to_another_right_view() {
let mut cx = TestAppContext::single();
let (dock, opened, mut visual) = sidebar_window(&mut cx);
cx.update(|cx| {
dock.update(cx, |dock, cx| {
dock.register_panel(descriptor_with_right_sidebar("overview"), cx);
dock.register_panel(descriptor_with_right_sidebar("explore"), cx);
});
});
open(&mut visual, &dock, "overview");
open(&mut visual, &dock, "explore");
assert!(bounds(&mut visual, "side-explore").is_some());
cx.update(|cx| {
dock.update(cx, |dock, cx| dock.close_panel("explore", cx));
});
redraw(&mut visual);
assert!(
bounds(&mut visual, "side-overview").is_some(),
"the sidebar falls back to a remaining panel's view"
);
let _ = opened;
}