From 37b08927a7e1735a6165ad3a6ec168404b798567 Mon Sep 17 00:00:00 2001
From: yyc12345
Date: Tue, 12 May 2026 15:32:30 +0800
Subject: [PATCH] update frontend with bulma css and home&404 pages
---
assets/.nginx.conf | 61 +++++++++
assets/dial_plate_gen.py | 29 ++++
frontend/package.json | 1 +
frontend/pnpm-lock.yaml | 231 +++++++++++++++++++++++++++++---
frontend/public/index.css | 0
frontend/public/index.scss | 2 +
frontend/src/App.vue | 15 ++-
frontend/src/main.ts | 2 +
frontend/src/router/index.ts | 4 +-
frontend/src/stores/counter.ts | 12 --
frontend/src/stores/global.ts | 26 ++++
frontend/src/utils/i18n.ts | 4 +
frontend/src/views/Home.vue | 18 ++-
frontend/src/views/NotFound.vue | 17 +++
frontend/src/views/Page404.vue | 8 --
frontend/vite.config.ts | 3 +-
16 files changed, 383 insertions(+), 50 deletions(-)
create mode 100644 assets/.nginx.conf
create mode 100644 assets/dial_plate_gen.py
delete mode 100644 frontend/public/index.css
create mode 100644 frontend/public/index.scss
delete mode 100644 frontend/src/stores/counter.ts
create mode 100644 frontend/src/stores/global.ts
create mode 100644 frontend/src/utils/i18n.ts
create mode 100644 frontend/src/views/NotFound.vue
delete mode 100644 frontend/src/views/Page404.vue
diff --git a/assets/.nginx.conf b/assets/.nginx.conf
new file mode 100644
index 0000000..38148f6
--- /dev/null
+++ b/assets/.nginx.conf
@@ -0,0 +1,61 @@
+# ============================
+# 路由 1: /web -> 静态文件
+# ============================
+location /web {
+ # 使用 alias 精确映射
+ # 请求 /web/index.html -> /var/www/static/index.html
+ alias /var/www/static;
+
+ # 静态文件优化
+ expires 7d;
+ add_header Cache-Control "public, max-age=604800";
+
+ # 尝试返回文件,不存在则返回404(避免落入其他location)
+ try_files $uri $uri/ =404;
+
+ # 可选:启用 gzip 压缩
+ gzip_static on;
+}
+
+# ============================
+# 路由 2: /api -> Go 程序 (8848端口)
+# ============================
+location /api {
+ # 反向代理到本地 Go 服务
+ proxy_pass http://127.0.0.1:8848;
+
+ # 重要:保留原始请求头
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # WebSocket 支持(如果 Go 程序需要)
+ # proxy_http_version 1.1;
+ # proxy_set_header Upgrade $http_upgrade;
+ # proxy_set_header Connection "upgrade";
+
+ # 超时设置(根据业务调整)
+ proxy_connect_timeout 60s;
+ proxy_send_timeout 60s;
+ proxy_read_timeout 60s;
+
+ # 缓冲设置(可选,大文件上传时注意调整)
+ proxy_buffering on;
+ proxy_buffer_size 4k;
+ proxy_buffers 8 4k;
+}
+
+# ============================
+# 可选:根路径处理
+# ============================
+location = / {
+ # 重定向到 /web
+ return 302 /web/;
+}
+
+# 禁止访问隐藏文件
+location ~ /\. {
+ deny all;
+ return 404;
+}
\ No newline at end of file
diff --git a/assets/dial_plate_gen.py b/assets/dial_plate_gen.py
new file mode 100644
index 0000000..ad83c70
--- /dev/null
+++ b/assets/dial_plate_gen.py
@@ -0,0 +1,29 @@
+import math
+
+print('Dial Plate Generator')
+plateSize = float(input('Plate size: '))
+hourInnerRadius = float(input('Hour inner radius percent (float): '))
+hourOutterRadius = float(input('Hour outter radius percent (float): '))
+minuteRadius = float(input('Minute radius percent (float): '))
+
+halfPlateSize = plateSize / 2
+for i in range(24):
+ rad = math.radians(90 - i * 30)
+ x = math.cos(rad)
+ y = math.sin(rad)
+ radius = halfPlateSize * (hourOutterRadius if i < 12 else hourInnerRadius)
+ x = x * radius + halfPlateSize
+ y = (-y * radius) + halfPlateSize
+ print('{}'.format(x, y, i))
+
+print('')
+
+for i in range(12):
+ rad = math.radians(90 - i * 30)
+ x = math.cos(rad)
+ y = math.sin(rad)
+ radius = minuteRadius * halfPlateSize
+ x = x * radius + halfPlateSize
+ y = (-y * radius) + halfPlateSize
+ print('{}'.format(x, y, i * 5))
+
diff --git a/frontend/package.json b/frontend/package.json
index 9e48d9f..6afe2b1 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -33,6 +33,7 @@
"jiti": "^2.6.1",
"npm-run-all2": "^8.0.4",
"oxlint": "~1.60.0",
+ "sass": "^1.99.0",
"typescript": "~6.0.0",
"vite": "^8.0.8",
"vite-plugin-vue-devtools": "^8.1.1",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 61ad93c..fa9bbc2 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -35,7 +35,7 @@ importers:
version: 24.12.2
'@vitejs/plugin-vue':
specifier: ^6.0.6
- version: 6.0.6(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3))
+ version: 6.0.6(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3))
'@vue/eslint-config-typescript':
specifier: ^14.7.0
version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.1(jiti@2.6.1))))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
@@ -60,15 +60,18 @@ importers:
oxlint:
specifier: ~1.60.0
version: 1.60.0
+ sass:
+ specifier: ^1.99.0
+ version: 1.99.0
typescript:
specifier: ~6.0.0
version: 6.0.3
vite:
specifier: ^8.0.8
- version: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)
+ version: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)
vite-plugin-vue-devtools:
specifier: ^8.1.1
- version: 8.1.1(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3))
+ version: 8.1.1(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3))
vue-tsc:
specifier: ^3.2.6
version: 3.2.7(typescript@6.0.3)
@@ -451,6 +454,94 @@ packages:
cpu: [x64]
os: [win32]
+ '@parcel/watcher-android-arm64@2.5.6':
+ resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.6':
+ resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.6':
+ resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.6':
+ resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.6':
+ resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/watcher-linux-arm-musl@2.5.6':
+ resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.6':
+ resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.6':
+ resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.6':
+ resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/watcher-linux-x64-musl@2.5.6':
+ resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/watcher-win32-arm64@2.5.6':
+ resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.6':
+ resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.6':
+ resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.6':
+ resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
+ engines: {node: '>= 10.0.0'}
+
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
@@ -820,6 +911,10 @@ packages:
caniuse-lite@1.0.30001791:
resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==}
+ chokidar@4.0.3:
+ resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+ engines: {node: '>= 14.16.0'}
+
chokidar@5.0.0:
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
engines: {node: '>= 20.19.0'}
@@ -1034,6 +1129,9 @@ packages:
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
engines: {node: '>= 4'}
+ immutable@5.1.5:
+ resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==}
+
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
@@ -1250,6 +1348,9 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
node-releases@2.0.38:
resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==}
@@ -1371,6 +1472,10 @@ packages:
resolution: {integrity: sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==}
engines: {node: ^18.17.0 || >=20.5.0}
+ readdirp@4.1.2:
+ resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+ engines: {node: '>= 14.18.0'}
+
readdirp@5.0.0:
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
engines: {node: '>= 20.19.0'}
@@ -1394,6 +1499,11 @@ packages:
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ sass@1.99.0:
+ resolution: {integrity: sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+
scule@1.3.0:
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
@@ -2011,6 +2121,67 @@ snapshots:
'@oxlint/binding-win32-x64-msvc@1.60.0':
optional: true
+ '@parcel/watcher-android-arm64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.6':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.6':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.6':
+ optional: true
+
+ '@parcel/watcher@2.5.6':
+ dependencies:
+ detect-libc: 2.1.2
+ is-glob: 4.0.3
+ node-addon-api: 7.1.1
+ picomatch: 4.0.4
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.6
+ '@parcel/watcher-darwin-arm64': 2.5.6
+ '@parcel/watcher-darwin-x64': 2.5.6
+ '@parcel/watcher-freebsd-x64': 2.5.6
+ '@parcel/watcher-linux-arm-glibc': 2.5.6
+ '@parcel/watcher-linux-arm-musl': 2.5.6
+ '@parcel/watcher-linux-arm64-glibc': 2.5.6
+ '@parcel/watcher-linux-arm64-musl': 2.5.6
+ '@parcel/watcher-linux-x64-glibc': 2.5.6
+ '@parcel/watcher-linux-x64-musl': 2.5.6
+ '@parcel/watcher-win32-arm64': 2.5.6
+ '@parcel/watcher-win32-ia32': 2.5.6
+ '@parcel/watcher-win32-x64': 2.5.6
+ optional: true
+
'@polka/url@1.0.0-next.29': {}
'@rolldown/binding-android-arm64@1.0.0-rc.17':
@@ -2174,10 +2345,10 @@ snapshots:
'@typescript-eslint/types': 8.59.1
eslint-visitor-keys: 5.0.1
- '@vitejs/plugin-vue@6.0.6(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3))':
+ '@vitejs/plugin-vue@6.0.6(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-rc.13
- vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)
vue: 3.5.33(typescript@6.0.3)
'@volar/language-core@2.4.28':
@@ -2411,6 +2582,10 @@ snapshots:
caniuse-lite@1.0.30001791: {}
+ chokidar@4.0.3:
+ dependencies:
+ readdirp: 4.1.2
+
chokidar@5.0.0:
dependencies:
readdirp: 5.0.0
@@ -2611,6 +2786,8 @@ snapshots:
ignore@7.0.5: {}
+ immutable@5.1.5: {}
+
imurmurhash@0.1.4: {}
is-docker@3.0.0: {}
@@ -2769,6 +2946,9 @@ snapshots:
natural-compare@1.4.0: {}
+ node-addon-api@7.1.1:
+ optional: true
+
node-releases@2.0.38: {}
npm-normalize-package-bin@4.0.0: {}
@@ -2899,6 +3079,8 @@ snapshots:
json-parse-even-better-errors: 4.0.0
npm-normalize-package-bin: 4.0.0
+ readdirp@4.1.2: {}
+
readdirp@5.0.0: {}
reusify@1.1.0: {}
@@ -2932,6 +3114,14 @@ snapshots:
dependencies:
queue-microtask: 1.2.3
+ sass@1.99.0:
+ dependencies:
+ chokidar: 4.0.3
+ immutable: 5.1.5
+ source-map-js: 1.2.1
+ optionalDependencies:
+ '@parcel/watcher': 2.5.6
+
scule@1.3.0: {}
semver@6.3.1: {}
@@ -3022,17 +3212,17 @@ snapshots:
util-deprecate@1.0.2: {}
- vite-dev-rpc@1.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)):
+ vite-dev-rpc@1.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)):
dependencies:
birpc: 2.9.0
- vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)
- vite-hot-client: 2.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)
+ vite-hot-client: 2.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))
- vite-hot-client@2.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)):
+ vite-hot-client@2.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)):
dependencies:
- vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)
- vite-plugin-inspect@11.3.3(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)):
+ vite-plugin-inspect@11.3.3(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)):
dependencies:
ansis: 4.2.0
debug: 4.4.3
@@ -3042,26 +3232,26 @@ snapshots:
perfect-debounce: 2.1.0
sirv: 3.0.2
unplugin-utils: 0.3.1
- vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)
- vite-dev-rpc: 1.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)
+ vite-dev-rpc: 1.1.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))
transitivePeerDependencies:
- supports-color
- vite-plugin-vue-devtools@8.1.1(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3)):
+ vite-plugin-vue-devtools@8.1.1(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))(vue@3.5.33(typescript@6.0.3)):
dependencies:
'@vue/devtools-core': 8.1.1(vue@3.5.33(typescript@6.0.3))
'@vue/devtools-kit': 8.1.1
'@vue/devtools-shared': 8.1.1
sirv: 3.0.2
- vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)
- vite-plugin-inspect: 11.3.3(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))
- vite-plugin-vue-inspector: 5.4.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3))
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)
+ vite-plugin-inspect: 11.3.3(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))
+ vite-plugin-vue-inspector: 5.4.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3))
transitivePeerDependencies:
- '@nuxt/kit'
- supports-color
- vue
- vite-plugin-vue-inspector@5.4.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)):
+ vite-plugin-vue-inspector@5.4.0(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)):
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0)
@@ -3072,11 +3262,11 @@ snapshots:
'@vue/compiler-dom': 3.5.33
kolorist: 1.8.0
magic-string: 0.30.21
- vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3)
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3)
transitivePeerDependencies:
- supports-color
- vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(yaml@2.8.3):
+ vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)(sass@1.99.0)(yaml@2.8.3):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
@@ -3087,6 +3277,7 @@ snapshots:
'@types/node': 24.12.2
fsevents: 2.3.3
jiti: 2.6.1
+ sass: 1.99.0
yaml: 2.8.3
vscode-uri@3.1.0: {}
diff --git a/frontend/public/index.css b/frontend/public/index.css
deleted file mode 100644
index e69de29..0000000
diff --git a/frontend/public/index.scss b/frontend/public/index.scss
new file mode 100644
index 0000000..c59666b
--- /dev/null
+++ b/frontend/public/index.scss
@@ -0,0 +1,2 @@
+// 导入 Bulma
+@use "bulma/sass"
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 70a5f02..356f88c 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -1,4 +1,9 @@
-
+
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index fda1e6e..16055ff 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -4,6 +4,8 @@ import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
+import '../public/index.scss'
+
const app = createApp(App)
app.use(createPinia())
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index 7476e89..6046901 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -6,7 +6,7 @@ import Calendar from '@/views/Calendar.vue'
import Todo from '@/views/Todo.vue'
import Admin from '@/views/Admin.vue'
-import Page404 from '@/views/Page404.vue'
+import NotFound from '@/views/NotFound.vue'
const routes = [
{ path: '/home', component: Home },
@@ -15,7 +15,7 @@ const routes = [
{ path: '/todo', component: Todo},
{ path: '/admin', component: Admin },
- { path: '/404', component: Page404 },
+ { path: '/404', component: NotFound },
{ path: '/', redirect: '/home' },
{ path: '/:pathMatch(.*)*', redirect: '/404' },
diff --git a/frontend/src/stores/counter.ts b/frontend/src/stores/counter.ts
deleted file mode 100644
index b6757ba..0000000
--- a/frontend/src/stores/counter.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { ref, computed } from 'vue'
-import { defineStore } from 'pinia'
-
-export const useCounterStore = defineStore('counter', () => {
- const count = ref(0)
- const doubleCount = computed(() => count.value * 2)
- function increment() {
- count.value++
- }
-
- return { count, doubleCount, increment }
-})
diff --git a/frontend/src/stores/global.ts b/frontend/src/stores/global.ts
new file mode 100644
index 0000000..e36064d
--- /dev/null
+++ b/frontend/src/stores/global.ts
@@ -0,0 +1,26 @@
+import { ref, computed } from 'vue'
+import { defineStore } from 'pinia'
+import { Language } from '@/utils/i18n'
+
+export const useLanguageStore = defineStore('language', {
+ state: () => ({
+ language: Language.English
+ }),
+
+ getters: {
+ isEnglish: (state) => state.language === Language.English,
+ isSimplifiedChinese: (state) => state.language === Language.SimplifiedChinese,
+ },
+
+ actions: {
+ changeLanguage(lang: Language) {
+ this.language = lang;
+ },
+ changeToEnglish() {
+ this.changeLanguage(Language.English);
+ },
+ changeToSimplifiedChinese() {
+ this.changeLanguage(Language.SimplifiedChinese);
+ },
+ },
+})
diff --git a/frontend/src/utils/i18n.ts b/frontend/src/utils/i18n.ts
new file mode 100644
index 0000000..2ba58a3
--- /dev/null
+++ b/frontend/src/utils/i18n.ts
@@ -0,0 +1,4 @@
+export enum Language {
+ English,
+ SimplifiedChinese,
+}
diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue
index fad9719..9f75cb4 100644
--- a/frontend/src/views/Home.vue
+++ b/frontend/src/views/Home.vue
@@ -1,8 +1,20 @@
- Congratulations
- This is home.
+
+
+ coconut-leaf
+ A light, self-host and multi-account calendar system.
+ The original intention of this system is served for yyc12345 personal use.
+
+ See our GitHub project for the source code in detail.
+ The source code of this project is licensed under AGPL v3.
+
+
-
+
diff --git a/frontend/src/views/NotFound.vue b/frontend/src/views/NotFound.vue
new file mode 100644
index 0000000..96f83fe
--- /dev/null
+++ b/frontend/src/views/NotFound.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+ Oops!
+ You are wandering in the desert of coconut-leaf.
+ Please back to previous page and try again.
+
+
+
+
+
diff --git a/frontend/src/views/Page404.vue b/frontend/src/views/Page404.vue
deleted file mode 100644
index 680beb5..0000000
--- a/frontend/src/views/Page404.vue
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
- Congratulations
- 404 Not Found
-
-
-
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 6a5e119..d35b356 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -33,5 +33,6 @@ export default defineConfig({
rewrite: (path) => path.replace(/^\/api\//, '/'),
}
},
-
+ },
+
})