use ratatui::{
Frame,
layout::Rect,
style::{Modifier, Style},
text::{Line, Span},
widgets::{Block, BorderType, Borders, Padding},
};
use super::style;
use crate::theme::Skin;
pub fn panel() -> Block<'static> {
Block::default().padding(Padding::uniform(1))
}
pub fn menu_panel(skin: &Skin) -> Block<'static> {
panel().style(style::bg(skin.palette.panel))
}
pub fn modal_block(skin: &Skin, title: &str) -> Block<'static> {
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(style::border(&skin.palette))
.style(style::bg(skin.palette.background))
.title(title_line(skin, title, style::accent(&skin.palette)))
}
fn title_line(skin: &Skin, title: &str, label: Style) -> Line<'static> {
Line::from(vec![
Span::styled("\u{2500} ", style::border(&skin.palette)),
Span::styled(format!("{} ", title.trim()), label),
])
}
#[derive(Debug, Clone, Default)]
pub enum Badge {
#[default]
Auto,
Text(String),
Hidden,
}
#[derive(Debug, Clone, Default)]
pub struct BoxDecor {
pub caption: Option<String>,
pub badge: Badge,
}
impl BoxDecor {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn caption(mut self, caption: impl Into<String>) -> Self {
self.caption = Some(caption.into());
self
}
#[must_use]
pub fn badge(mut self, text: impl Into<String>) -> Self {
self.badge = Badge::Text(text.into());
self
}
#[must_use]
pub fn no_badge(mut self) -> Self {
self.badge = Badge::Hidden;
self
}
fn badge_text<'a>(&'a self, auto: &'a str) -> Option<&'a str> {
match &self.badge {
Badge::Auto => (!auto.is_empty()).then_some(auto),
Badge::Text(text) => Some(text.as_str()),
Badge::Hidden => None,
}
}
}
pub fn framed_decor(
frame: &mut Frame,
area: Rect,
skin: &Skin,
decor: &BoxDecor,
auto_badge: &str,
) -> Rect {
let mut block = Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(style::border(&skin.palette))
.padding(Padding::horizontal(1));
if let Some(caption) = &decor.caption {
let label = style::accent(&skin.palette).add_modifier(Modifier::BOLD);
block = block.title(title_line(skin, caption, label));
}
if let Some(badge) = decor.badge_text(auto_badge) {
block = block.title_bottom(badge_line(skin, badge).right_aligned());
}
let inner = block.inner(area);
frame.render_widget(block, area);
inner
}
fn badge_line(skin: &Skin, text: &str) -> Line<'static> {
let border = style::border(&skin.palette);
Line::from(vec![
Span::styled("\u{2500} ", border),
Span::styled(
format!("{} ", text.trim()),
style::secondary(&skin.palette),
),
Span::styled("\u{2500}", border),
])
}