Thing init
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { getCurrentWindow, Effect } from '@tauri-apps/api/window'
|
||||
|
||||
export type Theme = 'light' | 'dark' | 'system'
|
||||
export type EffectType = 'normal' | 'mica' | 'acrylic'
|
||||
|
||||
const STORAGE_KEY = 'thing_app_settings'
|
||||
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
const theme = ref<Theme>('system')
|
||||
const effect = ref<EffectType>('mica')
|
||||
const isAutoStart = ref(false)
|
||||
const isInitialized = ref(false)
|
||||
|
||||
const loadSettings = () => {
|
||||
try {
|
||||
const saved = localStorage.getItem(STORAGE_KEY)
|
||||
if (saved) {
|
||||
const settings = JSON.parse(saved)
|
||||
if (settings.theme) theme.value = settings.theme
|
||||
if (settings.effect) effect.value = settings.effect
|
||||
if (settings.isAutoStart !== undefined) isAutoStart.value = settings.isAutoStart
|
||||
}
|
||||
} catch {
|
||||
console.error('Failed to load settings from localStorage')
|
||||
}
|
||||
}
|
||||
|
||||
const saveSettings = () => {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify({
|
||||
theme: theme.value,
|
||||
effect: effect.value,
|
||||
isAutoStart: isAutoStart.value
|
||||
}))
|
||||
} catch {
|
||||
console.error('Failed to save settings to localStorage')
|
||||
}
|
||||
}
|
||||
|
||||
const setTheme = async (newTheme: Theme) => {
|
||||
theme.value = newTheme
|
||||
await applyTheme()
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
const setEffect = async (newEffect: EffectType) => {
|
||||
effect.value = newEffect
|
||||
await applyEffect()
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
const toggleAutoStart = () => {
|
||||
isAutoStart.value = !isAutoStart.value
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
const applyTheme = async () => {
|
||||
const root = document.documentElement
|
||||
root.classList.remove('dark')
|
||||
|
||||
let isDark = false
|
||||
if (theme.value === 'dark') {
|
||||
isDark = true
|
||||
root.classList.add('dark')
|
||||
} else if (theme.value === 'system') {
|
||||
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
if (isDark) {
|
||||
root.classList.add('dark')
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const tauriWindow = getCurrentWindow()
|
||||
await tauriWindow.setTheme(isDark ? 'dark' : 'light')
|
||||
} catch (e) {
|
||||
console.error('Failed to set window theme:', e)
|
||||
}
|
||||
|
||||
await applyEffect()
|
||||
}
|
||||
|
||||
const applyEffect = async () => {
|
||||
const root = document.documentElement
|
||||
root.classList.remove('effect-mica', 'effect-acrylic', 'effect-normal')
|
||||
root.classList.add(`effect-${effect.value}`)
|
||||
|
||||
try {
|
||||
const tauriWindow = getCurrentWindow()
|
||||
|
||||
const isDark = root.classList.contains('dark')
|
||||
|
||||
await tauriWindow.clearEffects()
|
||||
|
||||
if (effect.value === 'normal') {
|
||||
await tauriWindow.setBackgroundColor(isDark ? '#0f172a' : '#ffffff')
|
||||
} else if (effect.value === 'mica') {
|
||||
await tauriWindow.setEffects({
|
||||
effects: [Effect.Mica],
|
||||
color: isDark ? '#1e293b' : '#f1f5f9'
|
||||
})
|
||||
await tauriWindow.setBackgroundColor('#00000000')
|
||||
} else if (effect.value === 'acrylic') {
|
||||
await tauriWindow.setEffects({
|
||||
effects: [Effect.Acrylic],
|
||||
color: isDark ? '#1e293b' : '#f1f5f9'
|
||||
})
|
||||
await tauriWindow.setBackgroundColor('#00000000')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to set window effects:', e)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSystemThemeChange = async (e: MediaQueryListEvent) => {
|
||||
if (theme.value === 'system') {
|
||||
const root = document.documentElement
|
||||
if (e.matches) {
|
||||
root.classList.add('dark')
|
||||
} else {
|
||||
root.classList.remove('dark')
|
||||
}
|
||||
|
||||
try {
|
||||
const tauriWindow = getCurrentWindow()
|
||||
await tauriWindow.setTheme(e.matches ? 'dark' : 'light')
|
||||
} catch (err) {
|
||||
console.error('Failed to update window theme on system change:', err)
|
||||
}
|
||||
|
||||
await applyEffect()
|
||||
}
|
||||
}
|
||||
|
||||
const init = async () => {
|
||||
loadSettings()
|
||||
await applyTheme()
|
||||
await applyEffect()
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
mediaQuery.addEventListener('change', handleSystemThemeChange)
|
||||
|
||||
isInitialized.value = true
|
||||
}
|
||||
|
||||
return {
|
||||
theme,
|
||||
effect,
|
||||
isAutoStart,
|
||||
isInitialized,
|
||||
setTheme,
|
||||
setEffect,
|
||||
toggleAutoStart,
|
||||
applyTheme,
|
||||
applyEffect,
|
||||
init,
|
||||
loadSettings
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,113 @@
|
||||
export interface SearchIndexItem {
|
||||
title: string
|
||||
description?: string
|
||||
keywords: string[]
|
||||
}
|
||||
|
||||
export interface SearchIndexConfig {
|
||||
moduleId: string
|
||||
items: SearchIndexItem[]
|
||||
}
|
||||
|
||||
export const searchIndex: SearchIndexConfig[] = [
|
||||
{
|
||||
moduleId: 'settings',
|
||||
items: [
|
||||
{
|
||||
title: '浅色模式',
|
||||
description: '切换到浅色主题',
|
||||
keywords: ['浅色', '主题', 'theme', 'light']
|
||||
},
|
||||
{
|
||||
title: '深色模式',
|
||||
description: '切换到深色主题',
|
||||
keywords: ['深色', '主题', 'theme', 'dark']
|
||||
},
|
||||
{
|
||||
title: '跟随系统',
|
||||
description: '跟随系统主题设置',
|
||||
keywords: ['系统', '主题', 'theme', 'system']
|
||||
},
|
||||
{
|
||||
title: '普通模式',
|
||||
description: '标准背景效果',
|
||||
keywords: ['效果', '普通', 'normal', 'effect']
|
||||
},
|
||||
{
|
||||
title: 'Win 云母',
|
||||
description: 'Windows 11 云母效果',
|
||||
keywords: ['效果', '云母', 'mica', 'effect']
|
||||
},
|
||||
{
|
||||
title: 'Win 亚克力',
|
||||
description: 'Windows 11 亚克力效果',
|
||||
keywords: ['效果', '亚克力', 'acrylic', 'effect']
|
||||
},
|
||||
{
|
||||
title: '开机自启',
|
||||
description: '启动 Windows 时自动运行应用',
|
||||
keywords: ['开机', '自启', '自动', 'auto', 'start']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'proxy',
|
||||
items: [
|
||||
{
|
||||
title: '代理设置',
|
||||
description: '配置网络代理',
|
||||
keywords: ['代理', 'proxy', '网络', 'network']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'clipboard',
|
||||
items: [
|
||||
{
|
||||
title: '剪贴板历史',
|
||||
description: '查看和管理剪贴板记录',
|
||||
keywords: ['剪贴板', '复制', '粘贴', 'clipboard', 'copy', 'paste']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'screenshot',
|
||||
items: [
|
||||
{
|
||||
title: '截图工具',
|
||||
description: '捕获屏幕截图',
|
||||
keywords: ['截图', '屏幕', 'screenshot', 'capture']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'monitor',
|
||||
items: [
|
||||
{
|
||||
title: '硬件监控',
|
||||
description: '查看系统硬件状态',
|
||||
keywords: ['监控', '硬件', 'cpu', '内存', 'monitor', 'hardware']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'downloader',
|
||||
items: [
|
||||
{
|
||||
title: '下载管理',
|
||||
description: '管理下载任务',
|
||||
keywords: ['下载', 'download', '文件', 'file']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'finder',
|
||||
items: [
|
||||
{
|
||||
title: '文件搜索',
|
||||
description: '搜索本地文件',
|
||||
keywords: ['文件', '搜索', 'finder', 'search', 'file']
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { searchIndex } from './searchIndex'
|
||||
|
||||
export interface SearchItem {
|
||||
id: string
|
||||
moduleId: string
|
||||
title: string
|
||||
description?: string
|
||||
keywords: string[]
|
||||
action?: () => void
|
||||
}
|
||||
|
||||
export const useSearchStore = defineStore('search', () => {
|
||||
const items = ref<SearchItem[]>([])
|
||||
|
||||
const initGlobalIndex = () => {
|
||||
searchIndex.forEach(config => {
|
||||
config.items.forEach((item, index) => {
|
||||
const searchItem: SearchItem = {
|
||||
id: `${config.moduleId}-search-${index}`,
|
||||
moduleId: config.moduleId,
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
keywords: item.keywords
|
||||
}
|
||||
if (!items.value.find(i => i.id === searchItem.id)) {
|
||||
items.value.push(searchItem)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const registerAction = (moduleId: string, itemIndex: number, action: () => void) => {
|
||||
const id = `${moduleId}-search-${itemIndex}`
|
||||
const item = items.value.find(i => i.id === id)
|
||||
if (item) {
|
||||
item.action = action
|
||||
}
|
||||
}
|
||||
|
||||
const registerActions = (moduleId: string, actions: Map<number, () => void>) => {
|
||||
actions.forEach((action, index) => {
|
||||
registerAction(moduleId, index, action)
|
||||
})
|
||||
}
|
||||
|
||||
const registerItem = (item: SearchItem) => {
|
||||
if (!items.value.find(i => i.id === item.id)) {
|
||||
items.value.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
const registerItems = (newItems: SearchItem[]) => {
|
||||
newItems.forEach(item => registerItem(item))
|
||||
}
|
||||
|
||||
const unregisterItem = (id: string) => {
|
||||
const index = items.value.findIndex(i => i.id === id)
|
||||
if (index !== -1) {
|
||||
items.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const search = (query: string) => {
|
||||
if (!query.trim()) return []
|
||||
const lowerQuery = query.toLowerCase()
|
||||
return items.value.filter(item => {
|
||||
const titleMatch = item.title.toLowerCase().includes(lowerQuery)
|
||||
const descMatch = item.description ? item.description.toLowerCase().includes(lowerQuery) : false
|
||||
const keywordMatch = item.keywords.some(k => k.toLowerCase().includes(lowerQuery))
|
||||
const moduleIdMatch = item.moduleId.toLowerCase().includes(lowerQuery)
|
||||
return titleMatch || descMatch || keywordMatch || moduleIdMatch
|
||||
})
|
||||
}
|
||||
|
||||
const getItemsByModule = (moduleId: string) => {
|
||||
return items.value.filter(i => i.moduleId === moduleId)
|
||||
}
|
||||
|
||||
return {
|
||||
items,
|
||||
initGlobalIndex,
|
||||
registerAction,
|
||||
registerActions,
|
||||
registerItem,
|
||||
registerItems,
|
||||
unregisterItem,
|
||||
search,
|
||||
getItemsByModule
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user