v1.3.0: 主题系统+代码分割+设置重构+命令片段库+命令面板+连接面板 | 19 files +2141/-257 | tsc零错误 构建成功
This commit is contained in:
1 parent
caba5f4c0d
commit
1f2de032a4
19 files changed
+2142
-258
No files matched your search
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* CommandPaletteStore — 命令面板状态管理
|
||||
*
|
||||
* 管理 VS Code 风格命令面板 (Ctrl+Shift+P) 的开关状态
|
||||
* 与 UI 组件解耦,任何组件都可触发打开/关闭
|
||||
*/
|
||||
|
||||
import { create } from 'zustand'
|
||||
|
||||
interface CommandPaletteState {
|
||||
isOpen: boolean
|
||||
|
||||
// Actions
|
||||
open: () => void
|
||||
close: () => void
|
||||
toggle: () => void
|
||||
}
|
||||
|
||||
export const useCommandPaletteStore = create<CommandPaletteState>((set) => ({
|
||||
isOpen: false,
|
||||
|
||||
open: () => set({ isOpen: true }),
|
||||
|
||||
close: () => set({ isOpen: false }),
|
||||
|
||||
toggle: () => set((state) => ({ isOpen: !state.isOpen })),
|
||||
}))
|
||||
|
||||
export default useCommandPaletteStore
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Connection Panel Store - 连接面板开关状态
|
||||
*/
|
||||
|
||||
import { create } from 'zustand'
|
||||
|
||||
interface ConnectionPanelState {
|
||||
isOpen: boolean
|
||||
open: () => void
|
||||
close: () => void
|
||||
toggle: () => void
|
||||
}
|
||||
|
||||
export const useConnectionPanelStore = create<ConnectionPanelState>((set) => ({
|
||||
isOpen: false,
|
||||
open: () => set({ isOpen: true }),
|
||||
close: () => set({ isOpen: false }),
|
||||
toggle: () => set((s) => ({ isOpen: !s.isOpen })),
|
||||
}))
|
||||
@@ -18,5 +18,12 @@ export {
|
||||
getSessionConfig,
|
||||
} from './connection'
|
||||
|
||||
// 命令片段
|
||||
export { useSnippetStore } from './snippetStore'
|
||||
export type { Snippet } from './snippetStore'
|
||||
|
||||
// 命令面板
|
||||
export { useCommandPaletteStore } from './commandPaletteStore'
|
||||
|
||||
// 类型导出
|
||||
export type { ConnectionState } from './connection'
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* SnippetStore — 命令片段库状态管理
|
||||
*
|
||||
* 管理用户保存的常用命令片段,支持 CRUD 和搜索
|
||||
* 数据通过 electronAPI.settingsGet/settingsSet 持久化
|
||||
*/
|
||||
|
||||
import { create } from 'zustand'
|
||||
import { createLogger } from '../utils/logger'
|
||||
|
||||
const logger = createLogger('SnippetStore')
|
||||
|
||||
export interface Snippet {
|
||||
id: string
|
||||
name: string
|
||||
content: string
|
||||
tags: string[]
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
interface SnippetState {
|
||||
snippets: Snippet[]
|
||||
isLoaded: boolean
|
||||
|
||||
// Actions
|
||||
loadSnippets: () => Promise<void>
|
||||
addSnippet: (name: string, content: string, tags?: string[]) => Promise<void>
|
||||
updateSnippet: (id: string, updates: Partial<Pick<Snippet, 'name' | 'content' | 'tags'>>) => Promise<void>
|
||||
deleteSnippet: (id: string) => Promise<void>
|
||||
searchSnippets: (query: string) => Snippet[]
|
||||
}
|
||||
|
||||
/** 持久化到 settings 的 key */
|
||||
const STORAGE_KEY = 'snippets'
|
||||
|
||||
/** 生成唯一 ID */
|
||||
function generateId(): string {
|
||||
return `snippet-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
||||
}
|
||||
|
||||
/** 将片段数据保存到 electron settings */
|
||||
async function persistSnippets(snippets: Snippet[]): Promise<void> {
|
||||
try {
|
||||
await window.electronAPI?.settingsSet(STORAGE_KEY, snippets)
|
||||
} catch (error) {
|
||||
logger.error('Failed to persist snippets', error)
|
||||
}
|
||||
}
|
||||
|
||||
export const useSnippetStore = create<SnippetState>((set, get) => ({
|
||||
snippets: [],
|
||||
isLoaded: false,
|
||||
|
||||
loadSnippets: async () => {
|
||||
try {
|
||||
const result = await window.electronAPI?.settingsGet(STORAGE_KEY)
|
||||
if (result?.success && Array.isArray(result.value)) {
|
||||
set({ snippets: result.value as Snippet[], isLoaded: true })
|
||||
} else {
|
||||
set({ isLoaded: true })
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to load snippets', error)
|
||||
set({ isLoaded: true })
|
||||
}
|
||||
},
|
||||
|
||||
addSnippet: async (name, content, tags = []) => {
|
||||
const now = Date.now()
|
||||
const snippet: Snippet = {
|
||||
id: generateId(),
|
||||
name,
|
||||
content,
|
||||
tags,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}
|
||||
const snippets = [...get().snippets, snippet]
|
||||
set({ snippets })
|
||||
await persistSnippets(snippets)
|
||||
},
|
||||
|
||||
updateSnippet: async (id, updates) => {
|
||||
const snippets = get().snippets.map((s) =>
|
||||
s.id === id
|
||||
? { ...s, ...updates, updatedAt: Date.now() }
|
||||
: s
|
||||
)
|
||||
set({ snippets })
|
||||
await persistSnippets(snippets)
|
||||
},
|
||||
|
||||
deleteSnippet: async (id) => {
|
||||
const snippets = get().snippets.filter((s) => s.id !== id)
|
||||
set({ snippets })
|
||||
await persistSnippets(snippets)
|
||||
},
|
||||
|
||||
searchSnippets: (query) => {
|
||||
const { snippets } = get()
|
||||
if (!query.trim()) return snippets
|
||||
|
||||
const lowerQuery = query.toLowerCase().trim()
|
||||
return snippets.filter(
|
||||
(s) =>
|
||||
s.name.toLowerCase().includes(lowerQuery) ||
|
||||
s.content.toLowerCase().includes(lowerQuery) ||
|
||||
s.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))
|
||||
)
|
||||
},
|
||||
}))
|
||||
Reference in new issue
Block a user