mirror of
https://github.com/ayangweb/BongoCat.git
synced 2026-03-12 17:51:48 +08:00
feat: 新增「通用设置 > 外观设置 > 主题模式」配置项 (#583)
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"core:window:allow-set-ignore-cursor-events",
|
||||
"core:window:allow-set-decorations",
|
||||
"core:window:allow-set-position",
|
||||
"core:window:allow-set-theme",
|
||||
"custom-window:default",
|
||||
"os:default",
|
||||
"process:default",
|
||||
|
||||
10
src/App.vue
10
src/App.vue
@@ -3,7 +3,7 @@ import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { error } from '@tauri-apps/plugin-log'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
import { ConfigProvider } from 'ant-design-vue'
|
||||
import { ConfigProvider, theme } from 'ant-design-vue'
|
||||
import zhCN from 'ant-design-vue/es/locale/zh_CN'
|
||||
import { isString } from 'es-toolkit'
|
||||
import isURL from 'is-url'
|
||||
@@ -29,6 +29,7 @@ const generalStore = useGeneralStore()
|
||||
const shortcutStore = useShortcutStore()
|
||||
const appWindow = getCurrentWebviewWindow()
|
||||
const { isRestored, restoreState } = useWindowState()
|
||||
const { darkAlgorithm, defaultAlgorithm } = theme
|
||||
|
||||
onMounted(async () => {
|
||||
generateColorVars()
|
||||
@@ -79,7 +80,12 @@ useEventListener('click', (event) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfigProvider :locale="zhCN">
|
||||
<ConfigProvider
|
||||
:locale="zhCN"
|
||||
:theme="{
|
||||
algorithm: generalStore.appearance.isDark ? darkAlgorithm : defaultAlgorithm,
|
||||
}"
|
||||
>
|
||||
<RouterView v-if="isRestored" />
|
||||
</ConfigProvider>
|
||||
</template>
|
||||
|
||||
@@ -18,7 +18,7 @@ const hasDescription = computed(() => {
|
||||
<template>
|
||||
<Flex
|
||||
:align="vertical ? void 0 : 'center'"
|
||||
class="b b-color-2 rounded-lg b-solid bg-white p-4"
|
||||
class="b b-color-2 rounded-lg b-solid bg-color-3 p-4"
|
||||
gap="middle"
|
||||
justify="space-between"
|
||||
:vertical="vertical"
|
||||
|
||||
@@ -4,7 +4,7 @@ import { PhysicalSize } from '@tauri-apps/api/dpi'
|
||||
import { Menu } from '@tauri-apps/api/menu'
|
||||
import { sep } from '@tauri-apps/api/path'
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { exists } from '@tauri-apps/plugin-fs'
|
||||
import { exists, readDir } from '@tauri-apps/plugin-fs'
|
||||
import { useDebounceFn, useEventListener } from '@vueuse/core'
|
||||
import { nth } from 'es-toolkit/compat'
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
@@ -17,7 +17,9 @@ import { hideWindow, setAlwaysOnTop, setTaskbarVisibility, showWindow } from '@/
|
||||
import { useCatStore } from '@/stores/cat'
|
||||
import { useGeneralStore } from '@/stores/general.ts'
|
||||
import { useModelStore } from '@/stores/model'
|
||||
import { isImage } from '@/utils/is'
|
||||
import { join } from '@/utils/path'
|
||||
import { clearObject } from '@/utils/shared'
|
||||
|
||||
const { startListening } = useDevice()
|
||||
const appWindow = getCurrentWebviewWindow()
|
||||
@@ -47,15 +49,32 @@ useEventListener('resize', () => {
|
||||
})
|
||||
|
||||
watch(() => modelStore.currentModel, async (model) => {
|
||||
handleLoad()
|
||||
|
||||
if (!model) return
|
||||
|
||||
handleLoad()
|
||||
|
||||
const path = join(model.path, 'resources', 'background.png')
|
||||
|
||||
const existed = await exists(path)
|
||||
|
||||
backgroundImagePath.value = existed ? convertFileSrc(path) : void 0
|
||||
|
||||
clearObject([modelStore.supportKeys, modelStore.pressedKeys])
|
||||
|
||||
const resourcePath = join(model.path, 'resources')
|
||||
const groups = ['left-keys', 'right-keys']
|
||||
|
||||
for await (const groupName of groups) {
|
||||
const groupDir = join(resourcePath, groupName)
|
||||
const files = await readDir(groupDir).catch(() => [])
|
||||
const imageFiles = files.filter(file => isImage(file.name))
|
||||
|
||||
for (const file of imageFiles) {
|
||||
const fileName = file.name.split('.')[0]
|
||||
|
||||
modelStore.supportKeys[fileName] = join(groupDir, file.name)
|
||||
}
|
||||
}
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
watch([() => catStore.scale, modelSize], async () => {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<script setup lang="ts">
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { Select, SelectOption } from 'ant-design-vue'
|
||||
import { onMounted, watch } from 'vue'
|
||||
|
||||
import ProListItem from '@/components/pro-list-item/index.vue'
|
||||
import { useGeneralStore } from '@/stores/general'
|
||||
|
||||
const generalStore = useGeneralStore()
|
||||
const appWindow = getCurrentWebviewWindow()
|
||||
|
||||
onMounted(() => {
|
||||
appWindow.onThemeChanged(async ({ payload }) => {
|
||||
if (generalStore.appearance.theme !== 'auto') return
|
||||
|
||||
generalStore.appearance.isDark = payload === 'dark'
|
||||
})
|
||||
})
|
||||
|
||||
watch(() => generalStore.appearance.theme, async (value) => {
|
||||
let nextTheme = value === 'auto' ? null : value
|
||||
|
||||
await appWindow.setTheme(nextTheme)
|
||||
|
||||
nextTheme = nextTheme ?? (await appWindow.theme())
|
||||
|
||||
generalStore.appearance.isDark = nextTheme === 'dark'
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => generalStore.appearance.isDark, (value) => {
|
||||
if (value) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProListItem title="主题模式">
|
||||
<Select v-model:value="generalStore.appearance.theme">
|
||||
<SelectOption value="auto">
|
||||
跟随系统
|
||||
</SelectOption>
|
||||
<SelectOption value="light">
|
||||
亮色模式
|
||||
</SelectOption>
|
||||
<SelectOption value="dark">
|
||||
暗色模式
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</ProListItem>
|
||||
</template>
|
||||
@@ -4,6 +4,7 @@ import { Switch } from 'ant-design-vue'
|
||||
import { watch } from 'vue'
|
||||
|
||||
import MacosPermissions from './components/macos-permissions/index.vue'
|
||||
import ThemeMode from './components/theme-mode/index.vue'
|
||||
|
||||
import ProList from '@/components/pro-list/index.vue'
|
||||
import ProListItem from '@/components/pro-list-item/index.vue'
|
||||
@@ -40,6 +41,10 @@ watch(() => generalStore.autostart, async (value) => {
|
||||
</ProListItem>
|
||||
</ProList>
|
||||
|
||||
<ProList title="外观设置">
|
||||
<ThemeMode />
|
||||
</ProList>
|
||||
|
||||
<ProList title="更新设置">
|
||||
<ProListItem title="自动检查更新">
|
||||
<Switch v-model:checked="generalStore.autoCheckUpdate" />
|
||||
|
||||
@@ -53,7 +53,7 @@ const menus = [
|
||||
<template>
|
||||
<Flex class="h-screen">
|
||||
<div
|
||||
class="h-full w-30 flex flex-col items-center gap-4 overflow-auto bg-gradient-from-primary-1 bg-gradient-to-black/1 bg-gradient-linear"
|
||||
class="h-full w-30 flex flex-col items-center gap-4 overflow-auto dark:(bg-color-3 bg-none) bg-gradient-from-primary-1 bg-gradient-to-black/1 bg-gradient-linear"
|
||||
:class="[isMac ? 'pt-8' : 'pt-4']"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
@@ -73,8 +73,8 @@ const menus = [
|
||||
<div
|
||||
v-for="(item, index) in menus"
|
||||
:key="item.label"
|
||||
class="size-20 flex flex-col cursor-pointer items-center justify-center gap-2 rounded-lg hover:bg-color-7 text-color-3 transition"
|
||||
:class="{ 'bg-white! text-primary-5 font-bold': current === index }"
|
||||
class="size-20 flex flex-col cursor-pointer items-center justify-center gap-2 rounded-lg hover:bg-color-7 dark:text-color-2 text-color-3 transition"
|
||||
:class="{ 'bg-color-2! text-primary-5 dark:text-primary-7 font-bold dark:bg-color-8!': current === index }"
|
||||
@click="current = index"
|
||||
>
|
||||
<div
|
||||
@@ -91,7 +91,7 @@ const menus = [
|
||||
v-for="(item, index) in menus"
|
||||
v-show="current === index"
|
||||
:key="item.label"
|
||||
class="flex-1 overflow-auto bg-color-8 p-4"
|
||||
class="flex-1 overflow-auto bg-color-8 dark:bg-color-2 p-4"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<component :is="item.component" />
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
import type { Theme } from '@tauri-apps/api/window'
|
||||
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
interface Appearance {
|
||||
theme: 'auto' | Theme
|
||||
isDark: boolean
|
||||
}
|
||||
|
||||
export const useGeneralStore = defineStore('general', () => {
|
||||
const autoCheckUpdate = ref(false)
|
||||
const autostart = ref(false)
|
||||
const taskbarVisibility = ref(false)
|
||||
const appearance = reactive<Appearance>({
|
||||
theme: 'auto',
|
||||
isDark: false,
|
||||
})
|
||||
|
||||
return {
|
||||
autoCheckUpdate,
|
||||
autostart,
|
||||
taskbarVisibility,
|
||||
appearance,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { resolveResource } from '@tauri-apps/api/path'
|
||||
import { readDir } from '@tauri-apps/plugin-fs'
|
||||
import { filter, find } from 'es-toolkit/compat'
|
||||
import { nanoid } from 'nanoid'
|
||||
import { defineStore } from 'pinia'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
import { isImage } from '@/utils/is'
|
||||
import { join } from '@/utils/path'
|
||||
import { clearObject } from '@/utils/shared'
|
||||
|
||||
export type ModelMode = 'standard' | 'keyboard' | 'gamepad'
|
||||
|
||||
@@ -69,27 +66,6 @@ export const useModelStore = defineStore('model', () => {
|
||||
models.value = nextModels
|
||||
}
|
||||
|
||||
watch(currentModel, async (model) => {
|
||||
if (!model) return
|
||||
|
||||
clearObject([supportKeys, pressedKeys])
|
||||
|
||||
const resourcePath = join(model.path, 'resources')
|
||||
const groups = ['left-keys', 'right-keys']
|
||||
|
||||
for await (const groupName of groups) {
|
||||
const groupDir = join(resourcePath, groupName)
|
||||
const files = await readDir(groupDir).catch(() => [])
|
||||
const imageFiles = files.filter(file => isImage(file.name))
|
||||
|
||||
for (const file of imageFiles) {
|
||||
const fileName = file.name.split('.')[0]
|
||||
|
||||
supportKeys[fileName] = join(groupDir, file.name)
|
||||
}
|
||||
}
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
return {
|
||||
models,
|
||||
currentModel,
|
||||
|
||||
Reference in New Issue
Block a user