前端:构建好了主题切换
This commit is contained in:
commit
351ee3f675
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
**/target
|
||||||
|
.DS_Store
|
||||||
|
**/.idea
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
73
.vscode/tasks.json
vendored
Normal file
73
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "backend",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "cargo run",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/backend"
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$armcc5"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "backend-fmt",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "cargo fmt",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/backend"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "frontend-dev",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "dx serve --platform web",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/frontend"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "frontend-build",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "dx build --platform web",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/frontend"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "frontend-fmt",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "cargo fmt",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/frontend"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "format-all",
|
||||||
|
"dependsOn": [
|
||||||
|
"backend-fmt",
|
||||||
|
"frontend-fmt"
|
||||||
|
],
|
||||||
|
"dependsOrder": "parallel",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "run-all",
|
||||||
|
"dependsOn": [
|
||||||
|
"backend",
|
||||||
|
"frontend-dev"
|
||||||
|
],
|
||||||
|
"dependsOrder": "parallel",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5193
frontend/Cargo.lock
generated
Normal file
5193
frontend/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
frontend/Cargo.toml
Normal file
31
frontend/Cargo.toml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[package]
|
||||||
|
name = "frontend"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["lsy <lsy22@vip.qq.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dioxus = { version = "0.6.0", features = ["router"] }
|
||||||
|
dioxus-free-icons = { version = "0.9", features = ["bootstrap"] }
|
||||||
|
web-sys = { version = "0.3.76", features = ["Window","Storage","MediaQueryList"] }
|
||||||
|
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
web = ["dioxus/web"]
|
||||||
|
desktop = ["dioxus/desktop"]
|
||||||
|
mobile = ["dioxus/mobile"]
|
||||||
|
|
||||||
|
[profile]
|
||||||
|
|
||||||
|
[profile.wasm-dev]
|
||||||
|
inherits = "dev"
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
[profile.server-dev]
|
||||||
|
inherits = "dev"
|
||||||
|
|
||||||
|
[profile.android-dev]
|
||||||
|
inherits = "dev"
|
24
frontend/Dioxus.toml
Normal file
24
frontend/Dioxus.toml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[application]
|
||||||
|
|
||||||
|
# App (Project) Name
|
||||||
|
name = "frontend"
|
||||||
|
|
||||||
|
[web.app]
|
||||||
|
|
||||||
|
# HTML title tag content
|
||||||
|
title = "frontend"
|
||||||
|
|
||||||
|
# include `assets` in web platform
|
||||||
|
[web.resource]
|
||||||
|
|
||||||
|
# Additional CSS style files
|
||||||
|
style = []
|
||||||
|
|
||||||
|
# Additional JavaScript files
|
||||||
|
script = []
|
||||||
|
|
||||||
|
[web.resource.dev]
|
||||||
|
|
||||||
|
# Javascript code file
|
||||||
|
# serve: [dev-server] only
|
||||||
|
script = []
|
BIN
frontend/assets/favicon.ico
Normal file
BIN
frontend/assets/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
20
frontend/assets/header.svg
Normal file
20
frontend/assets/header.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 23 KiB |
8
frontend/assets/styling/blog.css
Normal file
8
frontend/assets/styling/blog.css
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#blog {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#blog a {
|
||||||
|
color: #ffffff;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
38
frontend/assets/styling/global.css
Normal file
38
frontend/assets/styling/global.css
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
:root {
|
||||||
|
--transition-duration: 150ms;
|
||||||
|
--transition-easing: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
--hljs-theme: 'github';
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[class~="dark"] {
|
||||||
|
--hljs-theme: 'github-dark';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保 Radix UI 主题类包裹整个应用 */
|
||||||
|
.radix-themes {
|
||||||
|
transition:
|
||||||
|
background-color var(--transition-duration) var(--transition-easing),
|
||||||
|
color var(--transition-duration) var(--transition-easing);
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 基础布局样式 */
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加暗色模式支持 */
|
||||||
|
.radix-themes-dark {
|
||||||
|
@apply dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏不活跃的主题样式 */
|
||||||
|
[data-theme="light"] .hljs-dark {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .hljs-light {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
5
frontend/assets/styling/navbar.css
Normal file
5
frontend/assets/styling/navbar.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#navbar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
574
frontend/assets/tailwind.css
Normal file
574
frontend/assets/tailwind.css
Normal file
@ -0,0 +1,574 @@
|
|||||||
|
*, ::before, ::after {
|
||||||
|
--tw-border-spacing-x: 0;
|
||||||
|
--tw-border-spacing-y: 0;
|
||||||
|
--tw-translate-x: 0;
|
||||||
|
--tw-translate-y: 0;
|
||||||
|
--tw-rotate: 0;
|
||||||
|
--tw-skew-x: 0;
|
||||||
|
--tw-skew-y: 0;
|
||||||
|
--tw-scale-x: 1;
|
||||||
|
--tw-scale-y: 1;
|
||||||
|
--tw-pan-x: ;
|
||||||
|
--tw-pan-y: ;
|
||||||
|
--tw-pinch-zoom: ;
|
||||||
|
--tw-scroll-snap-strictness: proximity;
|
||||||
|
--tw-gradient-from-position: ;
|
||||||
|
--tw-gradient-via-position: ;
|
||||||
|
--tw-gradient-to-position: ;
|
||||||
|
--tw-ordinal: ;
|
||||||
|
--tw-slashed-zero: ;
|
||||||
|
--tw-numeric-figure: ;
|
||||||
|
--tw-numeric-spacing: ;
|
||||||
|
--tw-numeric-fraction: ;
|
||||||
|
--tw-ring-inset: ;
|
||||||
|
--tw-ring-offset-width: 0px;
|
||||||
|
--tw-ring-offset-color: #fff;
|
||||||
|
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||||
|
--tw-ring-offset-shadow: 0 0 #0000;
|
||||||
|
--tw-ring-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow-colored: 0 0 #0000;
|
||||||
|
--tw-blur: ;
|
||||||
|
--tw-brightness: ;
|
||||||
|
--tw-contrast: ;
|
||||||
|
--tw-grayscale: ;
|
||||||
|
--tw-hue-rotate: ;
|
||||||
|
--tw-invert: ;
|
||||||
|
--tw-saturate: ;
|
||||||
|
--tw-sepia: ;
|
||||||
|
--tw-drop-shadow: ;
|
||||||
|
--tw-backdrop-blur: ;
|
||||||
|
--tw-backdrop-brightness: ;
|
||||||
|
--tw-backdrop-contrast: ;
|
||||||
|
--tw-backdrop-grayscale: ;
|
||||||
|
--tw-backdrop-hue-rotate: ;
|
||||||
|
--tw-backdrop-invert: ;
|
||||||
|
--tw-backdrop-opacity: ;
|
||||||
|
--tw-backdrop-saturate: ;
|
||||||
|
--tw-backdrop-sepia: ;
|
||||||
|
--tw-contain-size: ;
|
||||||
|
--tw-contain-layout: ;
|
||||||
|
--tw-contain-paint: ;
|
||||||
|
--tw-contain-style: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
::backdrop {
|
||||||
|
--tw-border-spacing-x: 0;
|
||||||
|
--tw-border-spacing-y: 0;
|
||||||
|
--tw-translate-x: 0;
|
||||||
|
--tw-translate-y: 0;
|
||||||
|
--tw-rotate: 0;
|
||||||
|
--tw-skew-x: 0;
|
||||||
|
--tw-skew-y: 0;
|
||||||
|
--tw-scale-x: 1;
|
||||||
|
--tw-scale-y: 1;
|
||||||
|
--tw-pan-x: ;
|
||||||
|
--tw-pan-y: ;
|
||||||
|
--tw-pinch-zoom: ;
|
||||||
|
--tw-scroll-snap-strictness: proximity;
|
||||||
|
--tw-gradient-from-position: ;
|
||||||
|
--tw-gradient-via-position: ;
|
||||||
|
--tw-gradient-to-position: ;
|
||||||
|
--tw-ordinal: ;
|
||||||
|
--tw-slashed-zero: ;
|
||||||
|
--tw-numeric-figure: ;
|
||||||
|
--tw-numeric-spacing: ;
|
||||||
|
--tw-numeric-fraction: ;
|
||||||
|
--tw-ring-inset: ;
|
||||||
|
--tw-ring-offset-width: 0px;
|
||||||
|
--tw-ring-offset-color: #fff;
|
||||||
|
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||||
|
--tw-ring-offset-shadow: 0 0 #0000;
|
||||||
|
--tw-ring-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow-colored: 0 0 #0000;
|
||||||
|
--tw-blur: ;
|
||||||
|
--tw-brightness: ;
|
||||||
|
--tw-contrast: ;
|
||||||
|
--tw-grayscale: ;
|
||||||
|
--tw-hue-rotate: ;
|
||||||
|
--tw-invert: ;
|
||||||
|
--tw-saturate: ;
|
||||||
|
--tw-sepia: ;
|
||||||
|
--tw-drop-shadow: ;
|
||||||
|
--tw-backdrop-blur: ;
|
||||||
|
--tw-backdrop-brightness: ;
|
||||||
|
--tw-backdrop-contrast: ;
|
||||||
|
--tw-backdrop-grayscale: ;
|
||||||
|
--tw-backdrop-hue-rotate: ;
|
||||||
|
--tw-backdrop-invert: ;
|
||||||
|
--tw-backdrop-opacity: ;
|
||||||
|
--tw-backdrop-saturate: ;
|
||||||
|
--tw-backdrop-sepia: ;
|
||||||
|
--tw-contain-size: ;
|
||||||
|
--tw-contain-layout: ;
|
||||||
|
--tw-contain-paint: ;
|
||||||
|
--tw-contain-style: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
|
||||||
|
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
|
||||||
|
*/
|
||||||
|
|
||||||
|
*,
|
||||||
|
::before,
|
||||||
|
::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* 1 */
|
||||||
|
border-width: 0;
|
||||||
|
/* 2 */
|
||||||
|
border-style: solid;
|
||||||
|
/* 2 */
|
||||||
|
border-color: #e5e7eb;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
::before,
|
||||||
|
::after {
|
||||||
|
--tw-content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Use a consistent sensible line-height in all browsers.
|
||||||
|
2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
3. Use a more readable tab size.
|
||||||
|
4. Use the user's configured `sans` font-family by default.
|
||||||
|
5. Use the user's configured `sans` font-feature-settings by default.
|
||||||
|
6. Use the user's configured `sans` font-variation-settings by default.
|
||||||
|
7. Disable tap highlights on iOS
|
||||||
|
*/
|
||||||
|
|
||||||
|
html,
|
||||||
|
:host {
|
||||||
|
line-height: 1.5;
|
||||||
|
/* 1 */
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
/* 2 */
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
/* 3 */
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
/* 3 */
|
||||||
|
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
/* 4 */
|
||||||
|
font-feature-settings: normal;
|
||||||
|
/* 5 */
|
||||||
|
font-variation-settings: normal;
|
||||||
|
/* 6 */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
/* 7 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Remove the margin in all browsers.
|
||||||
|
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
/* 1 */
|
||||||
|
line-height: inherit;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Add the correct height in Firefox.
|
||||||
|
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
|
||||||
|
3. Ensure horizontal rules are visible by default.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
height: 0;
|
||||||
|
/* 1 */
|
||||||
|
color: inherit;
|
||||||
|
/* 2 */
|
||||||
|
border-top-width: 1px;
|
||||||
|
/* 3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add the correct text decoration in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr:where([title]) {
|
||||||
|
-webkit-text-decoration: underline dotted;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the default font size and weight for headings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reset links to optimize for opt-in styling instead of opt-out.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add the correct font weight in Edge and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Use the user's configured `mono` font-family by default.
|
||||||
|
2. Use the user's configured `mono` font-feature-settings by default.
|
||||||
|
3. Use the user's configured `mono` font-variation-settings by default.
|
||||||
|
4. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp,
|
||||||
|
pre {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
/* 1 */
|
||||||
|
font-feature-settings: normal;
|
||||||
|
/* 2 */
|
||||||
|
font-variation-settings: normal;
|
||||||
|
/* 3 */
|
||||||
|
font-size: 1em;
|
||||||
|
/* 4 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
|
||||||
|
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
|
||||||
|
3. Remove gaps between table borders by default.
|
||||||
|
*/
|
||||||
|
|
||||||
|
table {
|
||||||
|
text-indent: 0;
|
||||||
|
/* 1 */
|
||||||
|
border-color: inherit;
|
||||||
|
/* 2 */
|
||||||
|
border-collapse: collapse;
|
||||||
|
/* 3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Change the font styles in all browsers.
|
||||||
|
2. Remove the margin in Firefox and Safari.
|
||||||
|
3. Remove default padding in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
/* 1 */
|
||||||
|
font-feature-settings: inherit;
|
||||||
|
/* 1 */
|
||||||
|
font-variation-settings: inherit;
|
||||||
|
/* 1 */
|
||||||
|
font-size: 100%;
|
||||||
|
/* 1 */
|
||||||
|
font-weight: inherit;
|
||||||
|
/* 1 */
|
||||||
|
line-height: inherit;
|
||||||
|
/* 1 */
|
||||||
|
letter-spacing: inherit;
|
||||||
|
/* 1 */
|
||||||
|
color: inherit;
|
||||||
|
/* 1 */
|
||||||
|
margin: 0;
|
||||||
|
/* 2 */
|
||||||
|
padding: 0;
|
||||||
|
/* 3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the inheritance of text transform in Edge and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
2. Remove default button styles.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input:where([type='button']),
|
||||||
|
input:where([type='reset']),
|
||||||
|
input:where([type='submit']) {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
/* 1 */
|
||||||
|
background-color: transparent;
|
||||||
|
/* 2 */
|
||||||
|
background-image: none;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use the modern Firefox focus style for all focusable elements.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:-moz-focusring {
|
||||||
|
outline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
|
||||||
|
*/
|
||||||
|
|
||||||
|
:-moz-ui-invalid {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add the correct vertical alignment in Chrome and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Correct the cursor style of increment and decrement buttons in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-inner-spin-button,
|
||||||
|
::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type='search'] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
/* 1 */
|
||||||
|
outline-offset: -2px;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the inner padding in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
/* 1 */
|
||||||
|
font: inherit;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add the correct display in Chrome and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removes the default spacing and border for appropriate elements.
|
||||||
|
*/
|
||||||
|
|
||||||
|
blockquote,
|
||||||
|
dl,
|
||||||
|
dd,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
hr,
|
||||||
|
figure,
|
||||||
|
p,
|
||||||
|
pre {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
menu {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reset default styling for dialogs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dialog {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Prevent resizing textareas horizontally by default.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
|
||||||
|
2. Set the default placeholder color to the user's configured gray 400 color.
|
||||||
|
*/
|
||||||
|
|
||||||
|
input::-moz-placeholder, textarea::-moz-placeholder {
|
||||||
|
opacity: 1;
|
||||||
|
/* 1 */
|
||||||
|
color: #9ca3af;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder,
|
||||||
|
textarea::placeholder {
|
||||||
|
opacity: 1;
|
||||||
|
/* 1 */
|
||||||
|
color: #9ca3af;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the default cursor for buttons.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
[role="button"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Make sure disabled buttons don't get the pointer cursor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
|
||||||
|
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
|
||||||
|
This can trigger a poorly considered lint error in some tools but is included by design.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img,
|
||||||
|
svg,
|
||||||
|
video,
|
||||||
|
canvas,
|
||||||
|
audio,
|
||||||
|
iframe,
|
||||||
|
embed,
|
||||||
|
object {
|
||||||
|
display: block;
|
||||||
|
/* 1 */
|
||||||
|
vertical-align: middle;
|
||||||
|
/* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
|
||||||
|
*/
|
||||||
|
|
||||||
|
img,
|
||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make elements with the HTML hidden attribute stay hidden by default */
|
||||||
|
|
||||||
|
[hidden]:where(:not([hidden="until-found"])) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.static {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-sky-700 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(3 105 161 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-white {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-slate-100 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(241 245 249 / var(--tw-text-opacity, 1));
|
||||||
|
}
|
3
frontend/input.css
Normal file
3
frontend/input.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
27
frontend/src/common/error.rs
Normal file
27
frontend/src/common/error.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CustomError(String);
|
||||||
|
|
||||||
|
impl std::fmt::Display for CustomError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CustomErrorInto {
|
||||||
|
fn into_custom_error(self) -> CustomError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomErrorInto for &str {
|
||||||
|
fn into_custom_error(self) -> CustomError {
|
||||||
|
CustomError(self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: std::error::Error> From<E> for CustomError {
|
||||||
|
fn from(error: E) -> Self {
|
||||||
|
CustomError(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CustomResult<T> = Result<T, CustomError>;
|
||||||
|
|
1
frontend/src/common/mod.rs
Normal file
1
frontend/src/common/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod error;
|
4
frontend/src/components/mod.rs
Normal file
4
frontend/src/components/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
mod navbar;
|
||||||
|
pub use navbar::Navbar;
|
||||||
|
mod theme_toggle;
|
||||||
|
pub use theme_toggle::Toggle;
|
25
frontend/src/components/navbar.rs
Normal file
25
frontend/src/components/navbar.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use crate::Route;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
const NAVBAR_CSS: Asset = asset!("/assets/styling/navbar.css");
|
||||||
|
use super::Toggle;
|
||||||
|
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Navbar() -> Element {
|
||||||
|
rsx! {
|
||||||
|
document::Link { rel: "stylesheet", href: NAVBAR_CSS }
|
||||||
|
|
||||||
|
div {
|
||||||
|
id: "navbar",
|
||||||
|
Link {
|
||||||
|
to: Route::Home {},
|
||||||
|
"home"
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle{}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Outlet::<Route> {}
|
||||||
|
}
|
||||||
|
}
|
64
frontend/src/components/theme_toggle.rs
Normal file
64
frontend/src/components/theme_toggle.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
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;
|
||||||
|
use crate::{IsDark,set_local_storage_value};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Props, Clone)]
|
||||||
|
pub struct ToggleProps {
|
||||||
|
#[props(default = 20)]
|
||||||
|
pub height: u32,
|
||||||
|
#[props(default = 20)]
|
||||||
|
pub width: u32,
|
||||||
|
#[props(default = "currentColor".to_string())]
|
||||||
|
pub fill: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Toggle(props: ToggleProps) -> Element {
|
||||||
|
let mut dark_context=use_context::<Signal<IsDark>>();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
onclick: move |_|
|
||||||
|
{
|
||||||
|
dark_context.set(IsDark(!dark_context().0));
|
||||||
|
match set_local_storage_value("theme", if !dark_context().0 { "true" } else { "false" }) {
|
||||||
|
Ok(_)=>{},
|
||||||
|
Err(_)=>{
|
||||||
|
tracing::error!("主题储存失败");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
match {dark_context().0} {
|
||||||
|
false=>{
|
||||||
|
rsx!(
|
||||||
|
Icon{
|
||||||
|
width:props.width,
|
||||||
|
height:props.height,
|
||||||
|
fill:props.fill,
|
||||||
|
icon:BsMoonStars,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
true=>{
|
||||||
|
rsx!{
|
||||||
|
Icon{
|
||||||
|
width:props.width,
|
||||||
|
height:props.height,
|
||||||
|
fill:props.fill,
|
||||||
|
icon:BsSun,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
4
frontend/src/input.css
Normal file
4
frontend/src/input.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@import "@radix-ui/themes/styles.css";
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
93
frontend/src/main.rs
Normal file
93
frontend/src/main.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use dioxus::{logger::tracing, prelude::*};
|
||||||
|
use web_sys::{window, MediaQueryList, Storage};
|
||||||
|
mod common;
|
||||||
|
use common::error::{CustomErrorInto, CustomResult};
|
||||||
|
|
||||||
|
use components::Navbar;
|
||||||
|
use views::Home;
|
||||||
|
|
||||||
|
mod components;
|
||||||
|
mod views;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Routable, PartialEq)]
|
||||||
|
#[rustfmt::skip]
|
||||||
|
enum Route {
|
||||||
|
#[layout(Navbar)]
|
||||||
|
#[route("/")]
|
||||||
|
Home {},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
||||||
|
const GLOBAL_CSS: Asset = asset!("/assets/styling/global.css");
|
||||||
|
const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css");
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct IsDark(bool);
|
||||||
|
|
||||||
|
fn get_storage() -> CustomResult<Storage> {
|
||||||
|
window()
|
||||||
|
.ok_or("浏览器window对象不存在".into_custom_error())?
|
||||||
|
.local_storage()
|
||||||
|
.map_err(|_| "无法访问localStorage API".into_custom_error())?
|
||||||
|
.ok_or("浏览器不支持localStorage".into_custom_error())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_local_storage_value(key: &str) -> CustomResult<String> {
|
||||||
|
get_storage()?
|
||||||
|
.get_item(key)
|
||||||
|
.map_err(|_| "读取localStorage时发生错误".into_custom_error())?
|
||||||
|
.ok_or(format!("localStorage中不存在键'{}'", key).into_custom_error())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_local_storage_value(key: &str, value: &str) -> CustomResult<()> {
|
||||||
|
get_storage()?
|
||||||
|
.set_item(key, value)
|
||||||
|
.map_err(|_| format!("无法将值写入localStorage的'{}'键", key).into_custom_error())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_media_theme() -> CustomResult<bool> {
|
||||||
|
let media_query = window()
|
||||||
|
.ok_or("浏览器window对象不存在".into_custom_error())?
|
||||||
|
.match_media("(prefers-color-scheme: dark)")
|
||||||
|
.map_err(|_| format!("读取媒体查询时发生错误").into_custom_error())?
|
||||||
|
.ok_or("查询media时发生错误".into_custom_error())?
|
||||||
|
.matches();
|
||||||
|
Ok(media_query)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dioxus::launch(App);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn App() -> Element {
|
||||||
|
use_context_provider(|| Signal::new(IsDark(false)));
|
||||||
|
let mut is_dark_context = use_context::<Signal<IsDark>>();
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
let _ = use_memo(move || {
|
||||||
|
let storage_theme = get_local_storage_value("theme");
|
||||||
|
match storage_theme {
|
||||||
|
Ok(b) => is_dark_context.set(IsDark(b == "true")),
|
||||||
|
Err(_) => {
|
||||||
|
let device_theme = get_media_theme();
|
||||||
|
match device_theme {
|
||||||
|
Ok(b) => is_dark_context.set(IsDark(b)),
|
||||||
|
Err(_) => is_dark_context.set(IsDark(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
// Global app resources
|
||||||
|
document::Link { rel: "icon", href: FAVICON }
|
||||||
|
document::Stylesheet{ href: GLOBAL_CSS }
|
||||||
|
document::Stylesheet { href: TAILWIND_CSS }
|
||||||
|
|
||||||
|
Router::<Route> {}
|
||||||
|
}
|
||||||
|
}
|
8
frontend/src/views/home.rs
Normal file
8
frontend/src/views/home.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Home() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div { "hello,world" }
|
||||||
|
}
|
||||||
|
}
|
2
frontend/src/views/mod.rs
Normal file
2
frontend/src/views/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mod home;
|
||||||
|
pub use home::Home;
|
9
frontend/tailwind.config.js
Normal file
9
frontend/tailwind.config.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
mode: "all",
|
||||||
|
content: ["./src/**/*.{rs,html,css}", "./dist/**/*.html"],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user