aura-gui 0.3.5

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
//! Temas incluidos. Cada uno se describe con una paleta compacta en hexadecimal.

use crate::core::Rgba;
use crate::view::theme::{SyntaxTheme, Theme};

mod ansi;
mod families;

pub use ansi::{ansi_palette, ansi_palette_names};
pub use families::*;

struct Palette {
    name: &'static str,
    is_dark: bool,
    /// canvas, surface, elevated, border, border_subtle, text, text_muted.
    base: [u32; 7],
    /// accent, accent_hover, danger, danger_hover, warning, success, hover, active.
    states: [u32; 8],
    /// keyword, function, type, string, comment, constant, attribute, operator, property, tag, title, link.
    syntax: [u32; 12],
    ansi: [u32; 16],
}

fn build(palette: Palette) -> Theme {
    let [canvas, surface, elevated, border, border_subtle, text, text_muted] = palette.base.map(Rgba::hex);
    let [accent, accent_hover, danger, danger_hover, warning, success, hover, active] = palette.states.map(Rgba::hex);
    let [keyword, function, type_name, string, comment, constant, attribute, operator, property, tag, title, link] =
        palette.syntax.map(Rgba::hex);
    Theme {
        name: palette.name.to_owned(),
        is_dark: palette.is_dark,
        canvas,
        surface,
        elevated_surface: elevated,
        border,
        border_subtle,
        border_focused: accent,
        text,
        text_muted,
        accent,
        accent_hover,
        accent_text: Rgba::hex(0xffffff),
        danger,
        danger_hover,
        danger_text: Rgba::hex(0xffffff),
        warning,
        success,
        created: success,
        modified: warning,
        deleted: danger,
        conflict: danger.mix(accent, 0.5),
        hover,
        active,
        selection: accent.with_alpha(if palette.is_dark { 0.35 } else { 0.22 }),
        shadow: Rgba::new(0.0, 0.0, 0.0, if palette.is_dark { 0.5 } else { 0.18 }),
        syntax: SyntaxTheme {
            keyword,
            function,
            type_name,
            string,
            comment,
            constant,
            attribute,
            operator,
            property,
            tag,
            title,
            link,
        },
        ansi: palette.ansi.map(Rgba::hex),
    }
}

const ANSI_DARK: [u32; 16] = [
    0x3f3f46, 0xef4444, 0x22c55e, 0xeab308, 0x3b82f6, 0xa855f7, 0x06b6d4, 0xe4e4e7, 0x71717a, 0xf87171, 0x4ade80,
    0xfacc15, 0x60a5fa, 0xc084fc, 0x22d3ee, 0xfafafa,
];
const ANSI_LIGHT: [u32; 16] = [
    0x18181b, 0xdc2626, 0x16a34a, 0xa16207, 0x2563eb, 0x9333ea, 0x0891b2, 0x71717a, 0x52525b, 0xef4444, 0x15803d,
    0xca8a04, 0x3b82f6, 0xa855f7, 0x0e7490, 0x27272a,
];

/// Temas incluidos y, después, los del usuario (`theme_json`).
pub fn all_themes() -> Vec<Theme> {
    let mut themes = vec![
        aura_dark(),
        aura_light(),
        one_dark(),
        one_light(),
        gruvbox_dark(),
        catppuccin_mocha(),
        catppuccin_latte(),
        tokyo_night(),
        dracula(),
        nord(),
        solarized_dark(),
        solarized_light(),
        rose_pine(),
    ];
    themes.extend(crate::view::theme_json::user_themes());
    themes
}

pub fn theme_by_name(name: &str) -> Option<Theme> {
    all_themes().into_iter().find(|theme| theme.name.eq_ignore_ascii_case(name))
}