前端:构建好了主题切换
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