breadcrumb.rs

  1use std::path::PathBuf;
  2
  3use gpui2::Div;
  4use crate::prelude::*;
  5use crate::{h_stack, HighlightedText};
  6
  7#[derive(Clone)]
  8pub struct Symbol(pub Vec<HighlightedText>);
  9
 10#[derive(Component)]
 11pub struct Breadcrumb {
 12    path: PathBuf,
 13    symbols: Vec<Symbol>,
 14}
 15
 16impl Breadcrumb {
 17    pub fn new(path: PathBuf, symbols: Vec<Symbol>) -> Self {
 18        Self {
 19            path,
 20            symbols,
 21        }
 22    }
 23
 24    fn render_separator<V: 'static>(&self, cx: &WindowContext) -> Div<V> {
 25        let theme = theme(cx);
 26
 27        div().child("").text_color(theme.text_muted)
 28    }
 29
 30    fn render<V: 'static>(self, view_state: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 31        let theme = theme(cx);
 32
 33        let symbols_len = self.symbols.len();
 34
 35        h_stack()
 36            .id("breadcrumb")
 37            .px_1()
 38            .text_sm()
 39            .text_color(theme.text_muted)
 40            .rounded_md()
 41            .hover(|style| style.bg(theme.ghost_element_hover))
 42            .active(|style| style.bg(theme.ghost_element_active))
 43            .child(self.path.clone().to_str().unwrap().to_string())
 44            .child(if !self.symbols.is_empty() {
 45                self.render_separator(cx)
 46            } else {
 47                div()
 48            })
 49            .child(
 50                div().flex().children(
 51                    self.symbols
 52                        .iter()
 53                        .enumerate()
 54                        // TODO: Could use something like `intersperse` here instead.
 55                        .flat_map(|(ix, symbol)| {
 56                            let mut items =
 57                                vec![div().flex().children(symbol.0.iter().map(|segment| {
 58                                    div().child(segment.text.clone()).text_color(segment.color)
 59                                }))];
 60
 61                            let is_last_segment = ix == symbols_len - 1;
 62                            if !is_last_segment {
 63                                items.push(self.render_separator(cx));
 64                            }
 65
 66                            items
 67                        })
 68                        .collect::<Vec<_>>(),
 69                ),
 70            )
 71    }
 72}
 73
 74#[cfg(feature = "stories")]
 75pub use stories::*;
 76
 77#[cfg(feature = "stories")]
 78mod stories {
 79    use std::str::FromStr;
 80
 81    use crate::Story;
 82
 83    use super::*;
 84
 85    #[derive(Component)]
 86    pub struct BreadcrumbStory;
 87
 88    impl BreadcrumbStory {
 89        pub fn new() -> Self {
 90            Self
 91        }
 92
 93        fn render<V: 'static>(self, view_state: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 94            let theme = theme(cx);
 95
 96            Story::container(cx)
 97                .child(Story::title_for::<_, Breadcrumb>(cx))
 98                .child(Story::label(cx, "Default"))
 99                .child(Breadcrumb::new(
100                    PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
101                    vec![
102                        Symbol(vec![
103                            HighlightedText {
104                                text: "impl ".to_string(),
105                                color: theme.syntax.keyword,
106                            },
107                            HighlightedText {
108                                text: "BreadcrumbStory".to_string(),
109                                color: theme.syntax.function,
110                            },
111                        ]),
112                        Symbol(vec![
113                            HighlightedText {
114                                text: "fn ".to_string(),
115                                color: theme.syntax.keyword,
116                            },
117                            HighlightedText {
118                                text: "render".to_string(),
119                                color: theme.syntax.function,
120                            },
121                        ]),
122                    ],
123                ))
124        }
125    }
126}