后端:新增cors,前端:新增设备判断钩子

This commit is contained in:
lsy 2025-01-16 22:36:51 +08:00
parent b75433cdbd
commit 5a6c020920
12 changed files with 164 additions and 64 deletions

2
.vscode/tasks.json vendored
View File

@ -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": []
},

28
Cargo.lock generated
View File

@ -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"

View File

@ -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]

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1,36 +1,37 @@
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::<Signal<DeviceProvider>>();
use_effect(move || {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let document_element = document.document_element().unwrap();
let closure: Closure<dyn FnMut(_)> = {
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 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 {
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<dyn FnMut(_)>)
};
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<dyn FnMut(Event)>);
document
.add_event_listener_with_callback("scroll", closure.as_ref().unchecked_ref())
@ -38,6 +39,8 @@ pub fn Navbar() -> Element {
closure.forget();
});
let tp = r#"<div>hello,world</div>"#;
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 {

View File

@ -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 {

View File

@ -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<f64> 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::<Signal<ThemeProvider>>();
let mut dervice_context = use_context::<Signal<DeviceProvider>>();
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<dyn FnMut(Event)>);
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);

View File

@ -10,3 +10,4 @@ rocket = { workspace = true }
tokio = { workspace = true }
serde = { workspace = true }
surrealdb = { workspace = true }
rocket_cors = { workspace = true }

View File

@ -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?;