aura-gui 0.2.1

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.
//! Sombras y animaciones de Aura UI en una pantalla. Funciona igual en escritorio, Android e iOS.
//!
//! ```bash
//! cargo run -p aura-gui --example vitrina
//! ```

use aura_ui::prelude::*;
use std::time::Duration;

struct Vitrina {
    abierto: bool,
}

fn tarjeta(titulo: &str, sombra: impl Into<Shadows>) -> Div {
    div()
        .w(px(120.0))
        .h(px(80.0))
        .flex()
        .items_center()
        .justify_center()
        .rounded_xl()
        .bg(Token::ElevatedSurface)
        .shadow(sombra)
        .child(titulo.to_owned())
}

impl Render for Vitrina {
    fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement {
        let muelle = Animation::new(Duration::from_millis(600)).easing(Easing::SPRING);
        // Se desliza hacia el nuevo destino cada vez que cambia `abierto`, partiendo de donde iba.
        let desplazamiento = cx.transition("panel", if self.abierto { 180.0 } else { 0.0 }, muelle);
        let pulso = cx.animate("pulso", Animation::new(Duration::from_millis(900)).easing(Easing::EaseInOut).ping_pong());
        let entrada = Animation::new(Duration::from_millis(500)).easing(Easing::STANDARD);
        let fondo = cx.animate_between("fondo", entrada, Rgba { r: 0.2, g: 0.4, b: 1.0, a: 0.0 }, Rgba {
            r: 0.2,
            g: 0.4,
            b: 1.0,
            a: 1.0,
        });

        div()
            .size_full()
            .flex_col()
            .items_start()
            .gap_6()
            .p_6()
            .bg(Token::Canvas)
            .text_color(Token::Text)
            .child(
                div()
                    .flex_row()
                    .flex_wrap()
                    .gap_6()
                    .child(tarjeta("xs", ShadowPreset::Xs))
                    .child(tarjeta("md", ShadowPreset::Md))
                    .child(tarjeta("2xl", ShadowPreset::Xxl))
                    .child(tarjeta("capas", Shadows::one(BoxShadow::new(0.0, 4.0, 6.0).spread(-1.0).strength(0.5)).with(
                        BoxShadow::new(0.0, 12.0, 24.0).spread(-4.0).strength(0.6),
                    )))
                    .child(tarjeta("color", BoxShadow::new(0.0, 8.0, 20.0).color(fondo))),
            )
            .child(
                div()
                    .w(px(16.0))
                    .h(px(16.0))
                    .rounded_full()
                    .bg(Token::Accent)
                    .opacity(0.4 + 0.6 * pulso)
                    .glow(Token::Accent, 4.0 + 12.0 * pulso),
            )
            .child(Button::new(if self.abierto { "Cerrar" } else { "Abrir" }).variant(ButtonVariant::Primary).on_click(
                cx.listener(|this: &mut Vitrina, _: &ClickEvent, cx| {
                    this.abierto = !this.abierto;
                    cx.notify();
                }),
            ))
            .child(
                div()
                    .ml(px(desplazamiento))
                    .w(px(160.0))
                    .p_4()
                    .rounded_lg()
                    .bg(fondo)
                    .shadow_lg()
                    .child("Panel con muelle"),
            )
            .into_element()
    }
}

aura_ui::main!(AppOptions::new("Vitrina").size(760.0, 520.0), |window| window.set_root(Vitrina { abierto: false }));