From e87f206905b84b9659a4d33dcde7cb1ddb442392 Mon Sep 17 00:00:00 2001 From: farion1231 Date: Wed, 6 Aug 2025 16:16:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=AE=8C=E7=BE=8E=E7=9A=84?= =?UTF-8?q?=E6=B5=AE=E5=8A=A8=E9=80=9A=E7=9F=A5=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加自定义通知组件替代阻塞式alert - 浮动定位不影响页面布局,宽度自适应内容 - 支持成功/错误两种样式,渐变背景+阴影效果 - 实现完整的淡入淡出动画,原地显示隐藏 - 重启提示显示4秒,普通操作反馈2-3秒 - 智能定时器管理,支持动画完成后清理 用户体验:切换供应商后优雅提示"请重启Claude Code终端以生效" --- src/renderer/App.css | 60 +++++++++++++++++++++++++++++++++++++++++ src/renderer/App.tsx | 64 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 111 insertions(+), 13 deletions(-) diff --git a/src/renderer/App.css b/src/renderer/App.css index 38fb59b..77958ab 100644 --- a/src/renderer/App.css +++ b/src/renderer/App.css @@ -88,4 +88,64 @@ .browse-btn:hover { background: #2980b9; +} + +/* 供应商列表区域 - 相对定位容器 */ +.provider-section { + position: relative; +} + +/* 浮动通知 - 绝对定位,不占据空间 */ +.notification-floating { + position: absolute; + top: -10px; + left: 50%; + transform: translateX(-50%); + z-index: 100; + + padding: 0.75rem 1.25rem; + border-radius: 6px; + font-size: 0.9rem; + font-weight: 500; + + width: fit-content; + white-space: nowrap; +} + +.fade-in { + animation: fadeIn 0.3s ease-out; +} + +.fade-out { + animation: fadeOut 0.3s ease-out; +} + +.notification-success { + background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%); + color: white; + box-shadow: 0 4px 12px rgba(39, 174, 96, 0.3); +} + +.notification-error { + background: linear-gradient(135deg, #e74c3c 0%, #ec7063 100%); + color: white; + box-shadow: 0 4px 12px rgba(231, 76, 60, 0.3); +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } } \ No newline at end of file diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 9a98aeb..1f7544d 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react' +import { useState, useEffect, useRef } from 'react' import { Provider } from '../shared/types' import ProviderList from './components/ProviderList' import AddProviderModal from './components/AddProviderModal' @@ -11,6 +11,31 @@ function App() { const [isAddModalOpen, setIsAddModalOpen] = useState(false) const [configPath, setConfigPath] = useState('') const [editingProviderId, setEditingProviderId] = useState(null) + const [notification, setNotification] = useState<{ message: string; type: 'success' | 'error' } | null>(null) + const [isNotificationVisible, setIsNotificationVisible] = useState(false) + const timeoutRef = useRef(null) + + // 设置通知的辅助函数 + const showNotification = (message: string, type: 'success' | 'error', duration = 3000) => { + // 清除之前的定时器 + if (timeoutRef.current) { + clearTimeout(timeoutRef.current) + } + + // 立即显示通知 + setNotification({ message, type }) + setIsNotificationVisible(true) + + // 设置淡出定时器 + timeoutRef.current = setTimeout(() => { + setIsNotificationVisible(false) + // 等待淡出动画完成后清除通知 + setTimeout(() => { + setNotification(null) + timeoutRef.current = null + }, 300) // 与CSS动画时间匹配 + }, duration) + } // 加载供应商列表 useEffect(() => { @@ -18,6 +43,15 @@ function App() { loadConfigPath() }, []) + // 清理定时器 + useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current) + } + } + }, []) + const loadProviders = async () => { const loadedProviders = await window.electronAPI.getProviders() @@ -58,10 +92,10 @@ function App() { const success = await window.electronAPI.switchProvider(id) if (success) { setCurrentProviderId(id) - // 移除阻塞式alert - console.log('供应商切换成功') + // 显示重启提示,时间更长 + showNotification('切换成功!请重启 Claude Code 终端以生效', 'success', 4000) } else { - console.error('切换失败,请检查配置') + showNotification('切换失败,请检查配置', 'error') } } @@ -70,17 +104,12 @@ function App() { await window.electronAPI.updateProvider(provider) await loadProviders() setEditingProviderId(null) - // 移除阻塞式alert,避免焦点管理问题 - setTimeout(() => { - console.log('供应商更新成功') - }, 100) + // 显示编辑成功提示,时间较短 + showNotification('供应商配置已保存', 'success', 2000) } catch (error) { console.error('更新供应商失败:', error) setEditingProviderId(null) - // 错误情况下也避免alert - setTimeout(() => { - console.error('保存失败,请重试') - }, 100) + showNotification('保存失败,请重试', 'error') } } @@ -106,13 +135,22 @@ function App() {
- + {/* 浮动通知组件 */} + {notification && ( +
+ {notification.message} +
+ )} + + + {configPath && (