use std::io;
use crossterm::{
event::{self, Event, KeyCode},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
Terminal,
backend::CrosstermBackend,
layout::{Constraint, Direction, Layout},
style::{Color, Style},
text::Line,
widgets::Paragraph,
};
use a2ui::core::catalog::Catalog;
use a2ui::core::message_processor::MessageProcessor;
use a2ui::tui::catalogs::basic::{build_basic_catalog, build_basic_registry};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let default_path = format!("{}/examples/assets/bad-apple.png", env!("CARGO_MANIFEST_DIR"));
let image_path = std::env::args().nth(1).unwrap_or(default_path);
if !std::path::Path::new(&image_path).is_file() {
return Err(format!("image file not found: {image_path}").into());
}
let registry = build_basic_registry();
let render_catalog = Catalog::new("placeholder");
let mut processor = MessageProcessor::new(vec![build_basic_catalog()]);
let create = serde_json::json!({
"version": "v1.0",
"createSurface": {
"surfaceId": "img",
"catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"
}
});
let update = serde_json::json!({
"version": "v1.0",
"updateComponents": {
"surfaceId": "img",
"components": [
{
"id": "root",
"component": "Card",
"child": "body"
},
{
"id": "body",
"component": "Column",
"children": ["title", "image"]
},
{
"id": "title",
"component": "Text",
"text": "A2UI Image Demo",
"variant": "h2"
},
{
"id": "image",
"component": "Image",
"url": image_path,
"description": "A2UI Image Demo"
}
]
}
});
processor.process_message(MessageProcessor::parse_message(&create.to_string())?)?;
processor.process_message(MessageProcessor::parse_message(&update.to_string())?)?;
enable_raw_mode()?;
let mut stdout = io::stderr();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(io::stderr());
let mut terminal = Terminal::new(backend)?;
loop {
terminal.draw(|frame| {
let area = frame.area();
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(3), Constraint::Length(1)])
.split(area);
if let Some(surface) = processor.model.get_surface("img") {
let renderer = a2ui::tui::surface::SurfaceRenderer::new(
surface,
®istry,
&render_catalog,
);
renderer.render(frame, chunks[0], None);
}
let proto = a2ui::tui::components::image::detected_protocol();
let bar = Paragraph::new(Line::from(format!(
" ratatui-image · protocol: {proto} · q: quit",
)))
.style(Style::default().fg(Color::DarkGray));
frame.render_widget(bar, chunks[1]);
})?;
if event::poll(std::time::Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
if key.code == KeyCode::Char('q') {
break;
}
}
}
}
disable_raw_mode()?;
execute!(stdout, LeaveAlternateScreen)?;
println!("Goodbye! (image rendered via ratatui-image)");
Ok(())
}