diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1fcba49..7012fe3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -35,7 +35,7 @@ "type": "shell", "command": "serve .", "options": { - "cwd": "${workspaceFolder}/client/target/dx/client/release/web/public" + "cwd": "${workspaceFolder}/target/dx/client/release/web/public" }, "problemMatcher": [] }, diff --git a/Cargo.lock b/Cargo.lock index 598dae4..4294367 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3632,6 +3632,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "rocket_cors" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfac3a1df83f8d4fc96aa41dba3b86c786417b7fc0f52ec76295df2ba781aa69" +dependencies = [ + "http 0.2.12", + "log", + "regex", + "rocket", + "serde", + "serde_derive", + "unicase", + "unicase_serde", + "url", +] + [[package]] name = "rocket_http" version = "0.5.1" @@ -3988,6 +4005,7 @@ version = "0.1.0" dependencies = [ "common", "rocket", + "rocket_cors", "serde", "surrealdb", "tokio", @@ -4984,6 +5002,16 @@ version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +[[package]] +name = "unicase_serde" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef53697679d874d69f3160af80bc28de12730a985d57bdf2b47456ccb8b11f1" +dependencies = [ + "serde", + "unicase", +] + [[package]] name = "unicode-ident" version = "1.0.14" diff --git a/Cargo.toml b/Cargo.toml index 144e70d..3b255de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ rocket = "0.5.0" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.0", features = ["full"] } surrealdb = "2.1.4" +rocket_cors = "0.6.0" [profile] diff --git a/client/assets/fonts/AlimamaFangYuanTiVF.ttf b/client/assets/fonts/AlimamaFangYuanTiVF.ttf deleted file mode 100644 index d7dc773..0000000 Binary files a/client/assets/fonts/AlimamaFangYuanTiVF.ttf and /dev/null differ diff --git a/client/assets/fonts/OperatorMonoLig.otf b/client/assets/fonts/OperatorMonoLig.otf deleted file mode 100644 index 5573d91..0000000 Binary files a/client/assets/fonts/OperatorMonoLig.otf and /dev/null differ diff --git a/client/assets/styling/global.css b/client/assets/styling/global.css index 87b9955..ece6f0d 100644 --- a/client/assets/styling/global.css +++ b/client/assets/styling/global.css @@ -10,14 +10,9 @@ html[data-theme="dark"]{ background-color:black; } -@font-face { - font-family: 'AlimamaTi'; - src: url('/assets/fonts/AlimamaFangYuanTiVF.ttf') format('truetype'); - font-display: swap; - font-weight: 500; -} html { overflow-x:hidden; - font-family: 'AlimamaTi', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + font-weight: 500; + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } diff --git a/client/assets/styling/tailwind.css b/client/assets/styling/tailwind.css index 3bfa425..cb7be54 100644 --- a/client/assets/styling/tailwind.css +++ b/client/assets/styling/tailwind.css @@ -586,10 +586,6 @@ video { top: 0px; } -.top-5 { - top: 1.25rem; -} - .top-\[0\.06rem\] { top: 0.06rem; } @@ -631,10 +627,6 @@ video { display: grid; } -.hidden { - display: none; -} - .h-1 { height: 0.25rem; } @@ -667,14 +659,14 @@ video { min-width: 0px; } -.min-w-7 { - min-width: 1.75rem; -} - .flex-shrink-0 { flex-shrink: 0; } +.transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + @keyframes slide-in { 0% { transform: translateX(100%); @@ -727,8 +719,8 @@ video { gap: 0.25rem; } -.gap-10 { - gap: 2.5rem; +.gap-5 { + gap: 1.25rem; } .justify-self-start { @@ -739,12 +731,20 @@ video { justify-self: end; } +.overflow-hidden { + overflow: hidden; +} + .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.whitespace-nowrap { + white-space: nowrap; +} + .rounded { border-radius: 0.25rem; } @@ -832,8 +832,9 @@ video { background-color: rgb(148 163 184 / var(--tw-bg-opacity, 1)); } -.p-2 { - padding: 0.5rem; +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; } .px-3 { @@ -906,6 +907,10 @@ video { transition-duration: 150ms; } +.duration-150 { + transition-duration: 150ms; +} + .duration-200 { transition-duration: 200ms; } diff --git a/client/src/components/navbar.rs b/client/src/components/navbar.rs index a8bfd34..f14d73b 100644 --- a/client/src/components/navbar.rs +++ b/client/src/components/navbar.rs @@ -1,43 +1,46 @@ use super::Toggle; +use crate::DeviceProvider; use crate::Route; use dioxus::{logger::tracing, prelude::*}; +use global_attributes::dangerous_inner_html; use wasm_bindgen::{prelude::Closure, JsCast}; +use web_sys::Event; #[component] pub fn Navbar() -> Element { let mut progress_signal = use_signal(|| 0); let mut progress_hover = use_signal(|| false); - - // 监听滚动事件 + let mut is_more_single = use_signal(|| false); + let mut device_context = use_context::>(); use_effect(move || { let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let document_element = document.document_element().unwrap(); - - let closure: Closure = { - Closure::wrap(Box::new(move |_: web_sys::Event| { - let screen_height = document_element.scroll_height() as f64; - let inner_height = window.inner_height().unwrap().as_f64().unwrap(); - let scrool_height = window.scroll_y().unwrap(); - let max_scroll_height = screen_height - inner_height; - let percent = if max_scroll_height > 0.0 { - scrool_height / max_scroll_height - } else { - 0.0 - }; - let percent = (percent.clamp(0.0, 1.0) * 100.0) as i32; - progress_signal.set(percent); - }) as Box) - }; - + let closure = Closure::wrap(Box::new(move |_: Event| { + let screen_height = document_element.scroll_height() as f64; + let inner_height = window.inner_height().unwrap().as_f64().unwrap(); + let scroll_height = window.scroll_y().unwrap(); + let max_scroll_height = screen_height - inner_height; + + let percent = if max_scroll_height > 0.0 { + scroll_height / max_scroll_height + } else { + 0.0 + }; + let percent = (percent.clamp(0.0, 1.0) * 100.0) as i32; + progress_signal.set(percent); + }) as Box); + document .add_event_listener_with_callback("scroll", closure.as_ref().unchecked_ref()) .unwrap(); closure.forget(); }); + let tp = r#"
hello,world
"#; + rsx! { nav { class: "border-red-500 bg-slate-400 text-xl fixed top-0 left-0 right-0", @@ -51,11 +54,7 @@ pub fn Navbar() -> Element { } } div { - class:"flex gap-10 justify-center", - Link { - to: Route::Home {}, - "首页" - } + class:"flex gap-5 justify-center", Link { to: Route::Home {}, "首页" @@ -64,6 +63,10 @@ pub fn Navbar() -> Element { to: Route::Home {}, "首页" } + + } + div{ + dangerous_inner_html:"{tp}" } div { @@ -74,10 +77,10 @@ pub fn Navbar() -> Element { } div { class: "progress bg-accent h-7 rounded-full text-xs flex items-center justify-center transition-all duration-300 overflow-hidden", - style: if progress_signal() > 0 { + style: if progress_signal() > 0 { format!("opacity: 1; transform: translateX(0); width: {}px;", if progress_signal()==100 { "70" } else { "28" }) - } else { - "opacity: 0; transform: translateX(100%); width: 0px".to_string() + } else { + "opacity: 0; transform: translateX(100%); width: 0px".to_string() }, onmouseenter: move |_| { progress_hover.set(true); diff --git a/client/src/components/notification.rs b/client/src/components/notification.rs index 8a52330..a740099 100644 --- a/client/src/components/notification.rs +++ b/client/src/components/notification.rs @@ -222,7 +222,7 @@ pub fn Notification() -> Element { return rsx! { div { - class: "w-[20rem] absolute right-8 top-5 max-sm:w-[12rem] ", + class: "w-[20rem] absolute right-8 max-sm:w-[12rem]", {notifications.notifications.iter().map(move |item| { rsx! { NotificationCard { diff --git a/client/src/main.rs b/client/src/main.rs index 4182505..fd3e0fd 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -3,12 +3,12 @@ use wasm_bindgen::{prelude::Closure, JsCast}; mod components; mod utils; mod views; -use crate::utils::error::CustomResult; use components::notification::{Notification, NotificationProvider}; use components::theme_toggle::{get_theme, ThemeProvider}; use components::Navbar; use utils::dom::{get_media_theme, set_element_dataset}; use views::Home; +use web_sys::Event; #[derive(Debug, Clone, Routable, PartialEq)] enum Route { @@ -22,6 +22,42 @@ const FAVICON: Asset = asset!("/assets/favicon.ico"); const GLOBAL_CSS: Asset = asset!("/assets/styling/global.css"); const TAILWIND_CSS: Asset = asset!("/assets/styling/tailwind.css"); +#[derive(Debug, Clone, PartialEq)] +enum DeviceType { + DESKTOP, + MOBILE, +} + +impl std::fmt::Display for DeviceType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let s = match self { + DeviceType::DESKTOP => "desktop", + DeviceType::MOBILE => "mobile", + }; + write!(f, "{}", s) + } +} + +#[derive(Debug, Clone, PartialEq)] +struct DeviceProvider(pub DeviceType); + +impl Default for DeviceProvider { + fn default() -> Self { + DeviceProvider(DeviceType::DESKTOP) + } +} + +impl From for DeviceProvider { + fn from(value: f64) -> Self { + let derive_type = if value > 1024.0 { + DeviceType::DESKTOP + } else { + DeviceType::MOBILE + }; + DeviceProvider(derive_type) + } +} + fn main() { dioxus::launch(App); } @@ -31,7 +67,24 @@ fn App() -> Element { let theme = get_theme(); use_context_provider(|| Signal::new(ThemeProvider(theme.clone()))); use_context_provider(|| Signal::new(NotificationProvider::default())); + use_context_provider(|| Signal::new(DeviceProvider::default())); let mut is_dark_context = use_context::>(); + let mut dervice_context = use_context::>(); + + use_effect(move || { + let window = web_sys::window().unwrap(); + let width = window.inner_width().unwrap().as_f64().unwrap(); + dervice_context.set(width.into()); + let closure = Closure::wrap(Box::new(move |_: Event| { + let width = window.inner_width().unwrap().as_f64().unwrap(); + dervice_context.set(width.into()); + }) as Box); + let window = web_sys::window().unwrap(); + window + .add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref()) + .unwrap(); + closure.forget(); + }); use_effect(move || { let _ = set_element_dataset("html", "theme", &theme); diff --git a/server/Cargo.toml b/server/Cargo.toml index e612021..01e4150 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -8,5 +8,6 @@ authors.workspace = true common = { path = "../common" } rocket = { workspace = true } tokio = { workspace = true } -serde = { workspace = true } -surrealdb = { workspace = true } \ No newline at end of file +serde = { workspace = true } +surrealdb = { workspace = true } +rocket_cors = { workspace = true } diff --git a/server/src/main.rs b/server/src/main.rs index 235c857..80999a1 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -2,9 +2,8 @@ mod db; mod utils; use db::Database; -use rocket::{get, routes, State}; -use serde::{Deserialize, Serialize}; -use std::sync::{Arc, Mutex}; +use rocket::{get, http::Method, routes}; +use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors, CorsOptions}; use utils::error::CustomResult; @@ -13,15 +12,29 @@ fn index() -> &'static str { "Hello, world!" } -#[get("/api/theme")] -fn get_theme() -> &'static str { - "light" -} - pub struct AppState { db: Database, } +fn cors() -> Cors { + CorsOptions { + allowed_origins: AllowedOrigins::all(), + allowed_methods: vec![Method::Get, Method::Post, Method::Options] + .into_iter() + .map(From::from) + .collect(), + allowed_headers: AllowedHeaders::all(), + allow_credentials: true, + expose_headers: Default::default(), + max_age: None, + send_wildcard: false, + fairing_route_base: "/".to_string(), + fairing_route_rank: 0, + } + .to_cors() + .expect("CORS配置错误") +} + #[rocket::main] async fn main() -> CustomResult<()> { let rocket_build = rocket::build(); @@ -29,8 +42,9 @@ async fn main() -> CustomResult<()> { let db = Database::link().await?; let rocket = rocket_build - .mount("/", routes![index, get_theme]) + .mount("/", routes![index]) .manage(AppState { db }) + .attach(cors()) .ignite() .await?; rocket.launch().await?;