1use gpui::AnyElement;
2use smallvec::SmallVec;
3
4use crate::prelude::*;
5
6#[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}