use dioxus::prelude::*;
#[derive(Clone, Debug, PartialEq)]
pub enum EffectType {
Confetti,
Fireworks,
Snow,
Hearts,
Rainbow,
Rainfall,
SpaceInvaders,
}
#[component]
pub fn MessageEffectsOverlay(effect: Option<EffectType>, on_complete: EventHandler<()>) -> Element {
let mut visible = use_signal(|| false);
let mut effect_sig = use_signal(|| effect.clone());
if *effect_sig.read() != effect {
effect_sig.set(effect.clone());
if effect.is_some() {
visible.set(true);
spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
visible.set(false);
on_complete.call(());
});
}
}
if !*visible.read() || effect.is_none() {
return rsx! {};
}
let effect = effect.unwrap();
let (class, particles) = match effect {
EffectType::Confetti => ("message-effects message-effects--confetti", generate_confetti()),
EffectType::Fireworks => ("message-effects message-effects--fireworks", generate_fireworks()),
EffectType::Snow => ("message-effects message-effects--snow", generate_snow()),
EffectType::Hearts => ("message-effects message-effects--hearts", generate_hearts()),
EffectType::Rainbow => ("message-effects message-effects--rainbow", vec![]),
EffectType::Rainfall => ("message-effects message-effects--rainfall", generate_rainfall()),
EffectType::SpaceInvaders => ("message-effects message-effects--spaceinvaders", generate_space_invaders()),
};
rsx! {
div {
class: class,
onclick: move |_| {
visible.set(false);
on_complete.call(());
},
for particle in particles.iter() {
{
let p = particle.clone();
rsx! {
span {
class: "message-effects__particle",
style: "left: {p.x}%; animation-delay: {p.delay}s; font-size: {p.size}px;",
"{p.char}"
}
}
}
}
}
}
}
#[derive(Clone)]
struct Particle {
char: String,
x: f32,
delay: f32,
size: u32,
}
fn generate_confetti() -> Vec<Particle> {
let colors = ["🟥", "🟧", "🟨", "🟩", "🟦", "🟪", "⬜"];
(0..30)
.map(|i| Particle {
char: colors[i % colors.len()].to_string(),
x: (i as f32 * 3.33) % 100.0,
delay: (i as f32 * 0.1) % 2.0,
size: 16 + (i % 3) as u32 * 4,
})
.collect()
}
fn generate_fireworks() -> Vec<Particle> {
let sparks = ["✨", "💥", "🎆", "⭐", "🌟"];
(0..20)
.map(|i| Particle {
char: sparks[i % sparks.len()].to_string(),
x: (i as f32 * 5.0) % 100.0,
delay: (i as f32 * 0.15) % 2.0,
size: 20 + (i % 4) as u32 * 6,
})
.collect()
}
fn generate_snow() -> Vec<Particle> {
(0..40)
.map(|i| Particle {
char: if i % 3 == 0 { "❄" } else { "❅" }.to_string(),
x: (i as f32 * 2.5) % 100.0,
delay: (i as f32 * 0.2) % 3.0,
size: 14 + (i % 4) as u32 * 4,
})
.collect()
}
fn generate_hearts() -> Vec<Particle> {
let hearts = ["❤️", "💕", "💖", "💗", "💓"];
(0..25)
.map(|i| Particle {
char: hearts[i % hearts.len()].to_string(),
x: (i as f32 * 4.0) % 100.0,
delay: (i as f32 * 0.12) % 2.0,
size: 18 + (i % 3) as u32 * 6,
})
.collect()
}
fn generate_rainfall() -> Vec<Particle> {
let drops = ["💧", "🌧", "💦"];
(0..35)
.map(|i| Particle {
char: drops[i % drops.len()].to_string(),
x: (i as f32 * 2.86) % 100.0,
delay: (i as f32 * 0.08) % 2.5,
size: 14 + (i % 3) as u32 * 4,
})
.collect()
}
fn generate_space_invaders() -> Vec<Particle> {
let aliens = ["👾", "🛸", "🚀", "⭐", "💫"];
(0..25)
.map(|i| Particle {
char: aliens[i % aliens.len()].to_string(),
x: (i as f32 * 4.0) % 100.0,
delay: (i as f32 * 0.12) % 2.0,
size: 18 + (i % 4) as u32 * 5,
})
.collect()
}