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