From 77bdeb02fbe40e6d5565e0c9d0de7f98820437d0 Mon Sep 17 00:00:00 2001 From: Jason Date: Sun, 7 Sep 2025 10:48:27 +0800 Subject: [PATCH] feat(settings): add minimal settings panel - Add settings icon button next to app title - Create SettingsModal component with: - Show in Dock option (macOS) - Version info and check for updates button - Config file location with open folder button - Add settings-related APIs in tauri-api - Update type definitions for new API methods --- src/App.tsx | 25 +++- src/components/SettingsModal.tsx | 203 +++++++++++++++++++++++++++++++ src/lib/tauri-api.ts | 29 +++++ src/vite-env.d.ts | 3 + 4 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 src/components/SettingsModal.tsx diff --git a/src/App.tsx b/src/App.tsx index 5b96508..376aab7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,7 +6,8 @@ import AddProviderModal from "./components/AddProviderModal"; import EditProviderModal from "./components/EditProviderModal"; import { ConfirmDialog } from "./components/ConfirmDialog"; import { AppSwitcher } from "./components/AppSwitcher"; -import { Plus } from "lucide-react"; +import SettingsModal from "./components/SettingsModal"; +import { Plus, Settings } from "lucide-react"; function App() { const [activeApp, setActiveApp] = useState("claude"); @@ -31,6 +32,7 @@ function App() { message: string; onConfirm: () => void; } | null>(null); + const [isSettingsOpen, setIsSettingsOpen] = useState(false); const timeoutRef = useRef | null>(null); // 设置通知的辅助函数 @@ -218,9 +220,18 @@ function App() { {/* Linear 风格的顶部导航 */}
-

- CC Switch -

+
+

+ CC Switch +

+ +
@@ -317,6 +328,12 @@ function App() { onCancel={() => setConfirmDialog(null)} /> )} + + {isSettingsOpen && ( + setIsSettingsOpen(false)} + /> + )}
); } diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx new file mode 100644 index 0000000..159f2ad --- /dev/null +++ b/src/components/SettingsModal.tsx @@ -0,0 +1,203 @@ +import { useState, useEffect } from "react"; +import { X, Info, RefreshCw, FolderOpen } from "lucide-react"; +import "../lib/tauri-api"; + +interface Settings { + showInDock: boolean; +} + +interface SettingsModalProps { + onClose: () => void; +} + +export default function SettingsModal({ onClose }: SettingsModalProps) { + const [settings, setSettings] = useState({ + showInDock: true, + }); + const [configPath, setConfigPath] = useState(""); + const [version] = useState("1.0.0"); + const [isCheckingUpdate, setIsCheckingUpdate] = useState(false); + + useEffect(() => { + loadSettings(); + loadConfigPath(); + }, []); + + const loadSettings = async () => { + try { + const loadedSettings = await window.api.getSettings(); + if (loadedSettings?.showInDock !== undefined) { + setSettings({ showInDock: loadedSettings.showInDock }); + } + } catch (error) { + console.error("加载设置失败:", error); + } + }; + + const loadConfigPath = async () => { + try { + const status = await window.api.getConfigStatus("claude"); + if (status?.path) { + setConfigPath(status.path.replace("/claude_code_config.json", "")); + } + } catch (error) { + console.error("获取配置路径失败:", error); + } + }; + + const saveSettings = async () => { + try { + await window.api.saveSettings(settings); + onClose(); + } catch (error) { + console.error("保存设置失败:", error); + } + }; + + const handleCheckUpdate = async () => { + setIsCheckingUpdate(true); + try { + await window.api.checkForUpdates(); + } catch (error) { + console.error("检查更新失败:", error); + } finally { + setTimeout(() => setIsCheckingUpdate(false), 2000); + } + }; + + const handleOpenConfigFolder = async () => { + try { + await window.api.openConfigFolder("claude"); + } catch (error) { + console.error("打开配置文件夹失败:", error); + } + }; + + return ( +
+
+ {/* 标题栏 */} +
+

+ 设置 +

+ +
+ + {/* 设置内容 */} +
+ {/* 显示设置 */} +
+

+ 显示设置 +

+ +
+ + {/* 配置文件位置 */} +
+

+ 配置文件位置 +

+
+
+ + {configPath || "加载中..."} + +
+ +
+
+ + {/* 关于 */} +
+

+ 关于 +

+
+
+
+ +
+

+ CC Switch +

+

+ 版本 {version} +

+

+ 管理 Claude Code 和 Codex 的 MCP 服务器配置 +

+
+
+ +
+
+
+
+ + {/* 底部按钮 */} +
+ + +
+
+
+ ); +} diff --git a/src/lib/tauri-api.ts b/src/lib/tauri-api.ts index 5c1a168..41ebe24 100644 --- a/src/lib/tauri-api.ts +++ b/src/lib/tauri-api.ts @@ -194,6 +194,35 @@ export const tauriAPI = { console.warn("selectConfigFile 在 Tauri 版本中暂不支持"); return null; }, + + // 获取设置 + getSettings: async (): Promise => { + try { + return await invoke("get_settings"); + } catch (error) { + console.error("获取设置失败:", error); + return { showInDock: true }; + } + }, + + // 保存设置 + saveSettings: async (settings: any): Promise => { + try { + return await invoke("save_settings", { settings }); + } catch (error) { + console.error("保存设置失败:", error); + return false; + } + }, + + // 检查更新 + checkForUpdates: async (): Promise => { + try { + await invoke("check_for_updates"); + } catch (error) { + console.error("检查更新失败:", error); + } + }, }; // 创建全局 API 对象,兼容现有代码 diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 7a6e3d5..eb320f3 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -35,6 +35,9 @@ declare global { onProviderSwitched: ( callback: (data: { appType: string; providerId: string }) => void, ) => Promise; + getSettings: () => Promise; + saveSettings: (settings: any) => Promise; + checkForUpdates: () => Promise; }; platform: { isMac: boolean;