From 5c06c7ce0ad56c5696e0d20179ab5800d5a07caf Mon Sep 17 00:00:00 2001 From: Seven Date: Sat, 20 Dec 2025 03:48:01 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auto-imports.d.ts | 5 + src/components/ui/tabs/index.vue | 2 +- src/composables/useTheme.ts | 26 ++++ src/locales/en-US.json | 7 +- src/locales/zh-CN.json | 7 +- src/main.ts | 4 +- src/router/index.ts | 4 + src/theme/ionic.css | 7 +- src/theme/variables.css | 118 +++++++++--------- src/views/market/components/category.vue | 2 +- src/views/onchain-address/index.vue | 2 +- src/views/system-settings/index.vue | 23 +++- src/views/system-settings/theme.vue | 57 +++++++++ .../trade-settings/bank-management/add.vue | 2 +- 14 files changed, 196 insertions(+), 70 deletions(-) create mode 100644 src/composables/useTheme.ts create mode 100644 src/views/system-settings/theme.vue diff --git a/auto-imports.d.ts b/auto-imports.d.ts index ad9616b..45d5ebe 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -281,6 +281,7 @@ declare global { const useTextDirection: typeof import('@vueuse/core').useTextDirection const useTextSelection: typeof import('@vueuse/core').useTextSelection const useTextareaAutosize: typeof import('@vueuse/core').useTextareaAutosize + const useTheme: typeof import('./src/composables/useTheme').useTheme const useThrottle: typeof import('@vueuse/core').useThrottle const useThrottleFn: typeof import('@vueuse/core').useThrottleFn const useThrottledRefHistory: typeof import('@vueuse/core').useThrottledRefHistory @@ -340,6 +341,9 @@ declare global { export type { QRScanResult } from './src/composables/useQRScanner' import('./src/composables/useQRScanner') // @ts-ignore + export type { ThemeMode } from './src/composables/useTheme' + import('./src/composables/useTheme') + // @ts-ignore export type { Series, TData, WeightChartOptions, TradingViewData, TradingViewOptions } from './src/composables/useTradingView' import('./src/composables/useTradingView') // @ts-ignore @@ -628,6 +632,7 @@ declare module 'vue' { readonly useTextDirection: UnwrapRef readonly useTextSelection: UnwrapRef readonly useTextareaAutosize: UnwrapRef + readonly useTheme: UnwrapRef readonly useThrottle: UnwrapRef readonly useThrottleFn: UnwrapRef readonly useThrottledRefHistory: UnwrapRef diff --git a/src/components/ui/tabs/index.vue b/src/components/ui/tabs/index.vue index d0c1cef..708f0f3 100644 --- a/src/components/ui/tabs/index.vue +++ b/src/components/ui/tabs/index.vue @@ -592,7 +592,7 @@ const stickyStyle = computed(() => { } /* Dark mode 支持 */ -@media (prefers-color-scheme: dark) { +.ion-palette-dark { .ui-tabs { --ui-tabs-primary: var(--ion-color-primary, #ffffff); --ui-tabs-primary-rgb: var(--ion-color-primary-rgb, 255, 255, 255); diff --git a/src/composables/useTheme.ts b/src/composables/useTheme.ts new file mode 100644 index 0000000..39fc55a --- /dev/null +++ b/src/composables/useTheme.ts @@ -0,0 +1,26 @@ +import { usePreferredDark } from "@vueuse/core"; + +export type ThemeMode = "light" | "dark" | "auto"; + +const STORAGE_KEY = "app-theme-mode"; + +export function useTheme() { + const prefersDark = usePreferredDark(); + const theme = useStorage(STORAGE_KEY, "auto"); + + const isDark = computed(() => { + if (theme.value === "auto") { + return prefersDark.value; + } + return theme.value === "dark"; + }); + + watch(isDark, (dark) => { + document.documentElement.classList.toggle("ion-palette-dark", dark); + }, { immediate: true }); + + return { + theme, + isDark, + }; +} diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 8ef02d3..e3a728c 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -315,6 +315,11 @@ "updateNow": "Update Now", "alreadyLatest": "Already up to date", "checkUpdateFailed": "Failed to check for updates", - "languageTitle": "Language / 语言" + "languageTitle": "Language / 语言", + "theme": "Theme", + "themeTitle": "Appearance", + "themeLight": "Light", + "themeDark": "Dark", + "themeAuto": "Auto" } } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 284dbf6..7eb28bf 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -315,6 +315,11 @@ "updateNow": "立即更新", "alreadyLatest": "已是最新版本", "checkUpdateFailed": "检查更新失败", - "languageTitle": "语言 / Language" + "languageTitle": "语言 / Language", + "theme": "主题", + "themeTitle": "外观主题", + "themeLight": "浅色", + "themeDark": "深色", + "themeAuto": "跟随系统" } } diff --git a/src/main.ts b/src/main.ts index 48f1b0e..2b200fd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -31,8 +31,8 @@ import "@ionic/vue/css/display.css"; */ // import "@ionic/vue/css/palettes/dark.always.css"; -// import "@ionic/vue/css/palettes/dark.class.css"; -import "@ionic/vue/css/palettes/dark.system.css"; +import "@ionic/vue/css/palettes/dark.class.css"; +// import "@ionic/vue/css/palettes/dark.system.css"; /* Theme variables */ import "./theme/index.css"; diff --git a/src/router/index.ts b/src/router/index.ts index a65a08e..293c303 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -65,6 +65,10 @@ const routes: Array = [ path: "language", component: () => import("@/views/system-settings/language.vue"), }, + { + path: "theme", + component: () => import("@/views/system-settings/theme.vue"), + }, ], }, { diff --git a/src/theme/ionic.css b/src/theme/ionic.css index 89d5e0c..e27f352 100644 --- a/src/theme/ionic.css +++ b/src/theme/ionic.css @@ -24,7 +24,7 @@ ion-datetime.ui-datetime { border-radius: 16px; overflow: hidden; } -@media (prefers-color-scheme: dark) { +.ion-palette-dark { ion-datetime.ui-datetime { --background: rgb(15, 15, 15); --background-rgb: 15, 15, 15; @@ -32,4 +32,9 @@ ion-datetime.ui-datetime { --wheel-highlight-border-radius: 48px; --wheel-fade-background-rgb: 15, 15, 15; } +} + +:root.ios { + --ion-padding: 20px; + --ion-margin: 20px; } \ No newline at end of file diff --git a/src/theme/variables.css b/src/theme/variables.css index 4e8beb5..6840670 100644 --- a/src/theme/variables.css +++ b/src/theme/variables.css @@ -1,6 +1,6 @@ /* For information on how to create your own theme, please refer to: http://ionicframework.com/docs/theming/ */ -:root { +html:root { --ion-color-primary: #0d0d0d; --ion-color-primary-rgb: 13, 13, 13; --ion-color-primary-contrast: #ffffff; @@ -120,72 +120,70 @@ http://ionicframework.com/docs/theming/ */ --ui-background-primary: linear-gradient(180deg, #615fff 0%, #9810fa 100%); } -@media (prefers-color-scheme: dark) { - :root { - --ion-color-primary: #ffffff; - --ion-color-primary-rgb: 255, 255, 255; - --ion-color-primary-contrast: #000000; - --ion-color-primary-contrast-rgb: 0, 0, 0; - --ion-color-primary-shade: #e0e0e0; - --ion-color-primary-tint: #ffffff; +html.ion-palette-dark { + --ion-color-primary: #ffffff; + --ion-color-primary-rgb: 255, 255, 255; + --ion-color-primary-contrast: #000000; + --ion-color-primary-contrast-rgb: 0, 0, 0; + --ion-color-primary-shade: #e0e0e0; + --ion-color-primary-tint: #ffffff; - --ion-color-secondary: #ededed; - --ion-color-secondary-rgb: 237, 237, 237; - --ion-color-secondary-contrast: #000000; - --ion-color-secondary-contrast-rgb: 0, 0, 0; - --ion-color-secondary-shade: #d1d1d1; - --ion-color-secondary-tint: #efefef; + --ion-color-secondary: #ededed; + --ion-color-secondary-rgb: 237, 237, 237; + --ion-color-secondary-contrast: #000000; + --ion-color-secondary-contrast-rgb: 0, 0, 0; + --ion-color-secondary-shade: #d1d1d1; + --ion-color-secondary-tint: #efefef; - --ion-color-tertiary: #d6d6d6; - --ion-color-tertiary-rgb: 214, 214, 214; - --ion-color-tertiary-contrast: #000000; - --ion-color-tertiary-contrast-rgb: 0, 0, 0; - --ion-color-tertiary-shade: #bcbcbc; - --ion-color-tertiary-tint: #dadada; + --ion-color-tertiary: #d6d6d6; + --ion-color-tertiary-rgb: 214, 214, 214; + --ion-color-tertiary-contrast: #000000; + --ion-color-tertiary-contrast-rgb: 0, 0, 0; + --ion-color-tertiary-shade: #bcbcbc; + --ion-color-tertiary-tint: #dadada; - --ion-color-success: #2dd55b; - --ion-color-success-rgb: 45, 213, 91; - --ion-color-success-contrast: #000000; - --ion-color-success-contrast-rgb: 0, 0, 0; - --ion-color-success-shade: #28bb50; - --ion-color-success-tint: #42d96b; + --ion-color-success: #2dd55b; + --ion-color-success-rgb: 45, 213, 91; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0, 0, 0; + --ion-color-success-shade: #28bb50; + --ion-color-success-tint: #42d96b; - --ion-color-warning: #ffc409; - --ion-color-warning-rgb: 255, 196, 9; - --ion-color-warning-contrast: #000000; - --ion-color-warning-contrast-rgb: 0, 0, 0; - --ion-color-warning-shade: #e0ac08; - --ion-color-warning-tint: #ffca22; + --ion-color-warning: #ffc409; + --ion-color-warning-rgb: 255, 196, 9; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0ac08; + --ion-color-warning-tint: #ffca22; - --ion-color-danger: #ff3344; - --ion-color-danger-rgb: 255,51,68; - --ion-color-danger-contrast: #000000; - --ion-color-danger-contrast-rgb: 0,0,0; - --ion-color-danger-shade: #e02d3c; - --ion-color-danger-tint: #ff4757; + --ion-color-danger: #ff3344; + --ion-color-danger-rgb: 255,51,68; + --ion-color-danger-contrast: #000000; + --ion-color-danger-contrast-rgb: 0,0,0; + --ion-color-danger-shade: #e02d3c; + --ion-color-danger-tint: #ff4757; - --ion-color-light: #f6f8fc; - --ion-color-light-rgb: 246, 248, 252; - --ion-color-light-contrast: #000000; - --ion-color-light-contrast-rgb: 0, 0, 0; - --ion-color-light-shade: #d8dade; - --ion-color-light-tint: #f7f9fc; + --ion-color-light: #f6f8fc; + --ion-color-light-rgb: 246, 248, 252; + --ion-color-light-contrast: #000000; + --ion-color-light-contrast-rgb: 0, 0, 0; + --ion-color-light-shade: #d8dade; + --ion-color-light-tint: #f7f9fc; - --ion-color-medium: #5f5f5f; - --ion-color-medium-rgb: 95, 95, 95; - --ion-color-medium-contrast: #ffffff; - --ion-color-medium-contrast-rgb: 255, 255, 255; - --ion-color-medium-shade: #545454; - --ion-color-medium-tint: #6f6f6f; + --ion-color-medium: #5f5f5f; + --ion-color-medium-rgb: 95, 95, 95; + --ion-color-medium-contrast: #ffffff; + --ion-color-medium-contrast-rgb: 255, 255, 255; + --ion-color-medium-shade: #545454; + --ion-color-medium-tint: #6f6f6f; - --ion-color-dark: #2f2f2f; - --ion-color-dark-rgb: 47, 47, 47; - --ion-color-dark-contrast: #ffffff; - --ion-color-dark-contrast-rgb: 255, 255, 255; - --ion-color-dark-shade: #292929; - --ion-color-dark-tint: #444444; + --ion-color-dark: #2f2f2f; + --ion-color-dark-rgb: 47, 47, 47; + --ion-color-dark-contrast: #ffffff; + --ion-color-dark-contrast-rgb: 255, 255, 255; + --ion-color-dark-shade: #292929; + --ion-color-dark-tint: #444444; - --ui-input-background: #1e1e1e; - --ui-input-color: #ffffff; - } + --ui-input-background: #1e1e1e; + --ui-input-color: #ffffff; } diff --git a/src/views/market/components/category.vue b/src/views/market/components/category.vue index 9922dce..ca1a512 100644 --- a/src/views/market/components/category.vue +++ b/src/views/market/components/category.vue @@ -36,7 +36,7 @@ ion-content::part(scroll) { .item { @apply px-3 py-1 rounded-full text-xs transition-all; } -@media (prefers-color-scheme: dark) { +.ion-palette-dark { .item { @apply bg-(--ion-color-step-800); } diff --git a/src/views/onchain-address/index.vue b/src/views/onchain-address/index.vue index 8c35e60..a4c9cdc 100644 --- a/src/views/onchain-address/index.vue +++ b/src/views/onchain-address/index.vue @@ -68,7 +68,7 @@ const { user } = useAuth(); --background: #f4f6f8; --border-color: #c6c5c5; } -@media (prefers-color-scheme: dark) { +.ion-palette-dark { .content-wrapper { --background: #232324; --border-color: #3a3a3b; diff --git a/src/views/system-settings/index.vue b/src/views/system-settings/index.vue index 38f5023..30620ee 100644 --- a/src/views/system-settings/index.vue +++ b/src/views/system-settings/index.vue @@ -1,12 +1,18 @@ + + + + diff --git a/src/views/trade-settings/bank-management/add.vue b/src/views/trade-settings/bank-management/add.vue index f485dcd..1731bcd 100644 --- a/src/views/trade-settings/bank-management/add.vue +++ b/src/views/trade-settings/bank-management/add.vue @@ -178,7 +178,7 @@ function formatCardNumber(value: string) { border-color: #ef4444; } -@media (prefers-color-scheme: dark) { +.ion-palette-dark { .ui-select { border-color: #4b5563; }