Introduce a parallel TUI built on the tuie widget toolkit, selectable at runtime with `--engine tuie`. ratatui remains the default and its crossterm/ratatui deps are retained, so default users see no behavior change; this lands the full screen/widget tree for the new engine side-by-side with the existing one. Engine wiring: - Cargo: add `tuie` (harmonious, images features) - main.rs: `--engine` flag + run_tuie_tui() entry path - src/ui: new `screens`, `widgets`, `theme`, `tuie_app` modules - app::recent_commits made pub(crate) for dashboard reuse Screens: splash (procedural bloom), welcome dashboard, chat (live streaming), agents picker, settings, plus cron/presence stubs. Widgets: brand_title, portrait, menu_list, message_list, chat_bubble, chat_input, cockpit, phase_bar, tool_card, and a reusable `responsive` container. Responsive welcome: the welcome screen now offers two viewable modes the way the old ratatui dashboard did — a side-by-side portrait/stats layout at >=100 cols and a stacked single column below it — switched by the new `Responsive` widget. It holds both subtrees and lays out / paints only the one that fits, while exposing both to id lookups so the menu selection survives a resize across the breakpoint. Flourishes: a breathing title colour pulse and a portrait border that surfaces subconscious state. Covered by a layout test driving a TestTerminal across the breakpoint.
96 lines
4.3 KiB
Rust
96 lines
4.3 KiB
Rust
//! Atmosphere → tuie Theme mapping.
|
|
//!
|
|
//! tuie's `harmonious` feature generates a 256-color palette from an 8-color
|
|
//! `Theme` struct. We map Souveraine's `ChatPalette` (derived from the active
|
|
//! `Atmosphere`) onto tuie's Theme slots so the terminal palette tracks the
|
|
//! agent's atmospheric shift — live, without restarting.
|
|
|
|
use tuie::prelude::Color;
|
|
use tuie::theme::Theme;
|
|
|
|
use crate::ui::atmosphere::Atmosphere;
|
|
use crate::ui::chat::ChatPalette;
|
|
|
|
/// Map a ChatPalette onto tuie's 8-color Theme slots.
|
|
///
|
|
/// The mapping is approximate but intentional — each role in ChatPalette
|
|
/// lands on the Theme slot that best expresses its semantic weight:
|
|
///
|
|
/// | ChatPalette role | Theme slot | Rationale |
|
|
/// |----------------------|-------------|----------------------------------|
|
|
/// | `bg` | `bg` | terminal background |
|
|
/// | `agent_dim` | `fg` | default foreground / muted text |
|
|
/// | `user_accent` | `cyan` | cool, distinct from agent colors |
|
|
/// | `tool_accent` | `green` | "go" signal, success |
|
|
/// | `agent_primary` | `yellow` | warmth, attention |
|
|
/// | `surfacing` | `magenta` | consciousness surfacing |
|
|
/// | `compaction` | `red` | urgency, warning |
|
|
/// | `reflection` | `blue` | calm, reflective |
|
|
pub fn chat_palette_to_theme(palette: &ChatPalette) -> Theme {
|
|
Theme {
|
|
bg: to_tuie_rgb(palette.bg),
|
|
fg: to_tuie_rgb(palette.agent_dim),
|
|
cyan: to_tuie_rgb(palette.user_accent),
|
|
green: to_tuie_rgb(palette.tool_accent),
|
|
yellow: to_tuie_rgb(palette.agent_primary),
|
|
magenta: to_tuie_rgb(palette.surfacing),
|
|
red: to_tuie_rgb(palette.compaction),
|
|
blue: to_tuie_rgb(palette.reflection),
|
|
}
|
|
}
|
|
|
|
/// Apply an atmosphere to tuie's global palette.
|
|
///
|
|
/// Builds a Theme from the atmosphere's ChatPalette, generates the 256-color
|
|
/// harmonious palette, and applies it globally. Calls `dirty_layout()` so all
|
|
/// widgets re-render on the next frame.
|
|
pub fn apply_atmosphere(atm: Atmosphere) {
|
|
let palette = ChatPalette::from_atmosphere(atm);
|
|
let theme = chat_palette_to_theme(&palette);
|
|
tuie::theme::harmonious::apply_palette(
|
|
tuie::theme::harmonious::Palette::from_theme(theme),
|
|
);
|
|
tuie::dirty_layout();
|
|
}
|
|
|
|
/// Convert a ratatui Color to a tuie Rgb.
|
|
///
|
|
/// tuie uses its own `Rgb` type (in `tuie::util::rgb`) for the Theme struct,
|
|
/// while the rest of the widget system uses `tuie::prelude::Color`. This
|
|
/// helper bridges ratatui colors (still used by ChatPalette during the dual-
|
|
/// stack transition) into tuie's Theme format.
|
|
fn to_tuie_rgb(c: ratatui::style::Color) -> tuie::util::rgb::Rgb {
|
|
match c {
|
|
ratatui::style::Color::Rgb(r, g, b) => tuie::util::rgb::Rgb::new(r, g, b),
|
|
_ => tuie::util::rgb::Rgb::new(255, 140, 66), // fallback: Default primary
|
|
}
|
|
}
|
|
|
|
/// Convert a ratatui Color to a tuie Color.
|
|
///
|
|
/// Used when building tuie `Style` objects from `ChatPalette` colors during
|
|
/// the transition period. Once ratatui is fully removed, ChatPalette can
|
|
/// directly use tuie Color.
|
|
pub fn to_tuie_color(c: ratatui::style::Color) -> Color {
|
|
match c {
|
|
ratatui::style::Color::Rgb(r, g, b) => Color::Rgb(r, g, b),
|
|
ratatui::style::Color::Reset => Color::Foreground,
|
|
ratatui::style::Color::Black => Color::BLACK,
|
|
ratatui::style::Color::Red => Color::RED,
|
|
ratatui::style::Color::Green => Color::GREEN,
|
|
ratatui::style::Color::Yellow => Color::YELLOW,
|
|
ratatui::style::Color::Blue => Color::BLUE,
|
|
ratatui::style::Color::Magenta => Color::MAGENTA,
|
|
ratatui::style::Color::Cyan => Color::CYAN,
|
|
ratatui::style::Color::Gray => Color::BRIGHT_BLACK,
|
|
ratatui::style::Color::DarkGray => Color::BRIGHT_BLACK,
|
|
ratatui::style::Color::LightRed => Color::BRIGHT_RED,
|
|
ratatui::style::Color::LightGreen => Color::BRIGHT_GREEN,
|
|
ratatui::style::Color::LightYellow => Color::BRIGHT_YELLOW,
|
|
ratatui::style::Color::LightBlue => Color::BRIGHT_BLUE,
|
|
ratatui::style::Color::LightMagenta => Color::BRIGHT_MAGENTA,
|
|
ratatui::style::Color::LightCyan => Color::BRIGHT_CYAN,
|
|
ratatui::style::Color::White => Color::WHITE,
|
|
_ => Color::Rgb(255, 140, 66),
|
|
}
|
|
}
|