tab_bar.rs

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