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 .w_full()
97 .h(rems(HEIGHT_IN_REMS))
98 .overflow_hidden()
99 .flex()
100 .flex_none()
101 .bg(cx.theme().colors().tab_bar_background)
102 .child(
103 h_stack()
104 .flex_none()
105 .gap_1()
106 .px_1()
107 .border_b()
108 .border_r()
109 .border_color(cx.theme().colors().border)
110 .children(self.start_children),
111 )
112 .child(
113 div()
114 .relative()
115 .flex_1()
116 .h_full()
117 .overflow_hidden_x()
118 .child(
119 div()
120 .absolute()
121 .top_0()
122 .left_0()
123 .z_index(1)
124 .size_full()
125 .border_b()
126 .border_color(cx.theme().colors().border),
127 )
128 .child(h_stack().id("tabs").z_index(2).children(self.children)),
129 )
130 .child(
131 h_stack()
132 .flex_none()
133 .gap_1()
134 .px_1()
135 .border_b()
136 .border_l()
137 .border_color(cx.theme().colors().border)
138 .children(self.end_children),
139 )
140 }
141}