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