设计好消息通知关闭

This commit is contained in:
lsy 2025-01-01 23:56:37 +08:00
parent 1f885b54f3
commit 995a3262ed
10 changed files with 115 additions and 55 deletions

1
frontend/Cargo.lock generated
View File

@ -1477,6 +1477,7 @@ dependencies = [
"getrandom 0.2.15", "getrandom 0.2.15",
"js-sys", "js-sys",
"rand 0.8.5", "rand 0.8.5",
"tokio",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
] ]

View File

@ -14,6 +14,7 @@ web-sys = { version = "0.3.76", features = ["Window","Storage","MediaQueryList",
js-sys = "0.3.76" js-sys = "0.3.76"
rand = "0.8.5" rand = "0.8.5"
getrandom = { version = "0.2", features = ["js"] } getrandom = { version = "0.2", features = ["js"] }
tokio = "1.42.0"
[features] [features]
default = ["dioxus/web"] default = ["dioxus/web"]

View File

@ -598,10 +598,18 @@ video {
height: 0.25rem; height: 0.25rem;
} }
.h-full {
height: 100%;
}
.w-\[20rem\] { .w-\[20rem\] {
width: 20rem; width: 20rem;
} }
.w-full {
width: 100%;
}
.min-w-0 { .min-w-0 {
min-width: 0px; min-width: 0px;
} }
@ -610,20 +618,6 @@ video {
flex-shrink: 0; flex-shrink: 0;
} }
@keyframes progress {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
.animate-progress {
animation: 5s progress linear infinite;
}
.items-center { .items-center {
align-items: center; align-items: center;
} }
@ -655,9 +649,14 @@ video {
border-color: rgb(239 68 68 / var(--tw-border-opacity, 1)); border-color: rgb(239 68 68 / var(--tw-border-opacity, 1));
} }
.bg-white { .bg-blue-500 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1));
}
.bg-slate-400 {
--tw-bg-opacity: 1;
background-color: rgb(148 163 184 / var(--tw-bg-opacity, 1));
} }
.px-3 { .px-3 {
@ -670,18 +669,26 @@ video {
padding-bottom: 0.75rem; padding-bottom: 0.75rem;
} }
.text-gray-300 { .text-gray-800 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity, 1)); color: rgb(31 41 55 / var(--tw-text-opacity, 1));
}
.opacity-75 {
opacity: 0.75;
}
.filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
} }
.hover\:text-accent:hover { .hover\:text-accent:hover {
color: var(--accent-color); color: var(--accent-color);
} }
.dark\:text-gray-800:is(.dark *) { .dark\:text-gray-200:is(.dark *) {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(31 41 55 / var(--tw-text-opacity, 1)); color: rgb(229 231 235 / var(--tw-text-opacity, 1));
} }
@media not all and (min-width: 640px) { @media not all and (min-width: 640px) {

View File

@ -54,3 +54,9 @@ pub fn add_element_class(ele_name: &str, class_name: &str) -> CustomResult<()> {
pub fn remove_element_class(ele_name: &str, class_name: &str) -> CustomResult<()> { pub fn remove_element_class(ele_name: &str, class_name: &str) -> CustomResult<()> {
Ok(get_element(ele_name)?.class_list().remove_1(class_name)?) Ok(get_element(ele_name)?.class_list().remove_1(class_name)?)
} }
pub fn remove_element(ele_name: &str)-> CustomResult<()> {
let e=get_element(ele_name)?;
let _=e.parent_node().ok_or("无法获取父节点")?.remove_child(&e)?;
Ok(())
}

View File

@ -0,0 +1,5 @@
use tokio;
pub fn set_interval(time:u32,callback:fn()){
}

View File

@ -1,3 +1,4 @@
pub mod dom; pub mod dom;
pub mod error; pub mod error;
pub mod helps; pub mod helps;
pub mod hooks;

View File

@ -1,7 +1,7 @@
use crate::common::error::{CustomErrorInto, CustomResult}; use crate::common::error::{CustomErrorInto, CustomResult};
use crate::common::helps::generate_random_string; use crate::common::helps::generate_random_string;
use crate::Route; use crate::Route;
use dioxus::prelude::*; use dioxus::{logger::tracing, prelude::*};
use dioxus_free_icons::icons::bs_icons::{BsCheckCircle, BsInfoCircle, BsXCircle, BsXLg}; use dioxus_free_icons::icons::bs_icons::{BsCheckCircle, BsInfoCircle, BsXCircle, BsXLg};
use dioxus_free_icons::Icon; use dioxus_free_icons::Icon;
@ -19,16 +19,25 @@ pub enum NotificationType {
#[derive(PartialEq, Props, Clone)] #[derive(PartialEq, Props, Clone)]
pub struct NotificationProps { pub struct NotificationProps {
#[props(default="".to_string())] id: String,
title: String, title: String,
#[props(default="".to_string())]
content: String, content: String,
#[props(default = 5)]
time: u64, time: u64,
#[props(default=NotificationType::Info)]
r#type: NotificationType, r#type: NotificationType,
} }
impl Default for NotificationProps {
fn default() -> Self {
Self {
id: "".to_string(),
title: "".to_string(),
content: "".to_string(),
time: 5,
r#type: NotificationType::Info,
}
}
}
#[derive(PartialEq, Clone)] #[derive(PartialEq, Clone)]
struct NoticationColorMatching { struct NoticationColorMatching {
color: String, color: String,
@ -38,7 +47,7 @@ struct NoticationColorMatching {
fn get_color_matching(notification_type: &NotificationType) -> NoticationColorMatching { fn get_color_matching(notification_type: &NotificationType) -> NoticationColorMatching {
match notification_type { match notification_type {
NotificationType::Info => NoticationColorMatching { NotificationType::Info => NoticationColorMatching {
color: String::from("rgba(0,168,91,0.85)"), color: String::from("rgb(38,131,255)"),
icon: rsx! { icon: rsx! {
Icon { Icon {
icon: BsInfoCircle, icon: BsInfoCircle,
@ -48,7 +57,7 @@ fn get_color_matching(notification_type: &NotificationType) -> NoticationColorMa
}, },
}, },
NotificationType::Error => NoticationColorMatching { NotificationType::Error => NoticationColorMatching {
color: String::from("rgba(225,45,57,0.85)"), color: String::from("rgb(225,45,57)"),
icon: rsx! { icon: rsx! {
Icon { Icon {
icon: BsXCircle, icon: BsXCircle,
@ -58,7 +67,7 @@ fn get_color_matching(notification_type: &NotificationType) -> NoticationColorMa
}, },
}, },
NotificationType::Success => NoticationColorMatching { NotificationType::Success => NoticationColorMatching {
color: String::from("rgba(38,131,255,0.85)"), color: String::from("rgb(0,168,91)"),
icon: rsx! { icon: rsx! {
Icon { Icon {
icon: BsCheckCircle, icon: BsCheckCircle,
@ -70,26 +79,39 @@ fn get_color_matching(notification_type: &NotificationType) -> NoticationColorMa
} }
} }
pub fn remove_notification(id: String) {
let mut notifications_context = use_context::<Signal<NotificationProvider>>();
let new_notifications:Vec<NotificationProps> = notifications_context.clone()()
.notifications
.into_iter()
.filter(|i| i.id != id )
.collect();
notifications_context.set(NotificationProvider {
notifications: new_notifications,
});
}
#[component] #[component]
pub fn Notification() -> Element { pub fn Notification() -> Element {
let notifications = use_context::<Signal<NotificationProvider>>()().notifications; let notifications_context = use_context::<Signal<NotificationProvider>>();
let notifications = notifications_context().clone();
return rsx! { return rsx! {
div { div {
class: "w-[20rem] absolute right-8 top-10 max-sm:w-[12rem]", class: "w-[20rem] absolute right-8 top-10 max-sm:w-[12rem]",
{notifications.iter().map(|item| { {notifications.notifications.iter().map(move |item| {
let color_matching=get_color_matching(&item.r#type); let color_matching=get_color_matching(&item.r#type);
let id = item.id.clone();
rsx!{ rsx!{
div { div {
id:format!("notification-{}",generate_random_string(10)), id: id.clone(),
class:"rounded px-3 py-3 m-2 !border-none text-gray-300 dark:text-gray-800 ", class:"rounded px-3 py-3 m-2 !border-none text-gray-800 dark:text-gray-200 opacity-75 ",
style:format!("background-color:{}",color_matching.color), style:format!("background-color:{}",color_matching.color),
div { div {
div { div {
class:"flex items-center justify-between", class:"flex items-center justify-between",
div { div {
onclick:|e|{
},
class:"mr-2 relative top-[0.06rem] hover:text-accent", class:"mr-2 relative top-[0.06rem] hover:text-accent",
{color_matching.icon}, {color_matching.icon},
} }
@ -98,6 +120,10 @@ pub fn Notification() -> Element {
{item.title.clone()} {item.title.clone()}
} }
div { div {
onclick:move |e|{
e.prevent_default();
remove_notification(id.clone());
},
class:"ml-1 flex-shrink-0", class:"ml-1 flex-shrink-0",
Icon{ Icon{
icon:BsXLg, icon:BsXLg,
@ -106,9 +132,15 @@ pub fn Notification() -> Element {
} }
} }
} }
div { div {
class:"mt-2 h-1 bg-white animate-progress", class:"mt-2 h-1 relative",
style: format!("animation-duration: {}s", item.time), div {
class:"absolute bg-slate-400 w-full h-full",
}
div {
class:"absolute w-full h-full ",
style:"width:80%"
}
} }
} }
} }
@ -125,30 +157,35 @@ impl Toast {
pub fn show(props: NotificationProps) { pub fn show(props: NotificationProps) {
let mut notification_context = use_context::<Signal<NotificationProvider>>(); let mut notification_context = use_context::<Signal<NotificationProvider>>();
let mut new_provider = notification_context().clone(); let mut new_provider = notification_context().clone();
new_provider.notifications.push(props); let mut new_props = props;
new_props.id = format!("notification-{}",generate_random_string(10));
new_provider.notifications.push(new_props);
notification_context.set(new_provider); notification_context.set(new_provider);
} }
pub fn info(title: String, content: String) { pub fn info(title: String, content: String) {
Self::show(NotificationProps { Self::show(NotificationProps {
id: Default::default(),
title, title,
content, content,
time: 5, time: Default::default(),
r#type: NotificationType::Info, r#type: NotificationType::Info,
}); });
} }
pub fn error(title: String, content: String) { pub fn error(title: String, content: String) {
Self::show(NotificationProps { Self::show(NotificationProps {
id: Default::default(),
title, title,
content, content,
time: 5, time: Default::default(),
r#type: NotificationType::Error, r#type: NotificationType::Error,
}); });
} }
pub fn success(title: String, content: String) { pub fn success(title: String, content: String) {
Self::show(NotificationProps { Self::show(NotificationProps {
id: Default::default(),
title, title,
content, content,
time: 5, time: Default::default(),
r#type: NotificationType::Success, r#type: NotificationType::Success,
}); });
} }

View File

@ -4,7 +4,6 @@ mod common;
use common::dom::{add_element_class, get_media_theme, remove_element_class}; use common::dom::{add_element_class, get_media_theme, remove_element_class};
use components::notification::{Notification, NotificationProvider}; use components::notification::{Notification, NotificationProvider};
use components::theme_toggle::{get_theme, ThemeProvider}; use components::theme_toggle::{get_theme, ThemeProvider};
use components::Navbar; use components::Navbar;
use views::Home; use views::Home;

View File

@ -14,8 +14,22 @@ pub fn Home() -> Element {
onclick: move |_| { onclick: move |_| {
Toast::info("我是标sasadc我想二次TV要不以后牛魔题".to_string(), "我是内容".to_string()) Toast::info("我是标sasadc我想二次TV要不以后牛魔题".to_string(), "我是内容".to_string())
}, },
"Show Notification" "info "
} }
button {
onclick: move |_| {
Toast::error("我是标sasadc我想二次TV要不以后牛魔题".to_string(), "我是内容".to_string())
},
"error "
}
button {
onclick: move |_| {
Toast::success("我是标sasadc我想二次TV要不以后牛魔题".to_string(), "我是内容".to_string())
},
"success"
}
} }
} }
} }

View File

@ -7,17 +7,6 @@ module.exports = {
colors: { colors: {
accent: 'var(--accent-color)', accent: 'var(--accent-color)',
}, },
animation:{
progress:"5s progress linear infinite"
},
keyframes:{
progress:{
'0%':{width:'0%'},
'100%':{width:'100%'}
}
}
}, },
}, },
plugins: [], plugins: [],