use ruin_app::prelude::*; use ruin_ui::Border; #[ruin_runtime::async_main] async fn main() -> ruin_app::Result<()> { let title = "RUIN Counter"; App::new() .window( Window::new() .title(title) .app_id("dev.ruin.counter") .size(960.0, 640.0), ) .mount(view! { CounterApp(title = title) {} }) .run() .await } #[component] fn CounterApp(title: &'static str) -> impl IntoView { let count = use_signal(|| 0_i32); let doubled = use_memo({ let count = count.clone(); move || count.get() * 2 }); use_window_title({ let count = count.clone(); move || format!("{title} ({})", count.get()) }); view! { column(gap = 16.0, padding = 24.0) { text(role = TextRole::Heading(1), size = 32.0, weight = FontWeight::Semibold) { title } CounterActions(count = count.clone()) {} block( padding = 16.0, gap = 8.0, background = surfaces::raised(), border_radius = 12.0, border = Border::new(2.0, Color::rgb(0, 0, 0)) ) { text(size = 18.0) { "count = "; count.clone() } text(color = colors::muted()) { "double = "; doubled.clone() } } } } } #[component] fn CounterActions(count: Signal) -> impl IntoView { view! { row(gap = 8.0) { button( on_press = { let count = count.clone(); move |_| { count.update(|value| *value -= 1); } }, ) { "-1" } button( on_press = { let count = count.clone(); move |_| { let _ = count.set(0); } }, ) { "Reset" } button( on_press = { let count = count.clone(); move |_| { count.update(|value| *value += 1); } }, ) { "+1" } } } }