1#![allow(missing_docs)]
2use gpui::{AnyElement, ScrollHandle};
3use smallvec::SmallVec;
4
5use crate::prelude::*;
6use crate::Tab;
7
8#[derive(IntoElement)]
9pub struct TabBar {
10 id: ElementId,
11 start_children: SmallVec<[AnyElement; 2]>,
12 children: SmallVec<[AnyElement; 2]>,
13 end_children: SmallVec<[AnyElement; 2]>,
14 scroll_handle: Option<ScrollHandle>,
15}
16
17impl TabBar {
18 pub fn new(id: impl Into<ElementId>) -> Self {
19 Self {
20 id: id.into(),
21 start_children: SmallVec::new(),
22 children: SmallVec::new(),
23 end_children: SmallVec::new(),
24 scroll_handle: None,
25 }
26 }
27
28 pub fn track_scroll(mut self, scroll_handle: ScrollHandle) -> Self {
29 self.scroll_handle = Some(scroll_handle);
30 self
31 }
32
33 pub fn start_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
34 &mut self.start_children
35 }
36
37 pub fn start_child(mut self, start_child: impl IntoElement) -> Self
38 where
39 Self: Sized,
40 {
41 self.start_children_mut()
42 .push(start_child.into_element().into_any());
43 self
44 }
45
46 pub fn start_children(
47 mut self,
48 start_children: impl IntoIterator<Item = impl IntoElement>,
49 ) -> Self
50 where
51 Self: Sized,
52 {
53 self.start_children_mut().extend(
54 start_children
55 .into_iter()
56 .map(|child| child.into_any_element()),
57 );
58 self
59 }
60
61 pub fn end_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
62 &mut self.end_children
63 }
64
65 pub fn end_child(mut self, end_child: impl IntoElement) -> Self
66 where
67 Self: Sized,
68 {
69 self.end_children_mut()
70 .push(end_child.into_element().into_any());
71 self
72 }
73
74 pub fn end_children(mut self, end_children: impl IntoIterator<Item = impl IntoElement>) -> Self
75 where
76 Self: Sized,
77 {
78 self.end_children_mut().extend(
79 end_children
80 .into_iter()
81 .map(|child| child.into_any_element()),
82 );
83 self
84 }
85}
86
87impl ParentElement for TabBar {
88 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
89 self.children.extend(elements)
90 }
91}
92
93impl RenderOnce for TabBar {
94 fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
95 div()
96 .id(self.id)
97 .group("tab_bar")
98 .flex()
99 .flex_none()
100 .w_full()
101 .h(Tab::container_height(cx))
102 .bg(cx.theme().colors().tab_bar_background)
103 .when(!self.start_children.is_empty(), |this| {
104 this.child(
105 h_flex()
106 .flex_none()
107 .gap(DynamicSpacing::Base04.rems(cx))
108 .px(DynamicSpacing::Base06.rems(cx))
109 .border_b_1()
110 .border_r_1()
111 .border_color(cx.theme().colors().border)
112 .children(self.start_children),
113 )
114 })
115 .child(
116 div()
117 .relative()
118 .flex_1()
119 .h_full()
120 .overflow_x_hidden()
121 .child(
122 div()
123 .absolute()
124 .top_0()
125 .left_0()
126 .size_full()
127 .border_b_1()
128 .border_color(cx.theme().colors().border),
129 )
130 .child(
131 h_flex()
132 .id("tabs")
133 .flex_grow()
134 .overflow_x_scroll()
135 .when_some(self.scroll_handle, |cx, scroll_handle| {
136 cx.track_scroll(&scroll_handle)
137 })
138 .children(self.children),
139 ),
140 )
141 .when(!self.end_children.is_empty(), |this| {
142 this.child(
143 h_flex()
144 .flex_none()
145 .gap(DynamicSpacing::Base04.rems(cx))
146 .px(DynamicSpacing::Base06.rems(cx))
147 .border_b_1()
148 .border_l_1()
149 .border_color(cx.theme().colors().border)
150 .children(self.end_children),
151 )
152 })
153 }
154}