tab_bar.rs

  1use crate::prelude::*;
  2use crate::{Icon, IconButton, Tab};
  3
  4#[derive(Component)]
  5pub struct TabBar {
  6    id: ElementId,
  7    /// Backwards, Forwards
  8    can_navigate: (bool, bool),
  9    tabs: Vec<Tab>,
 10}
 11
 12impl TabBar {
 13    pub fn new(id: impl Into<ElementId>, tabs: Vec<Tab>) -> Self {
 14        Self {
 15            id: id.into(),
 16            can_navigate: (false, false),
 17            tabs,
 18        }
 19    }
 20
 21    pub fn can_navigate(mut self, can_navigate: (bool, bool)) -> Self {
 22        self.can_navigate = can_navigate;
 23        self
 24    }
 25
 26    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 27        let (can_navigate_back, can_navigate_forward) = self.can_navigate;
 28
 29        div()
 30            .group("tab_bar")
 31            .id(self.id.clone())
 32            .w_full()
 33            .flex()
 34            .bg(cx.theme().colors().tab_bar_background)
 35            // Left Side
 36            .child(
 37                div()
 38                    .relative()
 39                    .px_1()
 40                    .flex()
 41                    .flex_none()
 42                    .gap_2()
 43                    // Nav Buttons
 44                    .child(
 45                        div()
 46                            .right_0()
 47                            .flex()
 48                            .items_center()
 49                            .gap_px()
 50                            .child(
 51                                IconButton::new("arrow_left", Icon::ArrowLeft)
 52                                    .state(InteractionState::Enabled.if_enabled(can_navigate_back)),
 53                            )
 54                            .child(
 55                                IconButton::new("arrow_right", Icon::ArrowRight).state(
 56                                    InteractionState::Enabled.if_enabled(can_navigate_forward),
 57                                ),
 58                            ),
 59                    ),
 60            )
 61            .child(
 62                div().w_0().flex_1().h_full().child(
 63                    div()
 64                        .id("tabs")
 65                        .flex()
 66                        .overflow_x_scroll()
 67                        .children(self.tabs.clone()),
 68                ),
 69            )
 70            // Right Side
 71            .child(
 72                div()
 73                    // We only use absolute here since we don't
 74                    // have opacity or `hidden()` yet
 75                    .absolute()
 76                    .neg_top_7()
 77                    .px_1()
 78                    .flex()
 79                    .flex_none()
 80                    .gap_2()
 81                    .group_hover("tab_bar", |this| this.top_0())
 82                    // Nav Buttons
 83                    .child(
 84                        div()
 85                            .flex()
 86                            .items_center()
 87                            .gap_px()
 88                            .child(IconButton::new("plus", Icon::Plus))
 89                            .child(IconButton::new("split", Icon::Split)),
 90                    ),
 91            )
 92    }
 93}
 94
 95use gpui::ElementId;
 96#[cfg(feature = "stories")]
 97pub use stories::*;
 98
 99#[cfg(feature = "stories")]
100mod stories {
101    use super::*;
102    use crate::Story;
103    use gpui::{Div, Render};
104
105    pub struct TabBarStory;
106
107    impl Render for TabBarStory {
108        type Element = Div<Self>;
109
110        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
111            Story::container(cx)
112                .child(Story::title_for::<_, TabBar>(cx))
113                .child(Story::label(cx, "Default"))
114                .child(TabBar::new(
115                    "tab-bar",
116                    vec![
117                        Tab::new(1)
118                            .title("Cargo.toml".to_string())
119                            .current(false)
120                            .git_status(GitStatus::Modified),
121                        Tab::new(2)
122                            .title("Channels Panel".to_string())
123                            .current(false),
124                        Tab::new(3)
125                            .title("channels_panel.rs".to_string())
126                            .current(true)
127                            .git_status(GitStatus::Modified),
128                        Tab::new(4)
129                            .title("workspace.rs".to_string())
130                            .current(false)
131                            .git_status(GitStatus::Modified),
132                        Tab::new(5)
133                            .title("icon_button.rs".to_string())
134                            .current(false),
135                        Tab::new(6)
136                            .title("storybook.rs".to_string())
137                            .current(false)
138                            .git_status(GitStatus::Created),
139                        Tab::new(7).title("theme.rs".to_string()).current(false),
140                        Tab::new(8)
141                            .title("theme_registry.rs".to_string())
142                            .current(false),
143                        Tab::new(9)
144                            .title("styleable_helpers.rs".to_string())
145                            .current(false),
146                    ],
147                ))
148        }
149    }
150}