use ratatui::layout::HorizontalAlignment;
use ratatui::style::{Color, Style};
use ratatui::text::{Line, Span};
use crate::themes;
use crate::ui::{UI_GLYPHS, UI_STRINGS};
use super::{CurrentTheme, ThemeStyles, chrome_page_background, tab_active, tab_inactive};
#[must_use]
pub fn tab_node_segment(label: &str, active: bool, chord_mode: bool) -> Vec<Span<'static>> {
let t = CurrentTheme::palette();
let (circle_style, node_style) = if active {
if chord_mode {
(
Style::default().fg(t.hint),
Style::default().fg(t.background).bg(t.hint),
)
} else {
(Style::default().fg(t.tab_active_bg), tab_active())
}
} else {
(Style::default().fg(t.tab_inactive_bg), tab_inactive())
};
vec![
Span::styled(UI_GLYPHS.round_left.to_string(), circle_style),
Span::styled(format!(" {label} "), node_style),
Span::styled(UI_GLYPHS.round_right.to_string(), circle_style),
]
}
fn node_color(transparent_page: bool) -> (ratatui::style::Color, Style, Style) {
let t = CurrentTheme::palette();
let pill_bg = themes::node_pill_background(t);
let page_bg = chrome_page_background(transparent_page);
let circle_style = Style::default().fg(pill_bg).bg(page_bg);
let node_style = Style::default().fg(t.text).bg(pill_bg);
(pill_bg, circle_style, node_style)
}
fn chord_node_color(transparent_page: bool) -> (Style, Style) {
let t = CurrentTheme::palette();
let pill_bg = t.hint;
let page_bg = chrome_page_background(transparent_page);
let circle_style = Style::default().fg(pill_bg).bg(page_bg);
let node_style = Style::default().fg(t.background).bg(pill_bg);
(circle_style, node_style)
}
fn node_spans(content: &str, circle_style: Style, node_style: Style) -> Vec<Span<'static>> {
vec![
Span::styled(UI_GLYPHS.round_left.to_string(), circle_style),
Span::styled(format!(" {content} "), node_style),
Span::styled(UI_GLYPHS.round_right.to_string(), circle_style),
]
}
#[must_use]
pub fn node_line(
text: &str,
alignment: HorizontalAlignment,
chord_mode: bool,
transparent_page_chrome: bool,
) -> Line<'static> {
let (circle_style, node_style) = if chord_mode {
chord_node_color(transparent_page_chrome)
} else {
let (_, c, n) = node_color(transparent_page_chrome);
(c, n)
};
Line::from(node_spans(text, circle_style, node_style)).alignment(alignment)
}
#[must_use]
pub fn status_node_spans(
content: &str,
chord_mode: bool,
transparent_page_chrome: bool,
) -> Vec<Span<'static>> {
let (circle_style, node_style) = if chord_mode {
chord_node_color(transparent_page_chrome)
} else {
let (_, c, n) = node_color(transparent_page_chrome);
(c, n)
};
node_spans(content, circle_style, node_style)
}
#[must_use]
pub fn popup_input_accent_color(submitted: bool) -> Color {
let t = themes::current();
if submitted { t.hint } else { t.focused_border }
}
#[must_use]
pub fn popup_input_line_spans(
label: impl Into<String>,
query: impl Into<String>,
submitted: bool,
transparent_page_chrome: bool,
) -> Vec<Span<'static>> {
let t = themes::current();
let bg = if transparent_page_chrome {
chrome_page_background(true)
} else {
t.popup_bg
};
let accent = popup_input_accent_color(submitted);
vec![
Span::styled(" ", Style::default().bg(accent).fg(accent)),
Span::styled(" ", Style::default().bg(bg)),
Span::styled(label.into(), Style::default().fg(accent).bg(bg)),
Span::styled(query.into(), Style::default().fg(t.search_text).bg(bg)),
]
}
#[must_use]
pub fn search_catalog_popup_spans(
search_active: bool,
search_query: &str,
transparent_page_chrome: bool,
) -> Option<Vec<Span<'static>>> {
let show = search_active || !search_query.trim().is_empty();
if !show {
return None;
}
Some(popup_input_line_spans(
UI_STRINGS.search.search_label.to_string(),
search_query.to_string(),
!search_active,
transparent_page_chrome,
))
}
#[must_use]
pub fn viewer_footer_line(
size_str: Option<&str>,
mtime_ns: Option<i64>,
pdf_page_line: Option<&str>,
chord_mode: bool,
transparent_page_chrome: bool,
) -> Option<Line<'static>> {
use crate::utils::format_timestamp_ns;
let (circle_style, node_style) = if chord_mode {
chord_node_color(transparent_page_chrome)
} else {
let (_, c, n) = node_color(transparent_page_chrome);
(c, n)
};
let mut spans: Vec<Span<'static>> = Vec::new();
if let Some(pdf) = pdf_page_line {
spans.extend(node_spans(pdf, circle_style, node_style));
}
match (size_str, mtime_ns) {
(Some(s), None) => {
spans.extend(node_spans(s, circle_style, node_style));
}
(None, Some(ns)) => {
spans.extend(node_spans(
&format_timestamp_ns(ns),
circle_style,
node_style,
));
}
(Some(s), Some(ns)) => {
spans.extend(node_spans(s, circle_style, node_style));
spans.extend(node_spans(
&format_timestamp_ns(ns),
circle_style,
node_style,
));
}
(None, None) if pdf_page_line.is_none() => return None,
(None, None) => {}
}
Some(Line::from(spans).right_aligned())
}