setting: Add scrollbar to SettingPage. (#1660)
This commit is contained in:
parent
857f7973e3
commit
fc36451a27
5 changed files with 104 additions and 76 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
App, AppContext, Axis, Context, Element, Entity, FocusHandle, Focusable, Global, IntoElement,
|
App, AppContext, Axis, Context, Element, Entity, FocusHandle, Focusable, Global, IntoElement,
|
||||||
ParentElement as _, Render, SharedString, Styled, Window,
|
ParentElement as _, Render, SharedString, Styled, Window, px,
|
||||||
};
|
};
|
||||||
|
|
||||||
use gpui_component::{
|
use gpui_component::{
|
||||||
|
|
@ -99,6 +99,10 @@ impl super::Story for SettingsStory {
|
||||||
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
|
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
|
||||||
Self::view(window, cx)
|
Self::view(window, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn paddings() -> gpui::Pixels {
|
||||||
|
px(0.)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SettingsStory {
|
impl SettingsStory {
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ impl Render for SidebarStory {
|
||||||
Sidebar::new(self.side)
|
Sidebar::new(self.side)
|
||||||
.collapsed(self.collapsed)
|
.collapsed(self.collapsed)
|
||||||
.w(px(220.))
|
.w(px(220.))
|
||||||
.p_3()
|
.gap_0()
|
||||||
.header(
|
.header(
|
||||||
SidebarHeader::new()
|
SidebarHeader::new()
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
list, prelude::FluentBuilder as _, px, App, Entity, InteractiveElement as _, IntoElement,
|
div, list, prelude::FluentBuilder as _, px, App, Entity, InteractiveElement as _, IntoElement,
|
||||||
ParentElement as _, SharedString, StatefulInteractiveElement, Styled, Window,
|
ListAlignment, ListState, ParentElement as _, SharedString, Styled, Window,
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
button::{Button, ButtonVariants},
|
button::{Button, ButtonVariants},
|
||||||
divider::Divider,
|
|
||||||
h_flex,
|
h_flex,
|
||||||
label::Label,
|
label::Label,
|
||||||
|
scroll::{Scrollbar, ScrollbarState},
|
||||||
setting::{settings::SettingsState, RenderOptions, SettingGroup},
|
setting::{settings::SettingsState, RenderOptions, SettingGroup},
|
||||||
v_flex, ActiveTheme, IconName, Sizable,
|
v_flex, ActiveTheme, IconName, Sizable,
|
||||||
};
|
};
|
||||||
|
|
@ -100,11 +100,16 @@ impl SettingPage {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let groups_count = groups.len();
|
let groups_count = groups.len();
|
||||||
|
|
||||||
let list_state = window
|
let (scroll_state, list_state) = window
|
||||||
.use_keyed_state(
|
.use_keyed_state(
|
||||||
SharedString::from(format!("list-state:{}", ix)),
|
SharedString::from(format!("list-state:{}", ix)),
|
||||||
cx,
|
cx,
|
||||||
|_, _| gpui::ListState::new(groups_count, gpui::ListAlignment::Top, px(0.)),
|
|_, _| {
|
||||||
|
(
|
||||||
|
ScrollbarState::default(),
|
||||||
|
ListState::new(groups_count, ListAlignment::Top, px(100.)),
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.clone();
|
.clone();
|
||||||
|
|
@ -123,12 +128,13 @@ impl SettingPage {
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.id(ix)
|
.id(ix)
|
||||||
.p_4()
|
|
||||||
.size_full()
|
.size_full()
|
||||||
.overflow_scroll()
|
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.p_4()
|
||||||
.gap_3()
|
.gap_3()
|
||||||
|
.border_b_1()
|
||||||
|
.border_color(cx.theme().border)
|
||||||
.child(h_flex().justify_between().child(self.title.clone()).when(
|
.child(h_flex().justify_between().child(self.title.clone()).when(
|
||||||
self.is_resettable(cx),
|
self.is_resettable(cx),
|
||||||
|this| {
|
|this| {
|
||||||
|
|
@ -153,22 +159,37 @@ impl SettingPage {
|
||||||
.text_sm()
|
.text_sm()
|
||||||
.text_color(cx.theme().muted_foreground),
|
.text_color(cx.theme().muted_foreground),
|
||||||
)
|
)
|
||||||
})
|
}),
|
||||||
.child(Divider::horizontal()),
|
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
list(list_state.clone(), {
|
div()
|
||||||
let query = query.clone();
|
.px_4()
|
||||||
let options = *options;
|
.relative()
|
||||||
move |ix, window, cx| {
|
.flex_1()
|
||||||
let group = groups[ix].clone();
|
.w_full()
|
||||||
group
|
.child(
|
||||||
.pt_6()
|
list(list_state.clone(), {
|
||||||
.render(ix, &query, &options, window, cx)
|
let query = query.clone();
|
||||||
.into_any_element()
|
let options = *options;
|
||||||
}
|
move |ix, window, cx| {
|
||||||
})
|
let group = groups[ix].clone();
|
||||||
.size_full(),
|
group
|
||||||
|
.py_4()
|
||||||
|
.render(ix, &query, &options, window, cx)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.size_full(),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.absolute()
|
||||||
|
.top_0()
|
||||||
|
.left_0()
|
||||||
|
.right_0()
|
||||||
|
.bottom_0()
|
||||||
|
.child(Scrollbar::vertical(&scroll_state, &list_state)),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ use crate::{
|
||||||
resizable::{h_resizable, resizable_panel},
|
resizable::{h_resizable, resizable_panel},
|
||||||
setting::{SettingGroup, SettingPage},
|
setting::{SettingGroup, SettingPage},
|
||||||
sidebar::{Sidebar, SidebarMenu, SidebarMenuItem},
|
sidebar::{Sidebar, SidebarMenu, SidebarMenuItem},
|
||||||
IconName, Sizable, Size,
|
IconName, Sizable, Size, StyledExt,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, relative, App, AppContext as _, Axis, ElementId, Entity,
|
div, prelude::FluentBuilder as _, px, relative, App, AppContext as _, Axis, ElementId, Entity,
|
||||||
IntoElement, ParentElement as _, Pixels, RenderOnce, Styled, Window,
|
IntoElement, ParentElement as _, Pixels, RenderOnce, StyleRefinement, Styled, Window,
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
|
|
@ -31,6 +31,7 @@ pub struct Settings {
|
||||||
group_variant: GroupBoxVariant,
|
group_variant: GroupBoxVariant,
|
||||||
size: Size,
|
size: Size,
|
||||||
sidebar_width: Pixels,
|
sidebar_width: Pixels,
|
||||||
|
sidebar_style: StyleRefinement,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
|
|
@ -42,6 +43,7 @@ impl Settings {
|
||||||
group_variant: GroupBoxVariant::default(),
|
group_variant: GroupBoxVariant::default(),
|
||||||
size: Size::default(),
|
size: Size::default(),
|
||||||
sidebar_width: px(250.0),
|
sidebar_width: px(250.0),
|
||||||
|
sidebar_style: StyleRefinement::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,6 +73,12 @@ impl Settings {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the style refinement for the sidebar.
|
||||||
|
pub fn sidebar_style(mut self, style: &StyleRefinement) -> Self {
|
||||||
|
self.sidebar_style = style.clone();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn filtered_pages(&self, query: &str) -> Vec<SettingPage> {
|
fn filtered_pages(&self, query: &str) -> Vec<SettingPage> {
|
||||||
self.pages
|
self.pages
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -138,6 +146,7 @@ impl Settings {
|
||||||
Sidebar::left()
|
Sidebar::left()
|
||||||
.w(relative(1.))
|
.w(relative(1.))
|
||||||
.border_0()
|
.border_0()
|
||||||
|
.refine_style(&self.sidebar_style)
|
||||||
.collapsed(false)
|
.collapsed(false)
|
||||||
.header(
|
.header(
|
||||||
div()
|
div()
|
||||||
|
|
@ -145,57 +154,52 @@ impl Settings {
|
||||||
.child(Input::new(&search_input).prefix(IconName::Search)),
|
.child(Input::new(&search_input).prefix(IconName::Search)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
SidebarMenu::new()
|
SidebarMenu::new().children(pages.iter().enumerate().map(|(page_ix, page)| {
|
||||||
.p_2()
|
let is_page_active =
|
||||||
.children(pages.iter().enumerate().map(|(page_ix, page)| {
|
selected_index.page_ix == page_ix && selected_index.group_ix.is_none();
|
||||||
let is_page_active =
|
SidebarMenuItem::new(page.title.clone())
|
||||||
selected_index.page_ix == page_ix && selected_index.group_ix.is_none();
|
.default_open(page.default_open)
|
||||||
SidebarMenuItem::new(page.title.clone())
|
.active(is_page_active)
|
||||||
.default_open(page.default_open)
|
.on_click({
|
||||||
.active(is_page_active)
|
let state = state.clone();
|
||||||
.on_click({
|
move |_, _, cx| {
|
||||||
let state = state.clone();
|
state.update(cx, |state, cx| {
|
||||||
move |_, _, cx| {
|
state.selected_index = SelectIndex {
|
||||||
state.update(cx, |state, cx| {
|
page_ix,
|
||||||
state.selected_index = SelectIndex {
|
..Default::default()
|
||||||
page_ix,
|
};
|
||||||
..Default::default()
|
cx.notify();
|
||||||
};
|
})
|
||||||
cx.notify();
|
}
|
||||||
})
|
})
|
||||||
}
|
.when(page.groups.len() > 1, |this| {
|
||||||
})
|
this.children(
|
||||||
.when(page.groups.len() > 1, |this| {
|
page.groups
|
||||||
this.children(
|
.iter()
|
||||||
page.groups
|
.filter(|g| g.title.is_some())
|
||||||
.iter()
|
.enumerate()
|
||||||
.filter(|g| g.title.is_some())
|
.map(|(group_ix, group)| {
|
||||||
.enumerate()
|
let is_active = selected_index.page_ix == page_ix
|
||||||
.map(|(group_ix, group)| {
|
&& selected_index.group_ix == Some(group_ix);
|
||||||
let is_active = selected_index.page_ix == page_ix
|
let title = group.title.clone().unwrap_or_default();
|
||||||
&& selected_index.group_ix == Some(group_ix);
|
|
||||||
let title = group.title.clone().unwrap_or_default();
|
|
||||||
|
|
||||||
SidebarMenuItem::new(title).active(is_active).on_click(
|
SidebarMenuItem::new(title).active(is_active).on_click({
|
||||||
{
|
let state = state.clone();
|
||||||
let state = state.clone();
|
move |_, _, cx| {
|
||||||
move |_, _, cx| {
|
state.update(cx, |state, cx| {
|
||||||
state.update(cx, |state, cx| {
|
state.selected_index = SelectIndex {
|
||||||
state.selected_index = SelectIndex {
|
page_ix,
|
||||||
page_ix,
|
group_ix: Some(group_ix),
|
||||||
group_ix: Some(group_ix),
|
};
|
||||||
};
|
state.deferred_scroll_group_ix = Some(group_ix);
|
||||||
state.deferred_scroll_group_ix =
|
cx.notify();
|
||||||
Some(group_ix);
|
})
|
||||||
cx.notify();
|
}
|
||||||
})
|
})
|
||||||
}
|
}),
|
||||||
},
|
)
|
||||||
)
|
})
|
||||||
}),
|
})),
|
||||||
)
|
|
||||||
})
|
|
||||||
})),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,6 @@ impl<E: Collapsible + IntoElement> RenderOnce for Sidebar<E> {
|
||||||
.w(DEFAULT_WIDTH)
|
.w(DEFAULT_WIDTH)
|
||||||
.flex_shrink_0()
|
.flex_shrink_0()
|
||||||
.h_full()
|
.h_full()
|
||||||
.gap_3()
|
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.relative()
|
.relative()
|
||||||
.bg(cx.theme().sidebar)
|
.bg(cx.theme().sidebar)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue