From 618bcdaae19fdddd64b2209f973d059c7739da07 Mon Sep 17 00:00:00 2001 From: Tim Hsu Date: Wed, 25 Jun 2025 11:56:47 +0800 Subject: [PATCH 01/33] docs: add ads.txt file - Add ads.txt file for Google AdSense Signed-off-by: Tim Hsu --- public/ads.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 public/ads.txt diff --git a/public/ads.txt b/public/ads.txt new file mode 100644 index 0000000..b3607a6 --- /dev/null +++ b/public/ads.txt @@ -0,0 +1 @@ +google.com, pub-1617900048851450, DIRECT, f08c47fec0942fa0 From b8424ee54489804a5779a6858c79feda028d2d1c Mon Sep 17 00:00:00 2001 From: Tim Hsu Date: Wed, 25 Jun 2025 13:38:52 +0800 Subject: [PATCH 02/33] feat: introduce FontAwesome icons and account management page - Add fontawesome dependencies. - Modify the import order in the prettier config. - Move import statements to the top of the file in several API files. - Add fontawesome to the menu items. - Use the fontawesome icon component in the menu. - Add several translation keys. - Initialize fontawesome. - Modify the 404 page. - Move import statements to the top of the file in several page files. - Create a new account management page. Signed-off-by: Tim Hsu --- package.json | 3 + pnpm-lock.yaml | 42 ++ prettier.config.mjs | 2 +- src/apis/client.ts | 3 +- src/apis/system/backup.ts | 3 +- src/apis/user/user.ts | 3 +- .../dialog/DialogChangePassword.vue | 3 +- src/components/home/HomeEvent.vue | 5 +- src/components/layouts/AppMenu.vue | 12 +- src/components/layouts/AppMenuItem.vue | 4 +- src/locales/us.json | 30 +- src/locales/zh_tw.json | 28 +- src/main.ts | 8 + src/pages/[...path].vue | 87 ++-- src/pages/index.vue | 5 +- src/pages/realtime/future.vue | 3 +- src/pages/system/account.vue | 423 ++++++++++++++++++ src/utils/jwt.ts | 3 +- typed-router.d.ts | 1 + 19 files changed, 594 insertions(+), 74 deletions(-) create mode 100644 src/pages/system/account.vue diff --git a/package.json b/package.json index 6df36bd..99a4379 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,9 @@ "dependencies": { "@chindada/panther": "github:chindada/panther#v1.0", "@fontsource/roboto-mono": "^5.2.6", + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", + "@fortawesome/vue-fontawesome": "^3.0.8", "@primeuix/themes": "^1.1.2", "@primevue/core": "^4.3.5", "@primevue/forms": "^4.3.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6146ba4..84cc8b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,15 @@ importers: '@fontsource/roboto-mono': specifier: ^5.2.6 version: 5.2.6 + '@fortawesome/fontawesome-svg-core': + specifier: ^6.7.2 + version: 6.7.2 + '@fortawesome/free-solid-svg-icons': + specifier: ^6.7.2 + version: 6.7.2 + '@fortawesome/vue-fontawesome': + specifier: ^3.0.8 + version: 3.0.8(@fortawesome/fontawesome-svg-core@6.7.2)(vue@3.5.17(typescript@5.8.3)) '@primeuix/themes': specifier: ^1.1.2 version: 1.1.2 @@ -779,6 +788,24 @@ packages: '@fontsource/roboto-mono@5.2.6': resolution: {integrity: sha512-fLCa3zs9XruKE8Fdbq0UWB0wqTi5dzi09QsnW7HgTwwnSVDZ3nH+X7Qg7l0yeIZs+E472cKE3RUD21ZnaXk4Zg==} + '@fortawesome/fontawesome-common-types@6.7.2': + resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==} + engines: {node: '>=6'} + + '@fortawesome/fontawesome-svg-core@6.7.2': + resolution: {integrity: sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==} + engines: {node: '>=6'} + + '@fortawesome/free-solid-svg-icons@6.7.2': + resolution: {integrity: sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==} + engines: {node: '>=6'} + + '@fortawesome/vue-fontawesome@3.0.8': + resolution: {integrity: sha512-yyHHAj4G8pQIDfaIsMvQpwKMboIZtcHTUvPqXjOHyldh1O1vZfH4W03VDPv5RvI9P6DLTzJQlmVgj9wCf7c2Fw==} + peerDependencies: + '@fortawesome/fontawesome-svg-core': ~1 || ~6 + vue: '>= 3.0.0 < 4' + '@grpc/grpc-js@1.9.15': resolution: {integrity: sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==} engines: {node: ^8.13.0 || >=10.10.0} @@ -4064,6 +4091,21 @@ snapshots: '@fontsource/roboto-mono@5.2.6': {} + '@fortawesome/fontawesome-common-types@6.7.2': {} + + '@fortawesome/fontawesome-svg-core@6.7.2': + dependencies: + '@fortawesome/fontawesome-common-types': 6.7.2 + + '@fortawesome/free-solid-svg-icons@6.7.2': + dependencies: + '@fortawesome/fontawesome-common-types': 6.7.2 + + '@fortawesome/vue-fontawesome@3.0.8(@fortawesome/fontawesome-svg-core@6.7.2)(vue@3.5.17(typescript@5.8.3))': + dependencies: + '@fortawesome/fontawesome-svg-core': 6.7.2 + vue: 3.5.17(typescript@5.8.3) + '@grpc/grpc-js@1.9.15': dependencies: '@grpc/proto-loader': 0.7.15 diff --git a/prettier.config.mjs b/prettier.config.mjs index c3075c0..91fd6d2 100644 --- a/prettier.config.mjs +++ b/prettier.config.mjs @@ -7,7 +7,7 @@ const config = { tabWidth: 2, trailingComma: "none", useTabs: false, - importOrder: ["^@/(.*)$", "^@mold-link/(.*)$", "^[./]"], + importOrder: ["^@/(.*)$", "^@chindada/(.*)$", "^[./]"], importOrderSeparation: true, importOrderSortSpecifiers: true, tailwindConfig: "tailwind.config.cjs" diff --git a/src/apis/client.ts b/src/apis/client.ts index 7a82386..5b038c7 100644 --- a/src/apis/client.ts +++ b/src/apis/client.ts @@ -1,8 +1,9 @@ -import { APIResponse } from "@chindada/panther/typescript/system/api"; import axios from "axios"; import router from "@/router"; +import { APIResponse } from "@chindada/panther/typescript/system/api"; + const httpClient = axios.create({ responseType: "arraybuffer", headers: { diff --git a/src/apis/system/backup.ts b/src/apis/system/backup.ts index 4322f10..9ba6772 100644 --- a/src/apis/system/backup.ts +++ b/src/apis/system/backup.ts @@ -1,6 +1,7 @@ -import { Backup, BackupList } from "@chindada/panther/typescript/system/backup"; import type { AxiosRequestConfig } from "axios"; +import { Backup, BackupList } from "@chindada/panther/typescript/system/backup"; + import httpClient from "../client"; import path from "../path"; diff --git a/src/apis/user/user.ts b/src/apis/user/user.ts index 1f67da8..c045370 100644 --- a/src/apis/user/user.ts +++ b/src/apis/user/user.ts @@ -1,6 +1,7 @@ +import type { AxiosRequestConfig } from "axios"; + import { ChangePasswordRequest } from "@chindada/panther/typescript/system/api"; import { BasicUser, User, UserList } from "@chindada/panther/typescript/system/user"; -import type { AxiosRequestConfig } from "axios"; import httpClient from "../client"; import path from "../path"; diff --git a/src/components/dialog/DialogChangePassword.vue b/src/components/dialog/DialogChangePassword.vue index 23786bc..5518daa 100644 --- a/src/components/dialog/DialogChangePassword.vue +++ b/src/components/dialog/DialogChangePassword.vue @@ -1,5 +1,4 @@ diff --git a/src/components/layouts/AppMenuItem.vue b/src/components/layouts/AppMenuItem.vue index 5df168d..86f6649 100644 --- a/src/components/layouts/AppMenuItem.vue +++ b/src/components/layouts/AppMenuItem.vue @@ -94,7 +94,7 @@ function checkActiveRoute(item: Record) { :target="item.target" @click="itemClick($event, item)" > - + {{ item.label }} @@ -105,7 +105,7 @@ function checkActiveRoute(item: Record) { :to="item.to" @click="itemClick($event, item)" > - + {{ item.label }} diff --git a/src/locales/us.json b/src/locales/us.json index 3078df3..ff58570 100644 --- a/src/locales/us.json +++ b/src/locales/us.json @@ -1,11 +1,20 @@ { + "account_management": "Account Management", + "are_you_sure_to_delete": "Are you sure to delete", "cancel": "Cancel", "change": "Change", "change_password": "Change Password", + "confirm": "Confirm", "confirm_new_password": "Confirm new password", "confirm_password_is_not_same_as_password": "Confirm password is not same as password", "core": "Core", + "create": "New", + "created": "Created", + "delete": "Delete", + "deleted": "Deleted", "disk_usage": "Disk Usage", + "edit": "Edit", + "email": "Email", "enter_new_password": "Enter new password", "enter_old_password": "Enter old password", "error": "Error", @@ -17,17 +26,34 @@ "login_success": "Login success", "logout": "Logout", "new_password": "New password", + "no": "No", + "no_data": "No data", "not_found": "Not found", "old_password": "Old password", "password_changed": "Password changed", "password_minimum_length_is_8": "Password minimum length is 8", + "please_select": "Please select", "realtime": "Realtime", + "role": "Role", + "role_admin": "Admin", + "role_root": "Root", + "role_user": "User", + "save": "Save", + "search": "Search", + "show": "Show", "success": "Success", + "system": "System", "system_event": "System Event", "system_version": "System Version", - "unknown_user": "Unknown user", + "to": "To", + "total": "Total", + "unknown_user": "Unknown User", + "updated": "Updated", "uptime": "Uptime", "user": "User", + "username": "Username", + "username_minimum_length_is_8": "Username minimum length is 8", "warning": "Warning", - "web": "Web" + "web": "Web", + "yes": "Yes" } diff --git a/src/locales/zh_tw.json b/src/locales/zh_tw.json index 44bf51e..5bffefa 100644 --- a/src/locales/zh_tw.json +++ b/src/locales/zh_tw.json @@ -1,11 +1,20 @@ { + "account_management": "帳號管理", + "are_you_sure_to_delete": "確定要刪除", "cancel": "取消", "change": "修改", "change_password": "修改密碼", + "confirm": "確認", "confirm_new_password": "確認新密碼", "confirm_password_is_not_same_as_password": "確認密碼與密碼不相同", "core": "核心", + "create": "新增", + "created": "新增", + "delete": "刪除", + "deleted": "已刪除", "disk_usage": "磁碟使用量", + "edit": "編輯", + "email": "電子郵件", "enter_new_password": "輸入新密碼", "enter_old_password": "輸入舊密碼", "error": "錯誤", @@ -17,17 +26,34 @@ "login_success": "登入成功", "logout": "登出", "new_password": "新密碼", + "no": "否", + "no_data": "無資料", "not_found": "找不到", "old_password": "舊密碼", "password_changed": "密碼已修改", "password_minimum_length_is_8": "密碼最少 8 個字元", + "please_select": "請選擇", "realtime": "即時", + "role": "角色", + "role_admin": "管理員", + "role_root": "超級管理員", + "role_user": "使用者", + "save": "儲存", + "search": "搜尋", + "show": "顯示", "success": "成功", + "system": "系統", "system_event": "系統事件", "system_version": "系統版本", + "to": "至", + "total": "總計", "unknown_user": "未知使用者", + "updated": "更新", "uptime": "運行時間", "user": "使用者", + "username": "帳號", + "username_minimum_length_is_8": "帳號最少 8 個字元", "warning": "警告", - "web": "網頁" + "web": "網頁", + "yes": "是" } diff --git a/src/main.ts b/src/main.ts index 2eb28da..9fc85f5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,6 @@ +import { library } from "@fortawesome/fontawesome-svg-core"; +import { faChartLine, faUsers } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { definePreset } from "@primeuix/themes"; import Aura from "@primeuix/themes/aura"; import { createPinia } from "pinia"; @@ -18,8 +21,13 @@ import App from "./App.vue"; import useFirebase from "./firebase"; import router from "./router"; +library.add(faUsers, faChartLine); + const app = createApp(App); +// add font awesome icon component +app.component("FontAwesomeIcon", FontAwesomeIcon); + // use pinia app.use(createPinia()); diff --git a/src/pages/[...path].vue b/src/pages/[...path].vue index 90ee91a..22429fe 100644 --- a/src/pages/[...path].vue +++ b/src/pages/[...path].vue @@ -1,76 +1,49 @@ diff --git a/src/pages/index.vue b/src/pages/index.vue index 24f3d80..585608f 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -1,6 +1,4 @@ + + diff --git a/src/utils/jwt.ts b/src/utils/jwt.ts index 7ccc4e0..6e3d221 100644 --- a/src/utils/jwt.ts +++ b/src/utils/jwt.ts @@ -1,6 +1,7 @@ -import { UserRole } from "@chindada/panther/typescript/system/user"; import { jwtDecode } from "jwt-decode"; +import { UserRole } from "@chindada/panther/typescript/system/user"; + interface JWToken { role: string; username: string; diff --git a/typed-router.d.ts b/typed-router.d.ts index ad1b827..9ee3a13 100644 --- a/typed-router.d.ts +++ b/typed-router.d.ts @@ -22,5 +22,6 @@ declare module 'vue-router/auto-routes' { '/[...path]': RouteRecordInfo<'/[...path]', '/:path(.*)', { path: ParamValue }, { path: ParamValue }>, '/login': RouteRecordInfo<'/login', '/login', Record, Record>, '/realtime/future': RouteRecordInfo<'/realtime/future', '/realtime/future', Record, Record>, + '/system/account': RouteRecordInfo<'/system/account', '/system/account', Record, Record>, } } From 4f2f39ece92dc6c017a0b69a2a8cbe354ec8b8dd Mon Sep 17 00:00:00 2001 From: Tim Hsu Date: Wed, 25 Jun 2025 17:51:20 +0800 Subject: [PATCH 03/33] feat: improve realtime futures bid/ask display - Create a BidAsk component for displaying bid and ask prices. - Use the BidAsk component in RealtimeFutures to display bid and ask data. - Improve the layout and styling of the RealtimeFutures component. Signed-off-by: Tim Hsu --- src/components/realtime/BidAsk.vue | 80 +++++++++++++++++++++ src/components/realtime/RealtimeFutures.vue | 9 +-- 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 src/components/realtime/BidAsk.vue diff --git a/src/components/realtime/BidAsk.vue b/src/components/realtime/BidAsk.vue new file mode 100644 index 0000000..93a17c3 --- /dev/null +++ b/src/components/realtime/BidAsk.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/components/realtime/RealtimeFutures.vue b/src/components/realtime/RealtimeFutures.vue index 000b903..37f3a28 100644 --- a/src/components/realtime/RealtimeFutures.vue +++ b/src/components/realtime/RealtimeFutures.vue @@ -13,13 +13,14 @@ const futuresArray = computed(() => {