sidebar: Refactor Sidebar to support Styled. (#1658)
## Break Change
- The `width`, `border_width` method has been removed from Sidebar, use
`Styled` trait to use `w`, `border` method from GPUI instead.
```diff
Sidebar::left()
- .width(relative(1.))
- .border_width(px(0.))
+ .w(relative(1.))
+ .border_0()
.collapsed(false)
```
This commit is contained in:
parent
44829a05e4
commit
c523b3485b
6 changed files with 68 additions and 41 deletions
|
|
@ -158,8 +158,8 @@ impl Render for Gallery {
|
||||||
.size_range(px(200.)..px(320.))
|
.size_range(px(200.)..px(320.))
|
||||||
.child(
|
.child(
|
||||||
Sidebar::left()
|
Sidebar::left()
|
||||||
.width(relative(1.))
|
.w(relative(1.))
|
||||||
.border_width(px(0.))
|
.border_0()
|
||||||
.collapsed(self.collapsed)
|
.collapsed(self.collapsed)
|
||||||
.header(
|
.header(
|
||||||
v_flex()
|
v_flex()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Action, App, AppContext, ClickEvent, Context, Entity, Focusable, IntoElement, ParentElement,
|
Action, App, AppContext, ClickEvent, Context, Entity, Focusable, IntoElement, ParentElement,
|
||||||
Render, SharedString, Styled, Window, div, prelude::FluentBuilder, relative,
|
Render, SharedString, Styled, Window, div, prelude::FluentBuilder, px, relative,
|
||||||
};
|
};
|
||||||
|
|
||||||
use gpui_component::{
|
use gpui_component::{
|
||||||
|
|
@ -280,9 +280,10 @@ impl Render for SidebarStory {
|
||||||
.child(
|
.child(
|
||||||
Sidebar::new(self.side)
|
Sidebar::new(self.side)
|
||||||
.collapsed(self.collapsed)
|
.collapsed(self.collapsed)
|
||||||
|
.w(px(220.))
|
||||||
|
.p_3()
|
||||||
.header(
|
.header(
|
||||||
SidebarHeader::new()
|
SidebarHeader::new()
|
||||||
.w_full()
|
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,8 @@ impl Settings {
|
||||||
let search_input = state.read(cx).search_input.clone();
|
let search_input = state.read(cx).search_input.clone();
|
||||||
|
|
||||||
Sidebar::left()
|
Sidebar::left()
|
||||||
.width(relative(1.))
|
.w(relative(1.))
|
||||||
.border_width(px(0.))
|
.border_0()
|
||||||
.collapsed(false)
|
.collapsed(false)
|
||||||
.header(
|
.header(
|
||||||
div()
|
div()
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@ impl<E: Collapsible + IntoElement> RenderOnce for SidebarGroup<E> {
|
||||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
v_flex()
|
v_flex()
|
||||||
.relative()
|
.relative()
|
||||||
.p_2()
|
|
||||||
.when(!self.collapsed, |this| {
|
.when(!self.collapsed, |this| {
|
||||||
this.child(
|
this.child(
|
||||||
div()
|
div()
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
prelude::FluentBuilder as _, Div, InteractiveElement, IntoElement, ParentElement, RenderOnce,
|
div, prelude::FluentBuilder as _, AnyElement, Div, InteractiveElement, IntoElement,
|
||||||
Styled,
|
ParentElement, RenderOnce, StyleRefinement, Styled,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{h_flex, menu::DropdownMenu, ActiveTheme as _, Collapsible, Selectable};
|
use crate::{menu::DropdownMenu, ActiveTheme as _, Collapsible, Selectable, StyledExt};
|
||||||
|
|
||||||
/// Header for the [`super::Sidebar`]
|
/// Header for the [`super::Sidebar`]
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct SidebarHeader {
|
pub struct SidebarHeader {
|
||||||
base: Div,
|
base: Div,
|
||||||
|
style: StyleRefinement,
|
||||||
|
children: Vec<AnyElement>,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
collapsed: bool,
|
collapsed: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -17,13 +19,21 @@ impl SidebarHeader {
|
||||||
/// Create a new [`SidebarHeader`].
|
/// Create a new [`SidebarHeader`].
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: h_flex().gap_2().w_full(),
|
base: div(),
|
||||||
|
style: StyleRefinement::default(),
|
||||||
|
children: Vec::new(),
|
||||||
selected: false,
|
selected: false,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for SidebarHeader {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Selectable for SidebarHeader {
|
impl Selectable for SidebarHeader {
|
||||||
fn selected(mut self, selected: bool) -> Self {
|
fn selected(mut self, selected: bool) -> Self {
|
||||||
self.selected = selected;
|
self.selected = selected;
|
||||||
|
|
@ -48,13 +58,13 @@ impl Collapsible for SidebarHeader {
|
||||||
|
|
||||||
impl ParentElement for SidebarHeader {
|
impl ParentElement for SidebarHeader {
|
||||||
fn extend(&mut self, elements: impl IntoIterator<Item = gpui::AnyElement>) {
|
fn extend(&mut self, elements: impl IntoIterator<Item = gpui::AnyElement>) {
|
||||||
self.base.extend(elements);
|
self.children.extend(elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Styled for SidebarHeader {
|
impl Styled for SidebarHeader {
|
||||||
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
||||||
self.base.style()
|
&mut self.style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,13 +78,15 @@ impl DropdownMenu for SidebarHeader {}
|
||||||
|
|
||||||
impl RenderOnce for SidebarHeader {
|
impl RenderOnce for SidebarHeader {
|
||||||
fn render(self, _: &mut gpui::Window, cx: &mut gpui::App) -> impl gpui::IntoElement {
|
fn render(self, _: &mut gpui::Window, cx: &mut gpui::App) -> impl gpui::IntoElement {
|
||||||
h_flex()
|
self.base
|
||||||
.id("sidebar-header")
|
.id("sidebar-header")
|
||||||
|
.h_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.p_2()
|
.p_2()
|
||||||
.w_full()
|
.w_full()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.rounded(cx.theme().radius)
|
.rounded(cx.theme().radius)
|
||||||
|
.refine_style(&self.style)
|
||||||
.hover(|this| {
|
.hover(|this| {
|
||||||
this.bg(cx.theme().sidebar_accent)
|
this.bg(cx.theme().sidebar_accent)
|
||||||
.text_color(cx.theme().sidebar_accent_foreground)
|
.text_color(cx.theme().sidebar_accent_foreground)
|
||||||
|
|
@ -83,6 +95,6 @@ impl RenderOnce for SidebarHeader {
|
||||||
this.bg(cx.theme().sidebar_accent)
|
this.bg(cx.theme().sidebar_accent)
|
||||||
.text_color(cx.theme().sidebar_accent_foreground)
|
.text_color(cx.theme().sidebar_accent_foreground)
|
||||||
})
|
})
|
||||||
.child(self.base)
|
.children(self.children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ use crate::{
|
||||||
v_flex, ActiveTheme, Collapsible, Icon, IconName, Side, Sizable, StyledExt,
|
v_flex, ActiveTheme, Collapsible, Icon, IconName, Side, Sizable, StyledExt,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder, px, AnyElement, App, ClickEvent, DefiniteLength,
|
div, prelude::FluentBuilder, px, AnyElement, App, ClickEvent, EdgesRefinement,
|
||||||
InteractiveElement as _, IntoElement, ParentElement, Pixels, RenderOnce, Styled, Window,
|
InteractiveElement as _, IntoElement, ParentElement, Pixels, RenderOnce, StyleRefinement,
|
||||||
|
Styled, Window,
|
||||||
};
|
};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
|
@ -25,6 +26,7 @@ const COLLAPSED_WIDTH: Pixels = px(48.);
|
||||||
/// A Sidebar element that can contain collapsible child elements.
|
/// A Sidebar element that can contain collapsible child elements.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct Sidebar<E: Collapsible + IntoElement + 'static> {
|
pub struct Sidebar<E: Collapsible + IntoElement + 'static> {
|
||||||
|
style: StyleRefinement,
|
||||||
content: Vec<E>,
|
content: Vec<E>,
|
||||||
/// header view
|
/// header view
|
||||||
header: Option<AnyElement>,
|
header: Option<AnyElement>,
|
||||||
|
|
@ -33,8 +35,6 @@ pub struct Sidebar<E: Collapsible + IntoElement + 'static> {
|
||||||
/// The side of the sidebar
|
/// The side of the sidebar
|
||||||
side: Side,
|
side: Side,
|
||||||
collapsible: bool,
|
collapsible: bool,
|
||||||
width: DefiniteLength,
|
|
||||||
border_width: Pixels,
|
|
||||||
collapsed: bool,
|
collapsed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,13 +42,12 @@ impl<E: Collapsible + IntoElement> Sidebar<E> {
|
||||||
/// Create a new Sidebar on the given [`Side`].
|
/// Create a new Sidebar on the given [`Side`].
|
||||||
pub fn new(side: Side) -> Self {
|
pub fn new(side: Side) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
style: StyleRefinement::default(),
|
||||||
content: vec![],
|
content: vec![],
|
||||||
header: None,
|
header: None,
|
||||||
footer: None,
|
footer: None,
|
||||||
side,
|
side,
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
width: DEFAULT_WIDTH.into(),
|
|
||||||
border_width: px(1.),
|
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -63,18 +62,6 @@ impl<E: Collapsible + IntoElement> Sidebar<E> {
|
||||||
Self::new(Side::Right)
|
Self::new(Side::Right)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the width of the sidebar
|
|
||||||
pub fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
|
|
||||||
self.width = width.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set border width of the sidebar
|
|
||||||
pub fn border_width(mut self, border_width: impl Into<Pixels>) -> Self {
|
|
||||||
self.border_width = border_width.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the sidebar to be collapsible, default is true
|
/// Set the sidebar to be collapsible, default is true
|
||||||
pub fn collapsible(mut self, collapsible: bool) -> Self {
|
pub fn collapsible(mut self, collapsible: bool) -> Self {
|
||||||
self.collapsible = collapsible;
|
self.collapsible = collapsible;
|
||||||
|
|
@ -192,41 +179,69 @@ impl RenderOnce for SidebarToggleButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: Collapsible + IntoElement> Styled for Sidebar<E> {
|
||||||
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
|
&mut self.style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: Collapsible + IntoElement> RenderOnce for Sidebar<E> {
|
impl<E: Collapsible + IntoElement> RenderOnce for Sidebar<E> {
|
||||||
fn render(mut self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(mut self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
self.style.padding = EdgesRefinement::default();
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.id("sidebar")
|
.id("sidebar")
|
||||||
.w(self.width)
|
.w(DEFAULT_WIDTH)
|
||||||
.when(self.collapsed, |this| this.w(COLLAPSED_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)
|
||||||
.text_color(cx.theme().sidebar_foreground)
|
.text_color(cx.theme().sidebar_foreground)
|
||||||
.border_color(cx.theme().sidebar_border)
|
.border_color(cx.theme().sidebar_border)
|
||||||
.map(|this| match self.side {
|
.map(|this| match self.side {
|
||||||
Side::Left => this.border_r(self.border_width),
|
Side::Left => this.border_r_1(),
|
||||||
Side::Right => this.border_l(self.border_width),
|
Side::Right => this.border_l_1(),
|
||||||
})
|
})
|
||||||
|
.refine_style(&self.style)
|
||||||
|
.when(self.collapsed, |this| this.w(COLLAPSED_WIDTH).gap_2())
|
||||||
.when_some(self.header.take(), |this, header| {
|
.when_some(self.header.take(), |this, header| {
|
||||||
this.child(h_flex().id("header").p_2().gap_2().child(header))
|
this.child(
|
||||||
|
h_flex()
|
||||||
|
.id("header")
|
||||||
|
.pt_3()
|
||||||
|
.px_3()
|
||||||
|
.gap_2()
|
||||||
|
.when(self.collapsed, |this| this.pt_2().px_2())
|
||||||
|
.child(header),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.child(
|
.child(
|
||||||
v_flex().id("content").flex_1().min_h_0().child(
|
v_flex().id("content").flex_1().min_h_0().child(
|
||||||
div()
|
v_flex()
|
||||||
|
.gap_3()
|
||||||
|
.p_3()
|
||||||
|
.when(self.collapsed, |this| this.p_2())
|
||||||
.children(
|
.children(
|
||||||
self.content
|
self.content
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(ix, c)| div().id(ix).child(c.collapsed(self.collapsed))),
|
.map(|(ix, c)| div().id(ix).child(c.collapsed(self.collapsed))),
|
||||||
)
|
)
|
||||||
.gap_2()
|
|
||||||
.scrollable(ScrollbarAxis::Vertical),
|
.scrollable(ScrollbarAxis::Vertical),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.when_some(self.footer.take(), |this, footer| {
|
.when_some(self.footer.take(), |this, footer| {
|
||||||
this.child(h_flex().id("footer").gap_2().p_2().child(footer))
|
this.child(
|
||||||
|
h_flex()
|
||||||
|
.id("footer")
|
||||||
|
.pb_3()
|
||||||
|
.px_3()
|
||||||
|
.gap_2()
|
||||||
|
.when(self.collapsed, |this| this.pt_2().px_2())
|
||||||
|
.child(footer),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue