From b66afcf2c5c4f4a9da5adc35f0bee3fa9c75dee3 Mon Sep 17 00:00:00 2001 From: lzt404 <2596933790@qq.com> Date: Fri, 31 Jul 2026 01:55:16 +0800 Subject: [PATCH] update ui --- index.html | 2 +- src/i18n/ja.ts | 18 +- src/i18n/resources.ts | 36 +- src/i18n/traditional.ts | 2 + src/pages/AgentsPage.tsx | 173 ++++---- src/styles.css | 896 ++++++++++++++++++++------------------- src/theme.ts | 4 +- tests/i18n.test.ts | 21 + 8 files changed, 567 insertions(+), 585 deletions(-) diff --git a/index.html b/index.html index 3a8c0ca..b35e535 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,7 @@ : matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; document.documentElement.dataset.theme = theme; document.documentElement.style.colorScheme = theme; - document.documentElement.style.backgroundColor = theme === 'dark' ? '#0b1220' : '#f4f7fb'; + document.documentElement.style.backgroundColor = theme === 'dark' ? '#111412' : '#f6f7f5'; } catch { // The app applies the theme again during initialization. } diff --git a/src/i18n/ja.ts b/src/i18n/ja.ts index c10851d..5863d85 100644 --- a/src/i18n/ja.ts +++ b/src/i18n/ja.ts @@ -442,7 +442,7 @@ export const jaOverrides = { 'agents.sessions.databaseMissing': 'セッションデータベースが見つかりません', 'agents.sessions.repairTitle': '過去のセッションを復元', 'agents.sessions.repairDescription': '他の Provider のセッションを現在のセッション Provider に同期します。', - 'agents.sessions.autoRepair': 'Codex 起動前に過去のセッションを自動復元', + 'agents.sessions.autoRepair': '過去のセッションを自動復元', 'agents.sessions.settingLoading': '読み込み中', 'agents.sessions.settingOn': 'オン', 'agents.sessions.settingOff': 'オフ', @@ -517,17 +517,11 @@ export const jaOverrides = { 'agents.modify.clear': '設定を消去', 'agents.modify.invalid': '現在の設定を解析できません。「設定変更を適用」は最小の有効な設定を再構築し、「デフォルト設定」はファイル全体をリセットします。', 'agents.modify.applied': 'アプリが管理するフィールドは適用済みで、それ以外のユーザー設定は保持されています。', - 'agents.footer.changed': 'モデル選択が変更されました。設定変更を適用すると新しいモデルが使用されます。', - 'agents.footer.applied': '設定変更は適用済みです。アプリは関連フィールドだけを管理します。', - 'agents.footer.invalidManaged': '設定が無効です。変更を適用して修復するか、デフォルト設定にリセットしてください。', - 'agents.footer.unsupported': '現在のシステムではこのクライアントを設定できません', - 'agents.footer.installFirst': 'クライアントをインストールしてから再検出してください', - 'agents.footer.noCommand': '設定ファイルは検出しましたが、クライアントコマンドが見つかりません', - 'agents.footer.invalidConfig': '元の設定形式が無効なため、安全に変更できません', - 'agents.launchMethods': 'Codex の起動方法', 'agents.launch.enableFirst': '先に設定変更を適用してください', 'agents.launch.applyFirst': '先に選択中のモデルを適用してください', 'agents.launch.starting': '起動中', + 'agents.launch.startCli': 'CLI を起動', + 'agents.launch.startApp': 'App を起動', 'agents.launch.start': '{target} を起動', 'agents.launch.unavailable': '起動できません', 'agents.launch.closeChatgpt': 'ChatGPT App を終了', @@ -791,9 +785,9 @@ export const jaOverrides = { 'kernel.dialog.install': 'コアのインストール', 'kernel.dialog.phase': '現在の段階', 'kernel.dialog.unknownProgress': '進捗不明', - 'kernel.access.openaiDescription': 'OpenAI SDK、OpenCode などの互換クライアント向け', - 'kernel.access.claudeDescription': 'Claude SDK および Claude Code 向け', - 'kernel.access.geminiDescription': 'Gemini ネイティブ互換クライアント向け', + 'kernel.access.openaiDescription': 'OpenAI互換形式', + 'kernel.access.claudeDescription': 'Anthropic互換形式', + 'kernel.access.geminiDescription': 'Gemini互換形式', 'authFiles.unnamed': '無名の認証ファイル', 'management.notConfigured': '未設定', 'management.error.upstream': '上流リクエストに失敗しました', diff --git a/src/i18n/resources.ts b/src/i18n/resources.ts index 9cf319a..40cd90c 100644 --- a/src/i18n/resources.ts +++ b/src/i18n/resources.ts @@ -445,7 +445,7 @@ export const zhCN = { 'agents.sessions.databaseMissing': '未发现会话数据库', 'agents.sessions.repairTitle': '恢复历史会话', 'agents.sessions.repairDescription': '将其他渠道的会话同步到当前会话', - 'agents.sessions.autoRepair': '启动 Codex 前自动恢复历史会话', + 'agents.sessions.autoRepair': '自动恢复历史会话', 'agents.sessions.settingLoading': '读取中', 'agents.sessions.settingOn': '已开启', 'agents.sessions.settingOff': '已关闭', @@ -520,17 +520,11 @@ export const zhCN = { 'agents.modify.clear': '清空配置', 'agents.modify.invalid': '当前配置无法解析。点击“应用配置修改”会重建最小合法配置;“默认配置”会重置整个文件。', 'agents.modify.applied': '软件负责的配置字段已应用,其他用户内容保持不变。', - 'agents.footer.changed': '模型选择已变化;应用配置修改后将使用新模型。', - 'agents.footer.applied': '配置修改已应用;软件只管理相关字段。', - 'agents.footer.invalidManaged': '配置当前无效,请应用修改进行修复,或重置为默认配置。', - 'agents.footer.unsupported': '当前系统无法配置该客户端', - 'agents.footer.installFirst': '请先安装客户端并重新检测', - 'agents.footer.noCommand': '检测到配置文件,但没有找到客户端命令', - 'agents.footer.invalidConfig': '原配置格式异常,无法安全修改', - 'agents.launchMethods': 'Codex 启动方式', 'agents.launch.enableFirst': '请先应用配置修改', 'agents.launch.applyFirst': '请先应用当前模型选择', 'agents.launch.starting': '启动中', + 'agents.launch.startCli': '启动 CLI', + 'agents.launch.startApp': '启动 App', 'agents.launch.start': '启动 {target}', 'agents.launch.unavailable': '无法启动', 'agents.launch.closeChatgpt': '关闭 ChatGPT App', @@ -794,9 +788,9 @@ export const zhCN = { 'kernel.dialog.install': '内核安装', 'kernel.dialog.phase': '当前阶段', 'kernel.dialog.unknownProgress': '进度未知', - 'kernel.access.openaiDescription': '适用于 OpenAI SDK、OpenCode 等兼容客户端', - 'kernel.access.claudeDescription': '适用于 Claude SDK 与 Claude Code', - 'kernel.access.geminiDescription': '适用于 Gemini 原生兼容客户端', + 'kernel.access.openaiDescription': 'OpenAI兼容格式', + 'kernel.access.claudeDescription': 'Anthropic兼容格式', + 'kernel.access.geminiDescription': 'Gemini兼容格式', 'authFiles.unnamed': '未命名认证文件', 'management.notConfigured': '未配置', 'management.error.upstream': '上游请求失败', @@ -1293,7 +1287,7 @@ export const en: Record = { 'agents.sessions.databaseMissing': 'No session database found', 'agents.sessions.repairTitle': 'Restore Historical Sessions', 'agents.sessions.repairDescription': 'Sync sessions from other providers to the current session provider.', - 'agents.sessions.autoRepair': 'Restore historical sessions before launching Codex', + 'agents.sessions.autoRepair': 'Automatically restore historical sessions', 'agents.sessions.settingLoading': 'Loading', 'agents.sessions.settingOn': 'On', 'agents.sessions.settingOff': 'Off', @@ -1368,17 +1362,11 @@ export const en: Record = { 'agents.modify.clear': 'Clear Configuration', 'agents.modify.invalid': 'The current configuration cannot be parsed. Apply Configuration Changes rebuilds a minimal valid configuration; Default Configuration resets the whole file.', 'agents.modify.applied': 'The fields managed by the app are applied; all other user content remains unchanged.', - 'agents.footer.changed': 'The model selection changed. Apply the configuration to use the new model.', - 'agents.footer.applied': 'Configuration changes are applied; only the relevant fields are managed by the app.', - 'agents.footer.invalidManaged': 'The configuration is invalid. Apply changes to repair it or reset it to the default configuration.', - 'agents.footer.unsupported': 'This client cannot be configured on the current system', - 'agents.footer.installFirst': 'Install the client, then detect again', - 'agents.footer.noCommand': 'A configuration file was found, but no client command is available', - 'agents.footer.invalidConfig': 'The original configuration is invalid and cannot be modified safely', - 'agents.launchMethods': 'Codex launch methods', 'agents.launch.enableFirst': 'Apply the configuration changes first', 'agents.launch.applyFirst': 'Apply the selected model first', 'agents.launch.starting': 'Starting', + 'agents.launch.startCli': 'Start CLI', + 'agents.launch.startApp': 'Start App', 'agents.launch.start': 'Start {target}', 'agents.launch.unavailable': 'Cannot Start', 'agents.launch.closeChatgpt': 'Close ChatGPT App', @@ -1642,9 +1630,9 @@ export const en: Record = { 'kernel.dialog.install': 'Core Installation', 'kernel.dialog.phase': 'Current Phase', 'kernel.dialog.unknownProgress': 'Progress Unknown', - 'kernel.access.openaiDescription': 'For OpenAI SDK, OpenCode, and other compatible clients', - 'kernel.access.claudeDescription': 'For Claude SDK and Claude Code', - 'kernel.access.geminiDescription': 'For native Gemini-compatible clients', + 'kernel.access.openaiDescription': 'OpenAI-compatible format', + 'kernel.access.claudeDescription': 'Anthropic-compatible format', + 'kernel.access.geminiDescription': 'Gemini-compatible format', 'authFiles.unnamed': 'Unnamed credential file', 'management.notConfigured': 'Not configured', 'management.error.upstream': 'Upstream request failed', diff --git a/src/i18n/traditional.ts b/src/i18n/traditional.ts index 413383f..13a9cc1 100644 --- a/src/i18n/traditional.ts +++ b/src/i18n/traditional.ts @@ -1,4 +1,6 @@ const phraseReplacements: ReadonlyArray = [ + ['兼容格式', '相容格式'], + ['历史', '歷史'], ['高级设置', '進階設定'], ['繁体中文', '繁體中文'], ['简体中文', '簡體中文'], diff --git a/src/pages/AgentsPage.tsx b/src/pages/AgentsPage.tsx index 7c92ba9..504f004 100644 --- a/src/pages/AgentsPage.tsx +++ b/src/pages/AgentsPage.tsx @@ -12,6 +12,7 @@ import { invoke } from '@tauri-apps/api/core'; import { listen } from '@tauri-apps/api/event'; import { AlertTriangle, + AppWindow, BadgeCheck, Bot, Check, @@ -22,6 +23,7 @@ import { RefreshCw, Search, Sparkles, + Terminal, Trash2, X, } from 'lucide-react'; @@ -481,10 +483,11 @@ export function AgentsPage() { const [modelByClient, setModelByClient] = useState>>( readAgentModelSelections, ); - const [launchTargetByClient, setLaunchTargetByClient] = useState>>({}); const [loading, setLoading] = useState(true); const [modelLoading, setModelLoading] = useState(false); - const [busyAction, setBusyAction] = useState<'apply' | 'default' | 'clear' | 'launch' | 'close-app' | null>(null); + const [busyAction, setBusyAction] = useState< + 'apply' | 'default' | 'clear' | 'launch' | 'launch-cli' | 'launch-app' | 'close-app' | null + >(null); const busy = busyAction !== null; const [detectionError, setDetectionError] = useState(''); const [modelError, setModelError] = useState(''); @@ -598,20 +601,6 @@ export function AgentsPage() { setCloseAppConfirmOpen(false); }, [selected]); - useEffect(() => { - setLaunchTargetByClient((current) => agentDefinitions.reduce>>( - (next, definition) => { - const targets = statuses.find((status) => status.id === definition.id)?.launchTargets ?? []; - const previous = current[definition.id] ?? ''; - next[definition.id] = targets.some((target) => target.id === previous) - ? previous - : targets[0]?.id ?? ''; - return next; - }, - {}, - )); - }, [statuses]); - const activeDefinition = agentDefinitions.find((agent) => agent.id === selected) ?? agentDefinitions[0]; const activeStatus = statuses.find((status) => status.id === selected) ?? null; @@ -622,10 +611,9 @@ export function AgentsPage() { const selectedModelOption = findAgentModel(models, savedSelectedModel); const selectedModel = selectedModelOption?.name ?? ''; const activeLaunchTargets = activeStatus?.launchTargets ?? []; - const selectedLaunchTargetId = launchTargetByClient[selected] ?? activeLaunchTargets[0]?.id ?? ''; - const selectedLaunchTarget = activeLaunchTargets.find( - (target) => target.id === selectedLaunchTargetId, - ) ?? activeLaunchTargets[0] ?? null; + const defaultLaunchTarget = activeLaunchTargets[0] ?? null; + const cliLaunchTarget = activeLaunchTargets.find((target) => target.id === 'cli') ?? null; + const appLaunchTarget = activeLaunchTargets.find((target) => target.id === 'app') ?? null; const appliedModel = activeStatus?.appliedModel ?? activeStatus?.currentModel ?? ''; const modelDraftChanged = Boolean( selectedModel.trim() @@ -641,13 +629,13 @@ export function AgentsPage() { && !modelLoading && selectedModelOption, ); - const canLaunch = Boolean( + const launchEnabled = Boolean( activeStatus?.supportedPlatform && activeStatus.installed - && selectedLaunchTarget && (selected === 'codex' || (activeStatus.modificationEnabled && activeStatus.modificationState === 'applied')), ); + const canLaunchTarget = (target: AgentLaunchTarget | null) => launchEnabled && Boolean(target); const modelHint = modelSelectionError || modelError || (modelLoading @@ -662,20 +650,6 @@ export function AgentsPage() { : activeStatus?.modificationState === 'applied' ? t('agents.modify.applied') : ''; - const footerMessage = activeStatus?.modificationState === 'applied' - ? draftChanged - ? t('agents.footer.changed') - : t('agents.footer.applied') - : activeStatus?.modificationState === 'invalid' - ? t('agents.footer.invalidManaged') - : !activeStatus?.supportedPlatform - ? t('agents.footer.unsupported') - : !activeStatus.installed - ? t('agents.footer.installFirst') - : activeStatus.launchTargets.length === 0 - ? t('agents.footer.noCommand') - : ''; - const refreshModels = () => { void loadModels(selected); }; @@ -776,14 +750,18 @@ export function AgentsPage() { } }; - const launchAgent = async () => { - setBusyAction('launch'); + const launchAgent = async (target: AgentLaunchTarget | null) => { + if (!target) return; + const launchAction = selected === 'codex' + ? target.id === 'cli' ? 'launch-cli' : 'launch-app' + : 'launch'; + setBusyAction(launchAction); setLaunchError(''); try { if (selected !== 'codex' && draftChanged) { throw new Error(t('agents.error.applyFirst')); } - await invoke('launch_agent', { client: selected, target: selectedLaunchTarget?.id }); + await invoke('launch_agent', { client: selected, target: target.id }); } catch (requestError) { setLaunchError(String(requestError)); } finally { @@ -975,23 +953,26 @@ export function AgentsPage() {
{selected === 'codex' ? ( - +
+ + +
) : null}
- ))} -
- ) : null} - + + + ) : ( + + > + {busyAction === 'launch' ? : } + {busyAction === 'launch' ? t('agents.launch.starting') : defaultLaunchTarget ? t('agents.launch.start', { target: defaultLaunchTarget.label }) : t('agents.launch.unavailable')} + + )} {selected === 'codex' ? (