update sidebar

This commit is contained in:
2026-09-23 20:19:42 +07:00
parent 273ddabde5
commit c61be4a139
6 changed files with 485 additions and 596 deletions
+94 -49
View File
@@ -25,6 +25,7 @@ pub struct Tab {
children: Vec<AnyElement>,
pub(super) disabled: bool,
pub(super) selected: bool,
pub(super) segmented: bool,
on_click: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
}
@@ -69,6 +70,7 @@ impl Default for Tab {
children: Vec::new(),
disabled: false,
selected: false,
segmented: false,
prefix: None,
suffix: None,
on_click: None,
@@ -132,6 +134,12 @@ impl Tab {
self.tab_bar_prefix = Some(tab_bar_prefix);
self
}
/// Render the tab as a segment inside a segmented control.
pub(crate) fn segmented(mut self, segmented: bool) -> Self {
self.segmented = segmented;
self
}
}
impl ParentElement for Tab {
@@ -167,74 +175,111 @@ impl Styled for Tab {
impl RenderOnce for Tab {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
let fg = if self.disabled {
let Self {
ix,
base,
label,
icon,
prefix,
suffix,
children,
disabled,
selected,
segmented,
on_click,
..
} = self;
let fg = if disabled {
cx.theme().text_muted
} else if self.selected {
} else if selected {
cx.theme().tab_active_foreground
} else {
cx.theme().tab_foreground
};
self.base
.id(self.ix)
.flex()
.flex_wrap()
.gap_1()
let content = h_flex()
.flex_1()
.map(|this| {
if segmented {
this.h(px(24.))
} else {
this.h(px(30.))
}
})
.line_height(relative(1.))
.whitespace_nowrap()
.items_center()
.flex_shrink_0()
.h(TABBAR_HEIGHT)
.relative()
.justify_center()
.overflow_hidden()
.when(segmented, |this| this.px_1())
.when(!segmented, |this| this.flex_shrink_0().px_3())
.map(|this| match icon {
Some(icon) => this.w(px(38.)).child(icon.size_4()),
None => this
.map(|this| match label {
Some(label) => this.child(label),
None => this,
})
.children(children),
});
base.id(ix)
.flex()
.items_center()
.text_color(fg)
.text_sm()
.when_some(self.prefix, |this, prefix| this.child(prefix))
.child(
h_flex()
.when(segmented, |this| {
this.text_xs()
.flex_1()
.h(px(30.))
.line_height(relative(1.))
.whitespace_nowrap()
.items_center()
.justify_center()
.overflow_hidden()
.h(px(24.))
.rounded(cx.theme().radius)
.when(selected && !disabled, |this| {
this.bg(cx.theme().tab_active_background)
.when(cx.theme().shadow, |this| this.shadow_sm())
})
.when(!selected && !disabled, |this| {
this.hover(|this| this.bg(cx.theme().tab_hover_background))
})
})
.when(!segmented, |this| {
this.text_sm()
.flex_wrap()
.gap_1()
.flex_shrink_0()
.px_3()
.map(|this| match self.icon {
Some(icon) => this.w(px(38.)).child(icon.size_4()),
None => this
.map(|this| match self.label {
Some(label) => this.child(label),
None => this,
})
.children(self.children),
}),
)
.when_some(self.suffix, |this, suffix| {
.h(TABBAR_HEIGHT)
.relative()
.overflow_hidden()
})
.when_some(prefix, |this, prefix| this.child(prefix))
.child(content)
.when_some(suffix, |this, suffix| {
this.child(div().pr_2().child(suffix))
})
.on_mouse_down(MouseButton::Left, |_ev, _window, cx| {
cx.stop_propagation();
})
.when(!self.disabled, |this| {
this.when_some(self.on_click.clone(), |this, on_click| {
.when(!disabled, |this| {
this.when_some(on_click, |this, on_click| {
this.on_click(move |event, window, cx| on_click(event, window, cx))
})
})
.child(
div()
.absolute()
.bottom_0()
.left_0()
.right_0()
.h_0p5()
.when(self.selected && !self.disabled, |this| {
this.bg(cx.theme().element_active)
})
.when(!self.selected && !self.disabled, |this| {
this.invisible().group_hover("", |this| {
this.visible().bg(cx.theme().secondary_background)
.when(!segmented, |this| {
this.child(
div()
.absolute()
.bottom_0()
.left_0()
.right_0()
.h_0p5()
.when(selected && !disabled, |this| {
this.bg(cx.theme().element_active)
})
}),
)
.when(!selected && !disabled, |this| {
this.invisible().group_hover("", |this| {
this.visible().bg(cx.theme().secondary_background)
})
}),
)
})
}
}