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 { 0 } else { self.active.min(count - 1) };
66
67 let mut bar = div().flex().border_b_1().border_color(line);
68 for (i, tab) in self.tabs.iter().enumerate() {
69 let is_active = i == active;
70 bar = bar.child(
71 div()
72 .id(("guise-tab", i))
73 .px(px(16.0))
74 .py(px(8.0))
75 .border_b_2()
76 .border_color(if is_active { accent } else { transparent_black() })
77 .text_size(px(font))
78 .text_color(if is_active { accent } else { dimmed })
79 .hover(move |s| s.text_color(text))
80 .child(tab.label.clone())
81 .on_click(cx.listener(move |this, _ev, _window, cx| {
82 this.active = i;
83 cx.notify();
84 })),
85 );
86 }
87
88 let mut root = div().flex().flex_col().gap(px(12.0)).child(bar);
89 if count > 0 {
90 let panel = (self.tabs[active].content)(window, cx);
91 root = root.child(panel);
92 }
93 root
94 }
95}