use ratatui::{
prelude::*,
widgets::{Block, Borders, Clear, Paragraph, Widget, Wrap},
};
use crate::metadata::OsInfo;
pub struct AsciiInfoWidget<'a> {
pub ascii_art: &'a str,
pub os_info: Option<&'a OsInfo>,
pub vm_name: &'a str,
pub scroll: u16,
}
impl<'a> AsciiInfoWidget<'a> {
pub fn render(self, area: Rect, buf: &mut Buffer) {
Clear.render(area, buf);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Cyan));
let inner = block.inner(area);
block.render(area, buf);
let padded = Rect {
x: inner.x.saturating_add(2),
y: inner.y.saturating_add(1),
width: inner.width.saturating_sub(4),
height: inner.height.saturating_sub(1),
};
let mut lines: Vec<Line> = Vec::new();
for line in self.ascii_art.trim_start_matches('\n').lines() {
lines.push(Line::styled(line, Style::default().fg(Color::Green)));
}
lines.push(Line::from(""));
if let Some(info) = self.os_info {
lines.push(Line::from(vec![
Span::styled(&info.name, Style::default().fg(Color::White).add_modifier(Modifier::BOLD)),
]));
lines.push(Line::from(vec![
Span::styled(&info.publisher, Style::default().fg(Color::Gray)),
Span::raw(" | "),
Span::styled(&info.release_date, Style::default().fg(Color::Gray)),
Span::raw(" | "),
Span::styled(&info.architecture, Style::default().fg(Color::Gray)),
]));
lines.push(Line::from(""));
if !info.blurb.short.is_empty() {
for line in info.blurb.short.lines() {
lines.push(Line::styled(line, Style::default().fg(Color::White)));
}
lines.push(Line::from(""));
}
if !info.blurb.long.is_empty() {
lines.push(Line::from(Span::styled(
"About",
Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD),
)));
for line in info.blurb.long.lines() {
lines.push(Line::from(line.to_string()));
}
lines.push(Line::from(""));
}
if !info.fun_facts.is_empty() {
lines.push(Line::from(Span::styled(
"Fun Facts",
Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD),
)));
for fact in &info.fun_facts {
lines.push(Line::from(format!("• {}", fact)));
}
}
} else {
lines.push(Line::from(Span::styled(
self.vm_name,
Style::default().fg(Color::White).add_modifier(Modifier::BOLD),
)));
}
let para = Paragraph::new(lines)
.wrap(Wrap { trim: false })
.scroll((self.scroll, 0));
para.render(padded, buf);
}
}
pub struct DetailedInfoWidget<'a> {
pub os_info: Option<&'a OsInfo>,
pub vm_name: &'a str,
}
impl<'a> DetailedInfoWidget<'a> {
pub fn render(self, area: Rect, buf: &mut Buffer) {
let block = Block::default()
.title(format!(" {} - Details ", self.vm_name))
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Cyan));
let inner = block.inner(area);
block.render(area, buf);
if let Some(info) = self.os_info {
let mut text = vec![
Line::from(vec![
Span::styled("Name: ", Style::default().fg(Color::Yellow)),
Span::raw(&info.name),
]),
Line::from(vec![
Span::styled("Publisher: ", Style::default().fg(Color::Yellow)),
Span::raw(&info.publisher),
]),
Line::from(vec![
Span::styled("Released: ", Style::default().fg(Color::Yellow)),
Span::raw(&info.release_date),
]),
Line::from(vec![
Span::styled("Architecture: ", Style::default().fg(Color::Yellow)),
Span::raw(&info.architecture),
]),
Line::from(""),
];
if !info.blurb.long.is_empty() {
text.push(Line::from(Span::styled(
"About",
Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD),
)));
for line in info.blurb.long.lines() {
text.push(Line::from(line.to_string()));
}
text.push(Line::from(""));
}
if !info.fun_facts.is_empty() {
text.push(Line::from(Span::styled(
"Fun Facts",
Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD),
)));
for fact in &info.fun_facts {
text.push(Line::from(format!("• {}", fact)));
}
}
let para = Paragraph::new(text)
.wrap(Wrap { trim: true });
para.render(inner, buf);
} else {
let text = Paragraph::new("No detailed information available for this VM.")
.style(Style::default().fg(Color::Gray));
text.render(inner, buf);
}
}
}