1use crate::action_button::{ButtonAction, DescribedButtonExt};
2use crate::semantics;
3use crate::views::selectable_text::text;
4use iced::widget::{button, column, row};
5use iced::{Alignment, Element, Length, color};
6
7pub struct Tab {
8 pub label: String,
9 pub active: bool,
10 pub action: ButtonAction,
11 pub test_id: Option<String>,
12}
13
14impl Tab {
15 pub fn new(label: impl Into<String>, active: bool, action: ButtonAction) -> Self {
16 Self {
17 label: label.into(),
18 active,
19 action,
20 test_id: None,
21 }
22 }
23
24 #[must_use]
25 pub fn test_id(mut self, test_id: impl Into<String>) -> Self {
26 self.test_id = Some(test_id.into());
27 self
28 }
29}
30
31pub fn tab_bar(tabs: impl IntoIterator<Item = Tab>) -> Element<'static, crate::app::Message> {
32 tabs.into_iter()
33 .fold(row![].spacing(6), |bar, tab| {
34 let label = if tab.active {
35 text(tab.label.clone()).size(13).color(color!(0x8AB4FF))
36 } else {
37 text(tab.label.clone()).size(13)
38 };
39 let btn = button(label).padding([4, 10]).style(button::text);
40 let tab_button = if tab.active {
41 btn.described_disabled("This tab is already open.")
42 } else {
43 btn.on_action(tab.action)
44 };
45 let tab_button = if let Some(test_id) = tab.test_id {
46 semantics::test_id(test_id, tab_button)
47 } else {
48 tab_button
49 };
50 let indicator = if tab.active {
51 text("━━━━").size(10).color(color!(0x8AB4FF))
52 } else {
53 text("").size(10)
54 };
55 bar.push(
56 column![tab_button, indicator]
57 .spacing(0)
58 .align_x(Alignment::Center)
59 .width(Length::Shrink),
60 )
61 })
62 .align_y(Alignment::Center)
63 .into()
64}