use crate::{ h_flex, theme::{scale::ColorScaleStep, ActiveTheme}, }; use gpui::{ div, prelude::FluentBuilder as _, px, AnyElement, Div, ElementId, InteractiveElement, IntoElement, ParentElement, RenderOnce, ScrollHandle, StatefulInteractiveElement as _, Styled, WindowContext, }; use smallvec::SmallVec; #[derive(IntoElement)] pub struct TabBar { base: Div, id: ElementId, scroll_handle: ScrollHandle, prefix: Option, suffix: Option, children: SmallVec<[AnyElement; 2]>, } impl TabBar { pub fn new(id: impl Into) -> Self { Self { base: div().px(px(-1.)), id: id.into(), children: SmallVec::new(), scroll_handle: ScrollHandle::new(), prefix: None, suffix: None, } } /// Track the scroll of the TabBar pub fn track_scroll(mut self, scroll_handle: ScrollHandle) -> Self { self.scroll_handle = scroll_handle; self } /// Set the prefix element of the TabBar pub fn prefix(mut self, prefix: impl IntoElement) -> Self { self.prefix = Some(prefix.into_any_element()); self } /// Set the suffix element of the TabBar pub fn suffix(mut self, suffix: impl IntoElement) -> Self { self.suffix = Some(suffix.into_any_element()); self } } impl ParentElement for TabBar { fn extend(&mut self, elements: impl IntoIterator) { self.children.extend(elements) } } impl Styled for TabBar { fn style(&mut self) -> &mut gpui::StyleRefinement { self.base.style() } } impl RenderOnce for TabBar { fn render(self, cx: &mut WindowContext) -> impl IntoElement { self.base .id(self.id) .group("tab-bar") .relative() .flex() .flex_none() .items_center() .bg(cx.theme().base.step(cx, ColorScaleStep::TWO)) .child( div() .id("border-b") .absolute() .bottom_0() .size_full() .border_b_1() .border_color(cx.theme().base.step(cx, ColorScaleStep::FIVE)), ) .when_some(self.prefix, |this, prefix| this.child(prefix)) .child( h_flex() .id("tabs") .flex_grow() .overflow_x_scroll() .track_scroll(&self.scroll_handle) .children(self.children), ) .when_some(self.suffix, |this, suffix| this.child(suffix)) } }