- Updated SCSS for toast notifications to support multiple toast types (success, info, warning, error) and improved layout. - Added new SVG icons for error, info, success, and warning notifications. - Created separate HTML templates for toast notifications and modal dialogs. - Enhanced the dev panel with buttons to test different toast notifications and modal dialogs.
89 lines
2.6 KiB
Rust
89 lines
2.6 KiB
Rust
use gloo::{events::EventListener, timers::callback::Timeout};
|
|
use web_sys::{Element, HtmlElement, HtmlImageElement};
|
|
|
|
use crate::utils::{SelectorExt, by_id, selector_and_clone};
|
|
|
|
pub enum Level {
|
|
Success,
|
|
Error,
|
|
Info,
|
|
Warning,
|
|
Unknown,
|
|
}
|
|
|
|
const TIME_ANIMATION: u32 = 500; // [ms].
|
|
const TIME_DISPLAYED: u32 = 5_000; // [ms].
|
|
|
|
pub fn show_message(message: &str) {
|
|
show_message_level(Level::Unknown, message);
|
|
}
|
|
|
|
pub fn show_message_level(level: Level, message: &str) {
|
|
show_message_content(level, Content::Message(message))
|
|
}
|
|
|
|
pub fn show_element_level(level: Level, selector: &str) {
|
|
show_element_level_and_initialize(level, selector, |_| {})
|
|
}
|
|
|
|
pub fn show_element_level_and_initialize<T>(level: Level, selector: &str, initializer: T)
|
|
where
|
|
T: Fn(Element),
|
|
{
|
|
let content_element: Element = selector_and_clone(selector);
|
|
initializer(content_element.clone());
|
|
|
|
show_message_content(level, Content::Element(content_element))
|
|
}
|
|
|
|
enum Content<'a> {
|
|
Message(&'a str),
|
|
Element(Element),
|
|
}
|
|
|
|
fn show_message_content(level: Level, content: Content) {
|
|
let toast_element: HtmlElement = selector_and_clone("#toasts .toast");
|
|
|
|
let toast_icon: HtmlImageElement = toast_element.selector(".icon");
|
|
let toast_content: HtmlElement = toast_element.selector(".content");
|
|
|
|
match level {
|
|
Level::Success => toast_icon.set_src("/static/success.svg"),
|
|
Level::Error => toast_icon.set_src("/static/error.svg"),
|
|
Level::Info => toast_icon.set_src("/static/info.svg"),
|
|
Level::Warning => toast_icon.set_src("/static/warning.svg"),
|
|
Level::Unknown => toast_icon.remove(),
|
|
}
|
|
|
|
match content {
|
|
Content::Message(message) => toast_content.set_inner_html(message),
|
|
Content::Element(element) => {
|
|
let _ = toast_content.append_child(&element);
|
|
}
|
|
}
|
|
|
|
toast_element.style().set_css_text(&format!(
|
|
"display: block;
|
|
animation:
|
|
fadein {}ms,
|
|
fadeout {}ms {}ms;",
|
|
TIME_ANIMATION, TIME_ANIMATION, TIME_DISPLAYED
|
|
));
|
|
|
|
// FIXME: Here the two events will leak memory. How to fix that?
|
|
// Save them in a global vec variable and remove them manually?
|
|
let close_button: HtmlElement = toast_element.selector(".close");
|
|
let toast_element_cloned = toast_element.clone();
|
|
EventListener::once(&close_button, "click", move |_event| {
|
|
toast_element_cloned.remove();
|
|
})
|
|
.forget();
|
|
|
|
let toasts: HtmlElement = by_id("toasts");
|
|
toasts.append_child(&toast_element).unwrap();
|
|
|
|
Timeout::new(TIME_DISPLAYED, move || {
|
|
toast_element.remove();
|
|
})
|
|
.forget();
|
|
}
|