Skip to main content

ui/components/
navbar.rs

1use gpui::AnyElement;
2use smallvec::SmallVec;
3
4use crate::prelude::*;
5
6/// A fixed top bar: leading content (title/logo) on the left, optional trailing
7/// actions on the right. Neutrals are theme-driven.
8#[derive(IntoElement, RegisterComponent)]
9pub struct Navbar {
10    children: SmallVec<[AnyElement; 2]>,
11    trailing: Option<AnyElement>,
12}
13
14impl Navbar {
15    pub fn new() -> Self {
16        Self {
17            children: SmallVec::new(),
18            trailing: None,
19        }
20    }
21
22    pub fn trailing(mut self, trailing: impl IntoElement) -> Self {
23        self.trailing = Some(trailing.into_any_element());
24        self
25    }
26}
27
28impl Default for Navbar {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl ParentElement for Navbar {
35    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
36        self.children.extend(elements);
37    }
38}
39
40impl RenderOnce for Navbar {
41    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
42        h_flex()
43            .w_full()
44            .items_center()
45            .justify_between()
46            .px_6()
47            .py_4()
48            .bg(semantic::surface(cx))
49            .border_b_1()
50            .border_color(semantic::border(cx))
51            .shadow_level(Shadow::Sm)
52            .child(h_flex().items_center().gap_3().children(self.children))
53            .children(self.trailing)
54    }
55}
56
57impl Component for Navbar {
58    fn scope() -> ComponentScope {
59        ComponentScope::Navigation
60    }
61
62    fn description() -> Option<&'static str> {
63        Some("A fixed top bar with leading content and optional trailing actions.")
64    }
65
66    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
67        Some(
68            v_flex()
69                .gap_4()
70                .child(
71                    Navbar::new()
72                        .trailing(Badge::new("v1.4.2").color(BadgeColor::Primary))
73                        .child(Label::new("Application")),
74                )
75                .child(
76                    Navbar::new()
77                        .trailing(
78                            h_flex()
79                                .gap_2()
80                                .child(Button::new("navbar-search", "Search"))
81                                .child(Button::new("navbar-invite", "Invite").primary()),
82                        )
83                        .child(
84                            h_flex()
85                                .gap_2()
86                                .child(Icon::new(IconName::Folder).size(IconSize::Small))
87                                .child(Label::new("Acme Workspace")),
88                        ),
89                )
90                .into_any_element(),
91        )
92    }
93}