Skip to main content

teamctl_ui/
splash.rs

1//! Splash screen widget — figlet-isometric4 logo, version + team line,
2//! help-hint footer. Shown for ~3 seconds at launch (or until a key
3//! press) before the Triptych takes over. The art is vendored as a
4//! static asset; regenerate with `figlet -f isometric4 teamctl` when
5//! the wordmark changes.
6
7use ratatui::buffer::Buffer;
8use ratatui::layout::{Alignment, Constraint, Direction, Layout, Rect};
9use ratatui::style::{Modifier, Style};
10use ratatui::widgets::{Paragraph, Widget};
11
12use crate::app::App;
13
14const SPLASH_ART: &str = include_str!("assets/splash.txt");
15
16pub fn draw(f: &mut ratatui::Frame<'_>, app: &App) {
17    Splash { app }.render(f.area(), f.buffer_mut());
18}
19
20/// Standalone widget for snapshot tests: rendering into a `Buffer`
21/// directly is enough to assert layout without a `Terminal`.
22pub struct Splash<'a> {
23    pub app: &'a App,
24}
25
26impl Widget for Splash<'_> {
27    fn render(self, area: Rect, buf: &mut Buffer) {
28        let chunks = Layout::default()
29            .direction(Direction::Vertical)
30            .constraints([
31                Constraint::Min(0),     // top spacer
32                Constraint::Length(11), // logo (10 lines of art + 1 padding)
33                Constraint::Length(1),  // version + team line
34                Constraint::Length(1),  // hint line
35                Constraint::Min(0),     // bottom spacer
36            ])
37            .split(area);
38
39        let accent = Style::default()
40            .fg(self.app.capabilities.accent())
41            .add_modifier(Modifier::BOLD);
42        let muted = Style::default().fg(self.app.capabilities.muted());
43
44        Paragraph::new(SPLASH_ART)
45            .style(accent)
46            .alignment(Alignment::Center)
47            .render(chunks[1], buf);
48
49        let count = self.app.team.agents.len();
50        let team_line = format!(
51            "v{}  ·  {}  ·  {} agent{}",
52            self.app.version,
53            self.app.team.team_name,
54            count,
55            if count == 1 { "" } else { "s" }
56        );
57        Paragraph::new(team_line)
58            .alignment(Alignment::Center)
59            .render(chunks[2], buf);
60
61        Paragraph::new("Press `?` for help · `t` for tutorial")
62            .style(muted)
63            .alignment(Alignment::Center)
64            .render(chunks[3], buf);
65    }
66}