1use gpui::{AnyElement, FocusHandle, Focusable, Stateful};
2use smallvec::SmallVec;
3
4use crate::prelude::*;
5
6#[derive(IntoElement)]
7pub struct TabBar {
8 id: ElementId,
9 focus_handle: FocusHandle,
10 start_children: SmallVec<[AnyElement; 2]>,
11 children: SmallVec<[AnyElement; 2]>,
12 end_children: SmallVec<[AnyElement; 2]>,
13}
14
15impl TabBar {
16 pub fn new(id: impl Into<ElementId>, focus_handle: FocusHandle) -> Self {
17 Self {
18 id: id.into(),
19 focus_handle,
20 start_children: SmallVec::new(),
21 children: SmallVec::new(),
22 end_children: SmallVec::new(),
23 }
24 }
25
26 pub fn start_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
27 &mut self.start_children
28 }
29
30 pub fn start_child(mut self, start_child: impl IntoElement) -> Self
31 where
32 Self: Sized,
33 {
34 self.start_children_mut()
35 .push(start_child.into_element().into_any());
36 self
37 }
38
39 pub fn start_children(
40 mut self,
41 start_children: impl IntoIterator<Item = impl IntoElement>,
42 ) -> Self
43 where
44 Self: Sized,
45 {
46 self.start_children_mut().extend(
47 start_children
48 .into_iter()
49 .map(|child| child.into_any_element()),
50 );
51 self
52 }
53
54 pub fn end_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
55 &mut self.end_children
56 }
57
58 pub fn end_child(mut self, end_child: impl IntoElement) -> Self
59 where
60 Self: Sized,
61 {
62 self.end_children_mut()
63 .push(end_child.into_element().into_any());
64 self
65 }
66
67 pub fn end_children(mut self, end_children: impl IntoIterator<Item = impl IntoElement>) -> Self
68 where
69 Self: Sized,
70 {
71 self.end_children_mut().extend(
72 end_children
73 .into_iter()
74 .map(|child| child.into_any_element()),
75 );
76 self
77 }
78}
79
80impl ParentElement for TabBar {
81 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
82 &mut self.children
83 }
84}
85
86impl RenderOnce for TabBar {
87 type Rendered = Focusable<Stateful<Div>>;
88
89 fn render(self, cx: &mut WindowContext) -> Self::Rendered {
90 const HEIGHT_IN_REMS: f32 = 30. / 16.;
91
92 div()
93 .id(self.id)
94 .group("tab_bar")
95 .track_focus(&self.focus_handle)
96 .flex()
97 .flex_none()
98 .w_full()
99 .h(rems(HEIGHT_IN_REMS))
100 .bg(cx.theme().colors().tab_bar_background)
101 .child(
102 h_stack()
103 .flex_none()
104 .gap_1()
105 .px_1()
106 .border_b()
107 .border_r()
108 .border_color(cx.theme().colors().border)
109 .children(self.start_children),
110 )
111 .child(
112 div()
113 .relative()
114 .flex_1()
115 .h_full()
116 .overflow_hidden_x()
117 .child(
118 div()
119 .absolute()
120 .top_0()
121 .left_0()
122 .z_index(1)
123 .size_full()
124 .border_b()
125 .border_color(cx.theme().colors().border),
126 )
127 .child(
128 h_stack()
129 .id("tabs")
130 .z_index(2)
131 .overflow_x_scroll()
132 .children(self.children),
133 ),
134 )
135 .child(
136 h_stack()
137 .flex_none()
138 .gap_1()
139 .px_1()
140 .border_b()
141 .border_l()
142 .border_color(cx.theme().colors().border)
143 .children(self.end_children),
144 )
145 }
146}