zilliz 1.3.2

TUI and CLI tool for managing Zilliz Cloud clusters and Milvus operations
Documentation
use ratatui::prelude::*;
use ratatui::widgets::Paragraph;

use crate::tui::app::App;

/// ASCII art "Zilliz" with per-column gradient matching the SVG:
/// purple (#9D41FF) -> blue (#2858FF) -> light-blue (#29B8FF) -> cyan (#00F0FF)
///
/// Letter column ranges (0-indexed within the art):
///   Z: 0-6, i: 8-10, l: 12-14, l: 16-18, i: 20-22, z: 24-29
const LOGO_ART: [&str; 6] = [
    " ______  _   _   _   _   ______",
    " |___  / (_) | | | | (_) |___  /",
    "    / /   _  | | | |  _     / / ",
    "   / /   | | | | | | | |   / /  ",
    "  / /__  | | | | | | | |  / /__ ",
    " /_____| |_| |_| |_| |_| /_____|",
];

fn logo_lines() -> Vec<Line<'static>> {
    // Column-based gradient: map each character's x position to a color.
    // The art is ~30 chars wide; gradient spans left to right.
    let gradient: [(u8, u8, u8); 6] = [
        (157, 65, 255), // purple
        (120, 70, 255),
        (80, 80, 255),
        (40, 88, 255),
        (41, 150, 255),
        (0, 240, 255), // cyan
    ];

    LOGO_ART
        .iter()
        .map(|row| {
            let width = row.len().max(1);
            let spans: Vec<Span> = row
                .chars()
                .enumerate()
                .map(|(i, ch)| {
                    let t = i as f32 / (width - 1) as f32;
                    let idx = (t * (gradient.len() - 1) as f32).min((gradient.len() - 1) as f32);
                    let lo = idx.floor() as usize;
                    let hi = (lo + 1).min(gradient.len() - 1);
                    let frac = idx - lo as f32;
                    let r =
                        (gradient[lo].0 as f32 * (1.0 - frac) + gradient[hi].0 as f32 * frac) as u8;
                    let g =
                        (gradient[lo].1 as f32 * (1.0 - frac) + gradient[hi].1 as f32 * frac) as u8;
                    let b =
                        (gradient[lo].2 as f32 * (1.0 - frac) + gradient[hi].2 as f32 * frac) as u8;
                    Span::styled(
                        ch.to_string(),
                        Style::default()
                            .fg(Color::Rgb(r, g, b))
                            .add_modifier(Modifier::BOLD),
                    )
                })
                .collect();
            Line::from(spans)
        })
        .collect()
}

pub fn render(frame: &mut Frame, _app: &App, area: Rect) {
    let version = env!("CARGO_PKG_VERSION");

    let version_line = format!("v{}", version);

    let hints: Vec<&str> = vec![
        "Manage your Zilliz Cloud resources from the terminal.",
        "",
        "Run `zilliz --help` to get started.  Press q to quit.",
    ];

    let hints_height = hints.len() as u16;

    let logo = logo_lines();
    let logo_height = logo.len() as u16;

    // Total content: logo + blank + version + blank + hints
    let content_height = logo_height + 1 + 1 + 1 + hints_height;
    let top_pad = area.height.saturating_sub(content_height) / 2;

    let mut lines: Vec<Line> = Vec::new();

    for _ in 0..top_pad {
        lines.push(Line::from(""));
    }

    lines.extend(logo);

    lines.push(Line::from(""));

    lines.push(Line::from(Span::styled(
        version_line,
        Style::default().fg(Color::DarkGray),
    )));

    lines.push(Line::from(""));

    for hint in &hints {
        lines.push(Line::from(Span::styled(
            *hint,
            Style::default().fg(Color::Gray),
        )));
    }

    let paragraph = Paragraph::new(lines).alignment(Alignment::Center);

    frame.render_widget(paragraph, area);
}