feat: more work on UI

This commit is contained in:
2026-04-04 19:23:12 +02:00
parent eedd0a9118
commit 03dcaea88e
25 changed files with 713 additions and 178 deletions

View File

@@ -1,15 +1,78 @@
use iced::widget::{button, container, row, text, Space};
use iced::{Element, Length};
use iced::{Background, Border, Color, Element, Length, Theme};
use crate::app::Message;
use crate::state::tabs::Tab;
/// Tab bar background.
fn bar_style(_theme: &Theme) -> container::Style {
container::Style {
background: Some(Background::Color(Color::from_rgb(0.14, 0.14, 0.18))),
border: Border {
color: Color::from_rgb(0.25, 0.25, 0.30),
width: 0.0,
radius: 0.0.into(),
},
..container::Style::default()
}
}
/// Active tab style.
fn tab_active(_theme: &Theme, _status: button::Status) -> button::Style {
button::Style {
background: Some(Background::Color(Color::from_rgb(0.11, 0.11, 0.14))),
text_color: Color::WHITE,
border: Border {
color: Color::from_rgb(0.30, 0.55, 0.90),
width: 0.0,
radius: 4.0.into(),
},
..button::Style::default()
}
}
/// Inactive tab style.
fn tab_inactive(_theme: &Theme, status: button::Status) -> button::Style {
let bg = match status {
button::Status::Hovered => Color::from_rgb(0.18, 0.18, 0.22),
_ => Color::from_rgb(0.14, 0.14, 0.18),
};
button::Style {
background: Some(Background::Color(bg)),
text_color: Color::from_rgb(0.60, 0.60, 0.65),
border: Border {
color: Color::TRANSPARENT,
width: 0.0,
radius: 4.0.into(),
},
..button::Style::default()
}
}
/// Close button on tab.
fn close_style(_theme: &Theme, status: button::Status) -> button::Style {
let color = match status {
button::Status::Hovered => Color::WHITE,
_ => Color::from_rgb(0.45, 0.45, 0.50),
};
button::Style {
background: Some(Background::Color(Color::TRANSPARENT)),
text_color: color,
border: Border::default(),
..button::Style::default()
}
}
pub fn view(
tabs: &[Tab],
active_tab: Option<&str>,
) -> Element<'static, Message> {
if tabs.is_empty() {
return Space::with_height(0).into();
return container(Space::new(0, 0))
.width(Length::Fill)
.height(Length::Fixed(35.0))
.style(bar_style)
.into();
}
let tab_buttons: Vec<Element<'static, Message>> = tabs
@@ -17,7 +80,7 @@ pub fn view(
.map(|tab| {
let is_active = active_tab == Some(tab.id.as_str());
let title_text = if tab.is_transient {
format!("{} (preview)", tab.title)
format!("{} \u{25CB}", tab.title) // hollow circle for transient
} else {
tab.title.clone()
};
@@ -26,24 +89,19 @@ pub fn view(
let label = row![
text(title_text).size(12),
button(text("×").size(12))
button(text("\u{2715}").size(10))
.on_press(Message::CloseTab(close_id))
.padding(2)
.style(button::text),
.style(close_style),
]
.spacing(4);
.spacing(6)
.align_y(iced::Alignment::Center);
let mut btn = button(label)
button(label)
.on_press(Message::SelectTab(tab_id))
.padding([4, 8]);
if is_active {
btn = btn.style(button::primary);
} else {
btn = btn.style(button::secondary);
}
btn.into()
.padding([6, 12])
.style(if is_active { tab_active } else { tab_inactive })
.into()
})
.collect();
@@ -54,5 +112,6 @@ pub fn view(
)
.width(Length::Fill)
.height(Length::Fixed(35.0))
.style(bar_style)
.into()
}