完善弹窗样式,完善主题更改,如果储存主题和当前主题相同就不储存主题使用默认主题
This commit is contained in:
parent
e52c49a346
commit
1f885b54f3
5
frontend/Cargo.lock
generated
5
frontend/Cargo.lock
generated
@ -1474,6 +1474,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"dioxus",
|
||||
"dioxus-free-icons",
|
||||
"getrandom 0.2.15",
|
||||
"js-sys",
|
||||
"rand 0.8.5",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
@ -1736,8 +1739,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -10,7 +10,10 @@ edition = "2021"
|
||||
dioxus = { version = "0.6.0", features = ["router"] }
|
||||
dioxus-free-icons = { version = "0.9", features = ["bootstrap"] }
|
||||
wasm-bindgen = "0.2.99"
|
||||
web-sys = { version = "0.3.76", features = ["Window","Storage","MediaQueryList","Document"] }
|
||||
web-sys = { version = "0.3.76", features = ["Window","Storage","MediaQueryList","Document","DomTokenList","Element","MediaQueryListEvent"] }
|
||||
js-sys = "0.3.76"
|
||||
rand = "0.8.5"
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
|
||||
[features]
|
||||
default = ["dioxus/web"]
|
||||
|
@ -1,11 +1,18 @@
|
||||
.light{
|
||||
--accent-color:#3F51B5;
|
||||
}
|
||||
.light .box{
|
||||
background:
|
||||
color:black;
|
||||
}
|
||||
|
||||
.dark{
|
||||
--accent-color:#4d648d;
|
||||
color:white;
|
||||
}
|
||||
|
||||
html.dark{
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
html.light{
|
||||
background-color:white;
|
||||
}
|
||||
|
||||
|
@ -562,30 +562,76 @@ video {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.right-1 {
|
||||
right: 0.25rem;
|
||||
}
|
||||
|
||||
.right-8 {
|
||||
right: 2rem;
|
||||
}
|
||||
|
||||
.top-1 {
|
||||
top: 0.25rem;
|
||||
}
|
||||
|
||||
.top-10 {
|
||||
top: 2.5rem;
|
||||
}
|
||||
|
||||
.float-end {
|
||||
float: inline-end;
|
||||
.top-\[0\.06rem\] {
|
||||
top: 0.06rem;
|
||||
}
|
||||
|
||||
.m-2 {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-1 {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.h-1 {
|
||||
height: 0.25rem;
|
||||
}
|
||||
|
||||
.w-\[20rem\] {
|
||||
width: 20rem;
|
||||
}
|
||||
|
||||
.min-w-0 {
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.flex-shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@keyframes progress {
|
||||
0% {
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-progress {
|
||||
animation: 5s progress linear infinite;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@ -596,18 +642,27 @@ video {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.border-accent {
|
||||
border-color: var(--accent-color);
|
||||
.border-2 {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.bg-yellow-200 {
|
||||
.\!border-none {
|
||||
border-style: none !important;
|
||||
}
|
||||
|
||||
.border-red-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(239 68 68 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(254 240 138 / var(--tw-bg-opacity, 1));
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.px-2 {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
.px-3 {
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
}
|
||||
|
||||
.py-3 {
|
||||
@ -615,29 +670,18 @@ video {
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.text-base {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
.text-gray-300 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(209 213 219 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
.hover\:text-accent:hover {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.backdrop-blur-xl {
|
||||
--tw-backdrop-blur: blur(24px);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
||||
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
||||
}
|
||||
|
||||
.hover\:border-2:hover {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.dark\:bg-sky-500:is(.dark *) {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(14 165 233 / var(--tw-bg-opacity, 1));
|
||||
.dark\:text-gray-800:is(.dark *) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(31 41 55 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
@media not all and (min-width: 640px) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::error::{CustomErrorInto, CustomResult};
|
||||
use web_sys::{window, Document, MediaQueryList, Storage, Window};
|
||||
use web_sys::{window, Document, Element, Storage, Window};
|
||||
|
||||
fn get_window() -> CustomResult<Window> {
|
||||
Ok(window().ok_or("浏览器window对象不存在")?)
|
||||
@ -8,7 +8,18 @@ fn get_window() -> CustomResult<Window> {
|
||||
fn get_storage() -> CustomResult<Storage> {
|
||||
get_window()?
|
||||
.local_storage()?
|
||||
.ok_or("浏览器不支持localStorage".into_custom_error())
|
||||
.ok_or("获取浏览器Storge对象失败".into_custom_error())
|
||||
}
|
||||
fn get_document() -> CustomResult<Document> {
|
||||
get_window()?
|
||||
.document()
|
||||
.ok_or("获取浏览器Document对象失败".into_custom_error())
|
||||
}
|
||||
|
||||
fn get_element(ele_name: &str) -> CustomResult<Element> {
|
||||
get_document()?
|
||||
.query_selector(ele_name)?
|
||||
.ok_or(format!("获取元素{}失败", ele_name).into_custom_error())
|
||||
}
|
||||
|
||||
pub fn get_local_storage_value(key: &str) -> CustomResult<String> {
|
||||
@ -21,6 +32,10 @@ pub fn set_local_storage_value(key: &str, value: &str) -> CustomResult<()> {
|
||||
Ok(get_storage()?.set_item(key, value)?)
|
||||
}
|
||||
|
||||
pub fn remove_local_storage_value(key: &str) -> CustomResult<()> {
|
||||
Ok(get_storage()?.remove_item(key)?)
|
||||
}
|
||||
|
||||
pub fn get_media_theme() -> CustomResult<String> {
|
||||
let media_query = get_window()?
|
||||
.match_media("(prefers-color-scheme: dark)")?
|
||||
@ -32,13 +47,10 @@ pub fn get_media_theme() -> CustomResult<String> {
|
||||
Ok("light".to_string())
|
||||
}
|
||||
|
||||
pub fn set_element_class(ele_name: &str, class_name: &str) -> CustomResult<()> {
|
||||
get_window()?
|
||||
.document()
|
||||
.ok_or("浏览器document对象不存在".into_custom_error())?
|
||||
.query_selector(ele_name)?
|
||||
.ok_or(format!("获取元素{}失败", ele_name).into_custom_error())?
|
||||
.set_class_name(class_name);
|
||||
|
||||
Ok(())
|
||||
pub fn add_element_class(ele_name: &str, class_name: &str) -> CustomResult<()> {
|
||||
Ok(get_element(ele_name)?.class_list().add_1(class_name)?)
|
||||
}
|
||||
|
||||
pub fn remove_element_class(ele_name: &str, class_name: &str) -> CustomResult<()> {
|
||||
Ok(get_element(ele_name)?.class_list().remove_1(class_name)?)
|
||||
}
|
||||
|
9
frontend/src/common/helps.rs
Normal file
9
frontend/src/common/helps.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
pub fn generate_random_string(length: usize) -> String {
|
||||
let charset = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let mut rng = rand::thread_rng();
|
||||
(0..length)
|
||||
.map(|_| *charset.choose(&mut rng).unwrap() as char)
|
||||
.collect()
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub mod dom;
|
||||
pub mod error;
|
||||
pub mod helps;
|
||||
|
@ -3,4 +3,4 @@ pub use navbar::Navbar;
|
||||
pub mod theme_toggle;
|
||||
pub use theme_toggle::Toggle;
|
||||
pub mod notification;
|
||||
pub use notification::Message;
|
||||
pub use notification::Toast;
|
||||
|
@ -1,55 +1,155 @@
|
||||
use crate::common::error::{CustomErrorInto, CustomResult};
|
||||
use crate::common::helps::generate_random_string;
|
||||
use crate::Route;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_free_icons::icons::bs_icons::{BsCheckCircle, BsInfoCircle, BsXCircle, BsXLg};
|
||||
use dioxus_free_icons::Icon;
|
||||
use dioxus_free_icons::icons::bs_icons::BsXLg;
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub enum MessageType {
|
||||
pub struct NotificationProvider {
|
||||
pub notifications: Vec<NotificationProps>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub enum NotificationType {
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props, Clone)]
|
||||
pub struct MessageProps {
|
||||
#[props(default="wight".to_string())]
|
||||
color: String,
|
||||
pub struct NotificationProps {
|
||||
#[props(default="".to_string())]
|
||||
title: String,
|
||||
#[props(default="".to_string())]
|
||||
message: String,
|
||||
#[props(default=3)]
|
||||
time:u64,
|
||||
content: String,
|
||||
#[props(default = 5)]
|
||||
time: u64,
|
||||
#[props(default=NotificationType::Info)]
|
||||
r#type: NotificationType,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
struct NoticationColorMatching {
|
||||
color: String,
|
||||
icon: Element,
|
||||
}
|
||||
|
||||
fn get_color_matching(notification_type: &NotificationType) -> NoticationColorMatching {
|
||||
match notification_type {
|
||||
NotificationType::Info => NoticationColorMatching {
|
||||
color: String::from("rgba(0,168,91,0.85)"),
|
||||
icon: rsx! {
|
||||
Icon {
|
||||
icon: BsInfoCircle,
|
||||
width:18,
|
||||
height:18,
|
||||
}
|
||||
},
|
||||
},
|
||||
NotificationType::Error => NoticationColorMatching {
|
||||
color: String::from("rgba(225,45,57,0.85)"),
|
||||
icon: rsx! {
|
||||
Icon {
|
||||
icon: BsXCircle,
|
||||
width:18,
|
||||
height:18,
|
||||
}
|
||||
},
|
||||
},
|
||||
NotificationType::Success => NoticationColorMatching {
|
||||
color: String::from("rgba(38,131,255,0.85)"),
|
||||
icon: rsx! {
|
||||
Icon {
|
||||
icon: BsCheckCircle,
|
||||
width:18,
|
||||
height:18,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn Message(props: MessageProps) -> Element {
|
||||
pub fn Notification() -> Element {
|
||||
let notifications = use_context::<Signal<NotificationProvider>>()().notifications;
|
||||
return rsx! {
|
||||
div {
|
||||
class: "w-[20rem] px-2 py-3 absolute right-8 top-10 backdrop-blur-xl max-sm:w-[12rem] hover:border-2 border-accent rounded ",
|
||||
style: "background-color:{props.color}",
|
||||
class: "w-[20rem] absolute right-8 top-10 max-sm:w-[12rem]",
|
||||
{notifications.iter().map(|item| {
|
||||
let color_matching=get_color_matching(&item.r#type);
|
||||
rsx!{
|
||||
div {
|
||||
id:format!("notification-{}",generate_random_string(10)),
|
||||
class:"rounded px-3 py-3 m-2 !border-none text-gray-300 dark:text-gray-800 ",
|
||||
style:format!("background-color:{}",color_matching.color),
|
||||
div {
|
||||
div {
|
||||
class:"flex items-center justify-between",
|
||||
div {
|
||||
onclick:|e|{
|
||||
|
||||
div {
|
||||
|
||||
class:"text-lg",
|
||||
div {
|
||||
class:"float-end relative top-1 right-1",
|
||||
Icon{
|
||||
icon:BsXLg,
|
||||
},
|
||||
class:"mr-2 relative top-[0.06rem] hover:text-accent",
|
||||
{color_matching.icon},
|
||||
}
|
||||
div {
|
||||
class:"truncate min-w-0",
|
||||
{item.title.clone()}
|
||||
}
|
||||
div {
|
||||
class:"ml-1 flex-shrink-0",
|
||||
Icon{
|
||||
icon:BsXLg,
|
||||
height:18,
|
||||
width:18
|
||||
}
|
||||
}
|
||||
}
|
||||
div {
|
||||
class:"mt-2 h-1 bg-white animate-progress",
|
||||
style: format!("animation-duration: {}s", item.time),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div {
|
||||
class:"truncate",
|
||||
"我是标题水水水水水水水水水水水水水水水水水水水水水sssssssssssss水水水ssssssssssssssss"
|
||||
|
||||
}
|
||||
}
|
||||
div {
|
||||
class:"text-base",
|
||||
"我是水水水水水水水水水ssssssssssssssssssssss水水水水内容"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
})}
|
||||
}
|
||||
Outlet::<Route> {}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Toast();
|
||||
|
||||
impl Toast {
|
||||
pub fn show(props: NotificationProps) {
|
||||
let mut notification_context = use_context::<Signal<NotificationProvider>>();
|
||||
let mut new_provider = notification_context().clone();
|
||||
new_provider.notifications.push(props);
|
||||
notification_context.set(new_provider);
|
||||
}
|
||||
pub fn info(title: String, content: String) {
|
||||
Self::show(NotificationProps {
|
||||
title,
|
||||
content,
|
||||
time: 5,
|
||||
r#type: NotificationType::Info,
|
||||
});
|
||||
}
|
||||
pub fn error(title: String, content: String) {
|
||||
Self::show(NotificationProps {
|
||||
title,
|
||||
content,
|
||||
time: 5,
|
||||
r#type: NotificationType::Error,
|
||||
});
|
||||
}
|
||||
pub fn success(title: String, content: String) {
|
||||
Self::show(NotificationProps {
|
||||
title,
|
||||
content,
|
||||
time: 5,
|
||||
r#type: NotificationType::Success,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
use crate::common::dom::{set_element_class, set_local_storage_value};
|
||||
use crate::common::dom::{
|
||||
add_element_class, get_local_storage_value, get_media_theme, remove_element_class,
|
||||
remove_local_storage_value, set_local_storage_value,
|
||||
};
|
||||
use dioxus::{logger::tracing, prelude::*};
|
||||
use dioxus_free_icons::icons::bs_icons::BsMoonStars;
|
||||
use dioxus_free_icons::icons::bs_icons::BsSun;
|
||||
use dioxus_free_icons::Icon;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct IsDark(pub String);
|
||||
pub struct ThemeProvider(pub String);
|
||||
|
||||
#[derive(PartialEq, Props, Clone)]
|
||||
pub struct ToggleProps {
|
||||
@ -18,37 +22,34 @@ pub struct ToggleProps {
|
||||
|
||||
#[component]
|
||||
pub fn Toggle(props: ToggleProps) -> Element {
|
||||
let mut dark_context = use_context::<Signal<IsDark>>();
|
||||
let mut theme_context = use_context::<Signal<ThemeProvider>>();
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
onclick: move |_|
|
||||
{
|
||||
let theme;
|
||||
if dark_context().0=="light" {
|
||||
theme="dark"
|
||||
let system_theme=get_media_theme().unwrap_or_else(|_|"".to_string());
|
||||
let target_theme;
|
||||
|
||||
if theme_context().0=="light" {
|
||||
target_theme="dark".to_string()
|
||||
}else {
|
||||
theme="light"
|
||||
target_theme="light".to_string()
|
||||
};
|
||||
|
||||
dark_context.set(IsDark(theme.to_string()));
|
||||
match set_local_storage_value("theme",theme) {
|
||||
Ok(_)=>{},
|
||||
Err(_)=>{
|
||||
tracing::error!("主题储存失败");
|
||||
},
|
||||
let _=remove_element_class("html", &theme_context().0);
|
||||
theme_context.set(ThemeProvider(target_theme.clone()));
|
||||
let _=add_element_class("html", &target_theme);
|
||||
if target_theme==system_theme {
|
||||
let _=remove_local_storage_value("theme");
|
||||
}else{
|
||||
let _=set_local_storage_value("theme", &target_theme);
|
||||
}
|
||||
match set_element_class("html",theme) {
|
||||
Ok(_)=>{},
|
||||
Err(e)=>{
|
||||
tracing::error!("主题类名设置失败:{}",e);
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
match {dark_context().0.as_str()} {
|
||||
match {theme_context().0.as_str()} {
|
||||
"dark"=>{
|
||||
rsx!(
|
||||
Icon{
|
||||
@ -78,3 +79,17 @@ pub fn Toggle(props: ToggleProps) -> Element {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_theme() -> String {
|
||||
let storage_theme = get_local_storage_value("theme");
|
||||
match storage_theme {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
let device_theme = get_media_theme();
|
||||
match device_theme {
|
||||
Ok(s) => s,
|
||||
Err(_) => "light".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
use dioxus::{logger::tracing, prelude::*};
|
||||
use wasm_bindgen::prelude::*;
|
||||
mod common;
|
||||
use common::dom::{get_local_storage_value, get_media_theme, set_element_class};
|
||||
use components::theme_toggle::IsDark;
|
||||
use common::dom::{add_element_class, get_media_theme, remove_element_class};
|
||||
use components::notification::{Notification, NotificationProvider};
|
||||
use components::theme_toggle::{get_theme, ThemeProvider};
|
||||
|
||||
use components::Navbar;
|
||||
use views::Home;
|
||||
@ -10,12 +12,11 @@ mod components;
|
||||
mod views;
|
||||
|
||||
#[derive(Debug, Clone, Routable, PartialEq)]
|
||||
#[rustfmt::skip]
|
||||
enum Route {
|
||||
#[layout(Notification)]
|
||||
#[layout(Navbar)]
|
||||
#[route("/")]
|
||||
Home {},
|
||||
|
||||
}
|
||||
|
||||
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
||||
@ -28,25 +29,32 @@ fn main() {
|
||||
|
||||
#[component]
|
||||
fn App() -> Element {
|
||||
use_context_provider(|| Signal::new(IsDark("light".to_string())));
|
||||
let mut is_dark_context = use_context::<Signal<IsDark>>();
|
||||
let theme = get_theme();
|
||||
use_context_provider(|| Signal::new(ThemeProvider(theme.clone())));
|
||||
use_context_provider(|| {
|
||||
Signal::new(NotificationProvider {
|
||||
notifications: Vec::new(),
|
||||
})
|
||||
});
|
||||
let mut is_dark_context = use_context::<Signal<ThemeProvider>>();
|
||||
|
||||
use_effect(move || {
|
||||
let theme = {
|
||||
let storage_theme = get_local_storage_value("theme");
|
||||
match storage_theme {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
let device_theme = get_media_theme();
|
||||
match device_theme {
|
||||
Ok(s) => s,
|
||||
Err(_) => "light".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
is_dark_context.set(IsDark(theme.clone()));
|
||||
let _ = set_element_class("html", &theme);
|
||||
let _ = add_element_class("html", &theme);
|
||||
let window = web_sys::window().unwrap();
|
||||
let media_query = window
|
||||
.match_media("(prefers-color-scheme: dark)")
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let closure = Closure::wrap(Box::new(move |_: web_sys::MediaQueryListEvent| {
|
||||
let theme = get_media_theme().unwrap_or_else(|_| "light".to_string());
|
||||
let _ = remove_element_class("html", &is_dark_context().0);
|
||||
let _ = add_element_class("html", &theme);
|
||||
is_dark_context.set(ThemeProvider(theme));
|
||||
}) as Box<dyn FnMut(_)>);
|
||||
media_query
|
||||
.add_event_listener_with_callback("change", closure.as_ref().unchecked_ref())
|
||||
.unwrap();
|
||||
closure.forget();
|
||||
});
|
||||
|
||||
rsx! {
|
||||
|
@ -1,16 +1,21 @@
|
||||
use crate::components::Toast;
|
||||
use dioxus::prelude::*;
|
||||
use crate::components::Message;
|
||||
|
||||
#[component]
|
||||
pub fn Home() -> Element {
|
||||
rsx! {
|
||||
Message{},
|
||||
div {
|
||||
class:"bg-yellow-200 dark:bg-sky-500",
|
||||
class:"border-2 border-red-500",
|
||||
"hello,world"
|
||||
ul {
|
||||
li { "nihao" }
|
||||
}
|
||||
}
|
||||
button {
|
||||
onclick: move |_| {
|
||||
Toast::info("我是标sasadc我想二次TV要不以后牛魔题".to_string(), "我是内容".to_string())
|
||||
},
|
||||
"Show Notification"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,17 @@ module.exports = {
|
||||
colors: {
|
||||
accent: 'var(--accent-color)',
|
||||
},
|
||||
animation:{
|
||||
progress:"5s progress linear infinite"
|
||||
|
||||
},
|
||||
keyframes:{
|
||||
progress:{
|
||||
'0%':{width:'0%'},
|
||||
'100%':{width:'100%'}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
|
Loading…
Reference in New Issue
Block a user