use gloo_timers::future::TimeoutFuture; use log::debug; use sycamore::{futures::spawn_local_scoped, prelude::*}; use wasm_bindgen_futures::spawn_local; const MESSAGE_TIME: u32 = 5000; #[derive(Debug, Clone, PartialEq, Default)] pub struct Message { id: usize, title: String, text: String, } impl Message { pub fn new(title: String, text: String) -> Self { Self { id: 0, title, text } } } #[derive(Debug, Clone, PartialEq, Default)] pub struct Messenger { counter: RcSignal, messages: RcSignal>, } impl Messenger { pub fn add_message(&self, mut message: Message) { message.id = *self.counter.get_untracked(); self.counter.set(*self.counter.get_untracked() + 1); self.messages.modify().push(message); } pub fn info(&self, title: impl Into, text: impl Into) { self.add_message(Message::new(title.into(), text.into())); } pub fn add_result( &self, result: anyhow::Result, success: Option>, fail: Option>, ) { match result { Ok(_) => { if let Some(success) = success { self.add_message(Message::new(success.into(), String::new())) } } Err(e) => { if let Some(fail) = fail { self.add_message(Message::new(fail.into(), e.to_string())) } } } } pub fn remove_message(&self) { self.messages.modify().remove(0); } pub fn len(&self) -> usize { self.messages.get_untracked().len() } } #[component] pub fn Messages<'a, G: Html>(cx: Scope<'a>) -> View { let messages = use_context::(cx); create_effect(cx, move || { messages.messages.track(); if messages.len() > 0 { spawn_local_scoped(cx, async move { debug!("Spawn"); TimeoutFuture::new(MESSAGE_TIME).await; debug!("Remove"); messages.remove_message(); }); } }); view! { cx, div(class="messages") { Keyed( iterable=&messages.messages, view=move |cx, message| { view! { cx, div(class="message") { p(class="message-title") { (message.title) } p(class="message-text") { (message.text) } } } }, key=|message| (message.id), ) } } }