stynx-code-tui 3.12.1

Terminal user interface with ratatui for interactive sessions
Documentation
use ratatui::{
    buffer::Buffer,
    layout::Rect,
    style::{Modifier, Style},
    text::{Line, Span},
    widgets::{Paragraph, Widget},
};

use crate::widgets::spinner::FRAMES;
use crate::theme;

pub struct StatusBar<'a> {
    pub model: &'a str,
    pub mode: &'a str,
    pub cost: f64,
    pub git_branch: Option<&'a str>,
    pub is_streaming: bool,
    pub spinner_frame: usize,
}

impl<'a> StatusBar<'a> {
    pub fn new(model: &'a str, mode: &'a str, cost: f64, git_branch: Option<&'a str>, is_streaming: bool, spinner_frame: usize) -> Self {
        Self { model, mode, cost, git_branch, is_streaming, spinner_frame }
    }
}

impl<'a> Widget for StatusBar<'a> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        for x in area.x..area.x + area.width {
            buf[(x, area.y)].set_style(Style::default().bg(theme::SURFACE()));
        }

        let sep = Span::styled("  ·  ", Style::default().fg(theme::HL_HIGH()).bg(theme::SURFACE()));

        let mode_span = if self.is_streaming {
            let ch = FRAMES[self.spinner_frame % FRAMES.len()];
            Span::styled(format!("{ch} generating"), Style::default().fg(theme::IRIS()).bg(theme::SURFACE()).add_modifier(Modifier::ITALIC))
        } else {
            let (icon, color) = match self.mode {
                "Auto-accept" => ("", theme::GOLD()),
                "Plan"        => ("", theme::IRIS()),
                "Bypass"      => ("", theme::LOVE()),
                _             => ("", theme::FOAM()),
            };
            Span::styled(format!("{icon}{}", self.mode), Style::default().fg(color).bg(theme::SURFACE()))
        };

        let mut spans = vec![
            Span::styled(" ", Style::default().bg(theme::SURFACE())),
            Span::styled(self.model, Style::default().fg(theme::FOAM()).bg(theme::SURFACE()).add_modifier(Modifier::BOLD)),
            sep.clone(),
            mode_span,
            sep.clone(),
            Span::styled(format!("${:.4}", self.cost), Style::default().fg(theme::IRIS()).bg(theme::SURFACE())),
        ];

        if let Some(branch) = self.git_branch {
            spans.push(sep);
            spans.push(Span::styled(
                format!("\u{E0A0} {branch}"),
                Style::default().fg(theme::PINE()).bg(theme::SURFACE()),
            ));
        }

        Paragraph::new(Line::from(spans)).render(area, buf);
    }
}