tawasuyu

tawasuyu/llimphi

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

Rust 660Markdown 302TOML 157RON 312382 Sutichaykuna

⎇ c5a232cf24788ab75a850ffe81eca5a7af50e2f8 widgets/tiled/examples/tiled_demo.rs Rust · 218 siq'ikuna · 5.8 KB Ñawpa willay Pi imata llamkarqan ch'uya

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//! Showcase de `llimphi-widget-tiled` con drag-to-swap. Cinco paneles
2//! heterogéneos; arrastra la title bar de uno sobre otro para
3//! intercambiarlos. El destino se ilumina mientras está bajo el cursor.
4//!
5//! Corre con: `cargo run -p llimphi-widget-tiled --example tiled_demo --release`.
6
7use llimphi_theme::Theme;
8use llimphi_ui::llimphi_layout::taffy::{
9    prelude::{length, percent, FlexDirection, Size, Style},
10    Rect,
11};
12use llimphi_ui::llimphi_raster::peniko::Color;
13use llimphi_ui::llimphi_text::Alignment;
14use llimphi_ui::{App, Handle, View};
15use llimphi_widget_tiled::{tiled_view_reorderable, TileSpec, TiledPalette};
16
17#[derive(Clone, Copy, PartialEq, Eq)]
18enum TileId {
19    Logs,
20    Metrics,
21    Alerts,
22    Uptime,
23    Queue,
24}
25
26#[derive(Clone)]
27enum Msg {
28    Swap { from: usize, to: usize },
29}
30
31struct Model {
32    tiles: Vec<TileId>,
33}
34
35struct Showcase;
36
37impl App for Showcase {
38    type Model = Model;
39    type Msg = Msg;
40
41    fn title() -> &'static str {
42        "llimphi · tiled showcase (drag titles para intercambiar)"
43    }
44
45    fn initial_size() -> (u32, u32) {
46        (1100, 720)
47    }
48
49    fn init(_: &Handle<Msg>) -> Model {
50        Model {
51            tiles: vec![
52                TileId::Logs,
53                TileId::Metrics,
54                TileId::Alerts,
55                TileId::Uptime,
56                TileId::Queue,
57            ],
58        }
59    }
60
61    fn update(model: Model, msg: Msg, _: &Handle<Msg>) -> Model {
62        let mut m = model;
63        match msg {
64            Msg::Swap { from, to } => {
65                if from != to && from < m.tiles.len() && to < m.tiles.len() {
66                    m.tiles.swap(from, to);
67                }
68            }
69        }
70        m
71    }
72
73    fn view(model: &Model) -> View<Msg> {
74        let theme = Theme::dark();
75        let palette = TiledPalette::from_theme(&theme);
76
77        let tiles: Vec<TileSpec<Msg>> = model
78            .tiles
79            .iter()
80            .map(|id| match id {
81                TileId::Logs => TileSpec {
82                    label: "logs".into(),
83                    content: log_body(&theme),
84                },
85                TileId::Metrics => TileSpec {
86                    label: "métricas".into(),
87                    content: metrics_body(&theme),
88                },
89                TileId::Alerts => TileSpec {
90                    label: "alertas".into(),
91                    content: alerts_body(&theme),
92                },
93                TileId::Uptime => TileSpec {
94                    label: "uptime".into(),
95                    content: uptime_body(&theme),
96                },
97                TileId::Queue => TileSpec {
98                    label: "queue".into(),
99                    content: queue_body(&theme),
100                },
101            })
102            .collect();
103
104        tiled_view_reorderable(
105            tiles,
106            |from, to| Some(Msg::Swap { from, to }),
107            &palette,
108        )
109    }
110}
111
112fn padded(text: &str, size: f32, color: Color, align: Alignment) -> View<Msg> {
113    View::new(Style {
114        size: Size {
115            width: percent(1.0_f32),
116            height: percent(1.0_f32),
117        },
118        flex_grow: 1.0,
119        padding: Rect {
120            left: length(14.0_f32),
121            right: length(14.0_f32),
122            top: length(10.0_f32),
123            bottom: length(10.0_f32),
124        },
125        ..Default::default()
126    })
127    .text_aligned(text.to_string(), size, color, align)
128}
129
130fn log_body(theme: &Theme) -> View<Msg> {
131    padded(
132        "[12:01:33] boot\n[12:01:34] config ok\n[12:01:35] esperando eventos…\n[12:02:01] cliente 1 conectó\n[12:02:02] cliente 2 conectó",
133        12.0,
134        theme.fg_text,
135        Alignment::Start,
136    )
137}
138
139fn metrics_body(theme: &Theme) -> View<Msg> {
140    let stat = |label: &str, value: &str, color: Color| -> View<Msg> {
141        let label_view = View::new(Style {
142            size: Size {
143                width: percent(1.0_f32),
144                height: length(14.0_f32),
145            },
146            ..Default::default()
147        })
148        .text_aligned(label.to_string(), 10.0, theme.fg_muted, Alignment::Start);
149        let value_view = View::new(Style {
150            size: Size {
151                width: percent(1.0_f32),
152                height: length(28.0_f32),
153            },
154            ..Default::default()
155        })
156        .text_aligned(value.to_string(), 22.0, color, Alignment::Start);
157        View::new(Style {
158            flex_direction: FlexDirection::Column,
159            size: Size {
160                width: percent(1.0_f32),
161                height: percent(1.0_f32),
162            },
163            flex_grow: 1.0,
164            ..Default::default()
165        })
166        .children(vec![label_view, value_view])
167    };
168
169    View::new(Style {
170        flex_direction: FlexDirection::Row,
171        size: Size {
172            width: percent(1.0_f32),
173            height: percent(1.0_f32),
174        },
175        gap: Size {
176            width: length(12.0_f32),
177            height: length(0.0_f32),
178        },
179        padding: Rect {
180            left: length(14.0_f32),
181            right: length(14.0_f32),
182            top: length(10.0_f32),
183            bottom: length(10.0_f32),
184        },
185        ..Default::default()
186    })
187    .children(vec![
188        stat("cpu", "37%", theme.accent),
189        stat("ram", "1.2 G", theme.fg_text),
190        stat("net", "12 kB/s", theme.fg_text),
191    ])
192}
193
194fn alerts_body(theme: &Theme) -> View<Msg> {
195    padded(
196        "● info: dos clientes online\n● warn: latencia 250 ms\n● ok: backup nocturno verde",
197        12.0,
198        theme.fg_text,
199        Alignment::Start,
200    )
201}
202
203fn uptime_body(theme: &Theme) -> View<Msg> {
204    padded("4d 12h 33m", 26.0, theme.accent, Alignment::Center)
205}
206
207fn queue_body(theme: &Theme) -> View<Msg> {
208    padded(
209        "pending: 7\nin-flight: 2\ndone (24h): 1842",
210        13.0,
211        theme.fg_text,
212        Alignment::Start,
213    )
214}
215
216fn main() {
217    llimphi_ui::run::<Showcase>();
218}