1use gpui::prelude::*;
4use gpui::{div, px, transparent_black, App, Context, IntoElement, SharedString, Window};
5
6use super::Content;
7use crate::theme::{theme, Size};
8
9struct TabItem {
10 label: SharedString,
11 content: Content,
12}
13
14pub struct Tabs {
16 tabs: Vec<TabItem>,
17 active: usize,
18}
19
20impl Tabs {
21 pub fn new(_cx: &mut Context<Self>) -> Self {
22 Tabs {
23 tabs: Vec::new(),
24 active: 0,
25 }
26 }
27
28 pub fn tab<E>(
30 mut self,
31 label: impl Into<SharedString>,
32 content: impl Fn(&mut Window, &mut App) -> E + 'static,
33 ) -> Self
34 where
35 E: IntoElement,
36 {
37 self.tabs.push(TabItem {
38 label: label.into(),
39 content: Box::new(move |window, cx| content(window, cx).into_any_element()),
40 });
41 self
42 }
43
44 pub fn active(mut self, index: usize) -> Self {
45 self.active = index;
46 self
47 }
48
49 pub fn active_index(&self) -> usize {
51 self.active
52 }
53}
54
55impl Render for Tabs {
56 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
57 let t = theme(cx);
58 let accent = t.primary().hsla();
59 let dimmed = t.dimmed().hsla();
60 let text = t.text().hsla();
61 let line = t.border().hsla();
62 let font = t.font_size(Size::Sm);
63
64 let count = self.tabs.len();
65 let active = if count == 0 {
66 0
67 } else {
68 self.active.min(count - 1)
69 };
70
71 let mut bar = div().flex().border_b_1().border_color(line);
72 for (i, tab) in self.tabs.iter().enumerate() {
73 let is_active = i == active;
74 bar = bar.child(
75 div()
76 .id(("guise-tab", i))
77 .px(px(16.0))
78 .py(px(8.0))
79 .border_b_2()
80 .border_color(if is_active {
81 accent
82 } else {
83 transparent_black()
84 })
85 .text_size(px(font))
86 .text_color(if is_active { accent } else { dimmed })
87 .hover(move |s| s.text_color(text))
88 .child(tab.label.clone())
89 .on_click(cx.listener(move |this, _ev, _window, cx| {
90 this.active = i;
91 cx.notify();
92 })),
93 );
94 }
95
96 let mut root = div().flex().flex_col().gap(px(12.0)).child(bar);
97 if count > 0 {
98 let panel = (self.tabs[active].content)(window, cx);
99 root = root.child(panel);
100 }
101 root
102 }
103}