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