upgate-presentation 0.1.1

Keep globally installed developer tools up to date
Documentation
use ratatui::style::{Color, Modifier, Style};

use crate::{OutputTheme, ThemeOptions};

pub(super) struct TuiTheme {
    pub normal: Style,
    pub muted: Style,
    pub header: Style,
    pub selected: Style,
    pub selected_row_highlight: Style,
    pub keycap: Style,
    pub primary_keycap: Style,
    pub note: Style,
    pub forced: Style,
    pub running: Style,
    pub version_changed: Style,
    pub version_changed_selected: Style,
    pub frame_border: Style,
    pub separator: Style,
    pub scrollbar_thumb: Style,
}

impl TuiTheme {
    pub(super) fn current() -> Self {
        Self::from_output_theme(OutputTheme::from_environment(ThemeOptions::default()))
    }

    fn from_output_theme(output: OutputTheme) -> Self {
        if output.color() {
            return Self {
                normal: Style::default(),
                muted: Style::default().fg(Color::Gray),
                header: Style::default()
                    .fg(Color::Magenta)
                    .add_modifier(Modifier::BOLD),
                selected: Style::default().fg(Color::Black).bg(Color::Cyan),
                selected_row_highlight: Style::default().bg(Color::Cyan),
                keycap: Style::default()
                    .fg(Color::Black)
                    .bg(Color::Gray)
                    .add_modifier(Modifier::BOLD),
                primary_keycap: Style::default()
                    .fg(Color::White)
                    .bg(Color::Blue)
                    .add_modifier(Modifier::BOLD),
                note: Style::default().fg(Color::Gray),
                forced: Style::default().fg(Color::Red),
                running: Style::default().fg(Color::Yellow),
                version_changed: Style::default().fg(Color::Blue),
                version_changed_selected: Style::default()
                    .add_modifier(Modifier::BOLD | Modifier::UNDERLINED),
                frame_border: Style::default(),
                separator: Style::default().fg(Color::Gray),
                scrollbar_thumb: Style::default().fg(Color::Black),
            };
        }

        let selected = Style::default().add_modifier(Modifier::REVERSED);
        let emphasized = Style::default().add_modifier(Modifier::BOLD);
        Self {
            normal: Style::default(),
            muted: Style::default(),
            header: emphasized,
            selected,
            selected_row_highlight: selected,
            keycap: Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED),
            primary_keycap: Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED),
            note: Style::default(),
            forced: Style::default(),
            running: emphasized,
            version_changed: emphasized,
            version_changed_selected: Style::default()
                .add_modifier(Modifier::BOLD | Modifier::UNDERLINED),
            frame_border: Style::default(),
            separator: Style::default(),
            scrollbar_thumb: Style::default().add_modifier(Modifier::REVERSED),
        }
    }

    pub(super) const fn row_for_selectable_state(&self, selected: bool) -> Style {
        if selected { self.selected } else { self.normal }
    }

    #[expect(clippy::unused_self)]
    pub(super) const fn emphasis(&self, style: Style) -> Style {
        style.add_modifier(Modifier::BOLD)
    }

    pub(super) const fn version_changed_for(&self, selected: bool) -> Style {
        if selected {
            self.version_changed_selected
        } else {
            self.version_changed
        }
    }
}