gitkraft_gui/widgets/
header.rs1use 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
15pub fn view(state: &GitKraft) -> Element<'_, Message> {
17 let tab = state.active_tab();
18 let c = state.colors();
19
20 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 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 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 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 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 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 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 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 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 let left_items = 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 ]
124 .align_y(Alignment::Center);
125
126 let right_items = row![
127 fetch_btn,
128 Space::new().width(4),
129 refresh_btn,
130 Space::new().width(4),
131 open_btn,
132 Space::new().width(4),
133 close_btn,
134 Space::new().width(8),
135 theme_selector(state.current_theme_index),
136 ]
137 .align_y(Alignment::Center);
138
139 let toolbar = row![
140 container(left_items).width(Length::Fill).clip(true),
141 right_items,
142 ]
143 .align_y(Alignment::Center)
144 .padding([6, 12])
145 .width(Length::Fill);
146
147 container(toolbar)
148 .width(Length::Fill)
149 .style(theme::header_style)
150 .into()
151}