feat(tui): ratatui skeleton with layout

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
dailz
2026-04-10 21:20:14 +08:00
parent 09e7f995fb
commit 73322138c1
3 changed files with 84 additions and 1 deletions

17
crates/tui/src/app.rs Normal file
View File

@@ -0,0 +1,17 @@
pub struct App {
pub should_quit: bool,
}
impl App {
pub fn new() -> Self {
Self { should_quit: false }
}
pub fn handle_key(&mut self, key: crossterm::event::KeyEvent) {
match key.code {
crossterm::event::KeyCode::Char('q') => self.should_quit = true,
crossterm::event::KeyCode::Esc => self.should_quit = true,
_ => {}
}
}
}

View File

@@ -1 +1,41 @@
fn main() {}
use clap::Parser;
mod app;
mod ui;
#[derive(Parser)]
#[command(name = "log-viewer", about = "A log viewer TUI")]
struct Cli {
/// Log files to open
files: Vec<String>,
}
fn main() -> anyhow::Result<()> {
let _cli = Cli::parse();
crossterm::terminal::enable_raw_mode()?;
let mut stdout = std::io::stdout();
crossterm::execute!(stdout, crossterm::terminal::EnterAlternateScreen)?;
let backend = ratatui::backend::CrosstermBackend::new(stdout);
let mut terminal = ratatui::Terminal::new(backend)?;
let mut app = app::App::new();
while !app.should_quit {
terminal.draw(|frame| ui::render(frame, &app))?;
if crossterm::event::poll(std::time::Duration::from_millis(100))?
&& let crossterm::event::Event::Key(key) = crossterm::event::read()?
{
app.handle_key(key);
}
}
crossterm::terminal::disable_raw_mode()?;
crossterm::execute!(
terminal.backend_mut(),
crossterm::terminal::LeaveAlternateScreen
)?;
terminal.show_cursor()?;
Ok(())
}

26
crates/tui/src/ui.rs Normal file
View File

@@ -0,0 +1,26 @@
use crate::app::App;
pub fn render(frame: &mut ratatui::Frame, _app: &App) {
use ratatui::layout::{Constraint, Layout};
use ratatui::widgets::{Block, Borders, Paragraph};
let chunks = Layout::vertical([
Constraint::Length(1),
Constraint::Min(1),
Constraint::Length(1),
])
.split(frame.area());
frame.render_widget(
Paragraph::new(" Log Viewer").style(ratatui::style::Style::default().bold()),
chunks[0],
);
// Main area — 使用 Block::new()ratatui 0.30 推荐风格)
frame.render_widget(
Block::new().borders(Borders::ALL).title("No file loaded"),
chunks[1],
);
frame.render_widget(Paragraph::new(" Press '?' for help | q to quit"), chunks[2]);
}