tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 660Markdown 302TOML 157RON 312382 Definiciones

⎇ c5a232cf24788ab75a850ffe81eca5a7af50e2f8 widgets/banner/src/lib.rs Rust · 109 líneas · 3.5 KB Historia Quién tocó qué crudo

chore: refresco desde el monorepo — 27 crates nuevos (anim, lottie, svg, mesh, image, layer, test, wire-view, widgets rag-sidebar/router/lazy-list/rive-button) y sync de los 95 existentes 93253cc22 · Sergio ·

1//! `llimphi-widget-banner` — tiras horizontales de status.
2//!
3//! Cuatro variants con paleta consistente entre apps:
4//!
5//! - [`BannerKind::Info`] — azul tenue, mensajes neutros.
6//! - [`BannerKind::Success`] — verde, confirmaciones de op exitosa.
7//! - [`BannerKind::Warning`] — amber, llamadas de atención.
8//! - [`BannerKind::Error`] — rojo, errores fatales o de carga.
9//!
10//! Análogo Llimphi al `nahual-widget-banner` GPUI. Los colores son
11//! **semánticos** y no cambian con el theme (un Error en dark y en
12//! light tiene que seguir leyéndose como rojo).
13
14#![forbid(unsafe_code)]
15
16use llimphi_ui::llimphi_layout::taffy::{
17    prelude::{length, percent, Size, Style},
18    AlignItems, Rect,
19};
20use llimphi_ui::llimphi_raster::peniko::Color;
21use llimphi_ui::llimphi_text::Alignment;
22use llimphi_ui::View;
23
24/// Severidad / tono del banner.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum BannerKind {
27    Info,
28    Success,
29    Warning,
30    Error,
31}
32
33impl BannerKind {
34    pub fn bg(self) -> Color {
35        match self {
36            BannerKind::Info => Color::from_rgba8(0x1d, 0x2a, 0x3a, 0xff),
37            BannerKind::Success => Color::from_rgba8(0x2d, 0x3a, 0x2a, 0xff),
38            BannerKind::Warning => Color::from_rgba8(0x4a, 0x3a, 0x1a, 0xff),
39            BannerKind::Error => Color::from_rgba8(0x4a, 0x20, 0x20, 0xff),
40        }
41    }
42
43    pub fn fg(self) -> Color {
44        match self {
45            BannerKind::Info => Color::from_rgba8(0xc0, 0xd0, 0xe0, 0xff),
46            BannerKind::Success => Color::from_rgba8(0xc0, 0xe0, 0xa0, 0xff),
47            BannerKind::Warning => Color::from_rgba8(0xf0, 0xe0, 0xa0, 0xff),
48            BannerKind::Error => Color::from_rgba8(0xff, 0xd0, 0xd0, 0xff),
49        }
50    }
51}
52
53/// Ancho del rail de severidad en el edge izquierdo. Mismo valor que
54/// `llimphi-widget-toast` — banner y toast son las versiones persistente
55/// y efímera del mismo lenguaje (P5 → P8).
56const RAIL_W: f32 = 3.0;
57
58/// Banner simple: una fila con `message` centrado verticalmente y
59/// alineado a la izquierda. bg/fg vienen del `kind`.
60pub fn banner_view<Msg: Clone + 'static>(
61    kind: BannerKind,
62    message: impl Into<String>,
63) -> View<Msg> {
64    use llimphi_ui::llimphi_layout::taffy::prelude::FlexDirection;
65
66    // Rail de severidad en el edge izquierdo — stripe del color fg
67    // semántico, visible al pasar el ojo. Mismo patrón que toast P5.
68    let rail = View::new(Style {
69        size: Size {
70            width: length(RAIL_W),
71            height: percent(1.0_f32),
72        },
73        flex_shrink: 0.0,
74        ..Default::default()
75    })
76    .fill(kind.fg());
77
78    // Contenedor del mensaje: padding original ahora vive aquí para que
79    // el rail pegue al borde sin offset y el texto arranque después.
80    let body = View::new(Style {
81        size: Size {
82            width: percent(1.0_f32),
83            height: percent(1.0_f32),
84        },
85        padding: Rect {
86            left: length(12.0_f32),
87            right: length(12.0_f32),
88            top: length(6.0_f32),
89            bottom: length(6.0_f32),
90        },
91        align_items: Some(AlignItems::Center),
92        ..Default::default()
93    })
94    .text_aligned(message.into(), 11.0, kind.fg(), Alignment::Start);
95
96    View::new(Style {
97        flex_direction: FlexDirection::Row,
98        size: Size {
99            width: percent(1.0_f32),
100            height: length(28.0_f32),
101        },
102        align_items: Some(AlignItems::Center),
103        ..Default::default()
104    })
105    .fill(kind.bg())
106    .radius(3.0)
107    .clip(true)
108    .children(vec![rail, body])
109}