use crossterm::event::{self, Event, KeyCode}; use ratatui::style::Style; use ratatui::text::{Line, Span}; use ratatui::widgets::Paragraph; use std::io; use sysop_tui::{Footer, GlobalAction, classify, hint, layout, palette, selection, style}; enum State { Ok, Warn, Fault, Inactive, } struct Service { name: &'static str, state: State, } fn state_span(s: &State) -> Span<'static> { match s { State::Ok => style::ok("ok"), State::Warn => style::warn("syncing"), State::Fault => style::fault("down"), State::Inactive => style::inactive("stopped"), } } fn services() -> Vec { vec![ Service { name: "sshd", state: State::Ok }, Service { name: "unbound", state: State::Ok }, Service { name: "chronyd", state: State::Ok }, Service { name: "caddy", state: State::Warn }, Service { name: "nebula", state: State::Fault }, Service { name: "tlp", state: State::Inactive }, ] } fn body(items: &[Service], selected: usize) -> Paragraph<'_> { let lines: Vec = items .iter() .enumerate() .map(|(i, s)| { let is_sel = i == selected; let marker = if is_sel { selection::MARKER } else { " " }; let line = Line::from(vec![ Span::raw(format!(" {} ", marker)), Span::raw(format!("{:<12}", s.name)), Span::raw(" "), state_span(&s.state), ]); if is_sel { line.style(selection::selected_style()) } else { line } }) .collect(); Paragraph::new(lines).style(Style::default().bg(palette::BG).fg(palette::FG)) } fn main() -> io::Result<()> { let mut terminal = ratatui::init(); let services = services(); let mut idx: usize = 0; let footer = Footer::new([ hint("j/k", "move"), hint("Enter", "details"), hint("?", "help"), hint("q", "quit"), ]); let result: io::Result<()> = loop { let draw = terminal.draw(|frame| { let [body_area, foot_area] = layout::split(frame.area()); frame.render_widget(body(&services, idx), body_area); frame.render_widget(&footer, foot_area); }); if let Err(e) = draw { break Err(e); } match event::read() { Ok(Event::Key(key)) => match classify(key) { GlobalAction::Quit => break Ok(()), GlobalAction::Passthrough => match key.code { KeyCode::Char('j') | KeyCode::Down if idx + 1 < services.len() => { idx += 1; } KeyCode::Char('k') | KeyCode::Up => { idx = idx.saturating_sub(1); } _ => {} }, _ => {} }, Ok(_) => {} Err(e) => break Err(e), } }; ratatui::restore(); result }