Skip to main content

gitkraft_gui/widgets/
header.rs

1//! Top toolbar / header bar for the GitKraft main layout.
2//!
3//! Shows: repo name │ branch name │ fetch button │ refresh button │ toggle sidebar.
4
5use iced::widget::{button, container, row, text, Space};
6use iced::{Alignment, Element, Length};
7
8use crate::features::theme::view::theme_selector;
9use crate::icons;
10use crate::message::Message;
11use crate::state::GitKraft;
12use crate::theme;
13use crate::view_utils;
14
15/// Render the top toolbar row.
16pub fn view(state: &GitKraft) -> Element<'_, Message> {
17    let tab = state.active_tab();
18    let c = state.colors();
19
20    // ── Repo name ─────────────────────────────────────────────────────────
21    let repo_icon = icon!(icons::FOLDER_OPEN, 14, c.accent);
22
23    let repo_name = text(state.repo_display_name())
24        .size(14)
25        .color(c.text_primary);
26
27    let separator = || text("|").size(14).color(c.border);
28
29    // ── Branch indicator ──────────────────────────────────────────────────
30    let branch_icon = icon!(icons::GIT_BRANCH, 14, c.green);
31
32    let branch_name_str = tab.current_branch.as_deref().unwrap_or("(detached)");
33
34    let branch_label = text(branch_name_str).size(14).color(c.text_primary);
35
36    // ── Repo state badge (if not clean) ───────────────────────────────────
37    let state_badge: Element<'_, Message> = if let Some(ref info) = tab.repo_info {
38        if info.state != gitkraft_core::RepoState::Clean {
39            text(format!(" [{}]", info.state))
40                .size(12)
41                .color(c.yellow)
42                .into()
43        } else {
44            Space::new().into()
45        }
46    } else {
47        Space::new().into()
48    };
49
50    // ── Fetch button ──────────────────────────────────────────────────────
51    let fetch_icon = icon!(icons::CLOUD_ARROW_DOWN, 14, c.accent);
52
53    let fetch_msg = (!tab.remotes.is_empty()).then_some(Message::Fetch);
54    let fetch_btn = crate::view_utils::on_press_maybe(
55        button(
56            row![fetch_icon, Space::new().width(4), text("Fetch").size(12)]
57                .align_y(Alignment::Center),
58        )
59        .padding([4, 10])
60        .style(theme::toolbar_button),
61        fetch_msg,
62    );
63
64    // ── Refresh button ────────────────────────────────────────────────────
65    let refresh_icon = icon!(icons::ARROW_REPEAT, 14, c.accent);
66
67    let refresh_btn = view_utils::toolbar_btn(refresh_icon, "Refresh", Message::RefreshRepo);
68
69    // ── Open another repo button ──────────────────────────────────────────
70    let open_icon = icon!(icons::FOLDER_OPEN, 14, c.text_secondary);
71
72    let open_btn = view_utils::toolbar_btn(open_icon, "Open", Message::OpenRepo);
73
74    // ── Close repo button (return to welcome screen) ──────────────────────
75    let close_icon = icon!(icons::X_CIRCLE, 14, c.text_secondary);
76
77    let close_btn = view_utils::toolbar_btn(close_icon, "Close", Message::CloseRepo);
78
79    // ── Toggle sidebar ────────────────────────────────────────────────────
80    let sidebar_icon_char = if state.sidebar_expanded {
81        icons::CHEVRON_LEFT
82    } else {
83        icons::CHEVRON_RIGHT
84    };
85    let sidebar_icon = icon!(sidebar_icon_char, 14, c.text_secondary);
86
87    let sidebar_btn = button(sidebar_icon)
88        .padding([4, 8])
89        .style(theme::icon_button)
90        .on_press(Message::ToggleSidebar);
91
92    // ── Loading indicator ─────────────────────────────────────────────────
93    let loading_indicator: Element<'_, Message> = if tab.is_loading {
94        row![
95            icon!(icons::ARROW_REPEAT, 12, c.yellow),
96            iced::widget::Space::new().width(4),
97            text("Loading…").size(12).color(c.yellow)
98        ]
99        .align_y(iced::Alignment::Center)
100        .into()
101    } else {
102        Space::new().into()
103    };
104
105    // ── Assemble ──────────────────────────────────────────────────────────
106    let toolbar = row![
107        sidebar_btn,
108        Space::new().width(8),
109        repo_icon,
110        Space::new().width(6),
111        repo_name,
112        Space::new().width(10),
113        separator(),
114        Space::new().width(10),
115        branch_icon,
116        Space::new().width(6),
117        branch_label,
118        state_badge,
119        Space::new().width(10),
120        separator(),
121        Space::new().width(10),
122        loading_indicator,
123        Space::new().width(Length::Fill),
124        theme_selector(state.current_theme_index),
125        Space::new().width(8),
126        fetch_btn,
127        Space::new().width(4),
128        refresh_btn,
129        Space::new().width(4),
130        open_btn,
131        Space::new().width(4),
132        close_btn,
133    ]
134    .align_y(Alignment::Center)
135    .padding([6, 12])
136    .width(Length::Fill);
137
138    container(toolbar)
139        .width(Length::Fill)
140        .style(theme::header_style)
141        .into()
142}