设计好消息通知关闭
This commit is contained in:
parent
1f885b54f3
commit
995a3262ed
1
frontend/Cargo.lock
generated
1
frontend/Cargo.lock
generated
@ -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",
|
||||||
]
|
]
|
||||||
|
@ -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"]
|
||||||
|
@ -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) {
|
||||||
|
@ -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(())
|
||||||
|
}
|
5
frontend/src/common/hooks.rs
Normal file
5
frontend/src/common/hooks.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
use tokio;
|
||||||
|
|
||||||
|
pub fn set_interval(time:u32,callback:fn()){
|
||||||
|
|
||||||
|
}
|
@ -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;
|
@ -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,
|
||||||
@ -107,8 +133,14 @@ 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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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: [],
|
||||||
|
Loading…
Reference in New Issue
Block a user