/* * Copyright (C) 2025 Jonni Liljamo * * This file is licensed under MIT, see LICENSE for more information. */ use std::time::Duration; #[cfg(not(feature = "wasm"))] use std::time::Instant; #[cfg(feature = "wasm")] use web_time::Instant; use bevy::{color::palettes::tailwind::*, prelude::*}; pub struct ToastPlugin; impl Plugin for ToastPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, setup) .add_systems(Update, cleanup_toasts); app.add_event::() .add_observer(show_result_toast); } } #[derive(Component)] struct ToastUI; #[derive(Component)] struct Toast { spawned: Instant, } fn setup(mut commands: Commands) { commands.spawn(( Node { width: Val::Percent(100.0), height: Val::Percent(100.0), flex_direction: FlexDirection::Column, align_items: AlignItems::FlexEnd, padding: UiRect::all(Val::Px(8.0)), overflow: Overflow::scroll_y(), ..Default::default() }, ToastUI, )); } #[derive(Event)] pub struct ShowResultToast(pub u32, pub u8); fn show_result_toast( trigger: Trigger, mut commands: Commands, q_toast_ui: Query>, ) { if let Ok(toast_ui) = q_toast_ui.single() { let toast = commands .spawn(( Toast { spawned: Instant::now(), }, Node { width: Val::Px(180.0), height: Val::Px(60.0), border: UiRect::all(Val::Px(2.0)), flex_direction: FlexDirection::Column, justify_content: JustifyContent::Center, align_items: AlignItems::Center, ..Default::default() }, BackgroundColor(Color::from(EMERALD_400)), BorderColor(Color::from(EMERALD_700)), BorderRadius::all(Val::Px(10.0)), BoxShadow::new( Color::BLACK.with_alpha(0.8), Val::Px(4.0), Val::Px(4.0), Val::DEFAULT, Val::DEFAULT, ), children![ ( Text::new(format!("Die {}", trigger.0)), TextFont { font_size: 18.0, ..Default::default() }, TextColor(Color::BLACK), ), ( Text::new(format!("Result: {}", trigger.1)), TextFont { font_size: 20.0, ..Default::default() }, TextColor(Color::WHITE), ) ], )) .id(); commands.entity(toast_ui).add_child(toast); } } fn cleanup_toasts(mut commands: Commands, q_toast: Query<(Entity, &Toast)>) { for (entity, toast) in q_toast.iter() { if toast.spawned.elapsed() > Duration::from_secs(2) { commands.entity(entity).despawn(); } } }