From ff15dc6e9f81e66a9db6a415ee08b7d0bef28f9d Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 6 May 2026 22:36:11 +0800 Subject: [PATCH] fix: polish chat page refactor --- electron/main.ts | 25 +++++-- src/components/MessageBubble.tsx | 36 ---------- src/pages/Chat/ChatInputArea.tsx | 42 ------------ src/pages/ChatHistoryPage.scss | 6 +- src/pages/ChatPage.scss | 111 ++++++------------------------- src/pages/ChatPage.tsx | 2 - 6 files changed, 42 insertions(+), 180 deletions(-) delete mode 100644 src/components/MessageBubble.tsx delete mode 100644 src/pages/Chat/ChatInputArea.tsx diff --git a/electron/main.ts b/electron/main.ts index 76688c3..59815fe 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -1309,9 +1309,6 @@ function createChatHistoryRouteWindow(route: string) { ? join(process.resourcesPath, 'icon.icns') : join(process.resourcesPath, 'icon.ico')) - // 根据系统主题设置窗口背景色 - const isDark = nativeTheme.shouldUseDarkColors - const win = new BrowserWindow({ width: 600, height: 800, @@ -1326,13 +1323,31 @@ function createChatHistoryRouteWindow(route: string) { titleBarStyle: 'hidden', titleBarOverlay: false, show: false, - backgroundColor: isDark ? '#1A1A1A' : '#F0F0F0', + backgroundColor: '#FFFFFF', autoHideMenuBar: true }) setupCustomTitleBarWindow(win) - win.once('ready-to-show', () => { + let hasShown = false + let isReadyToShow = false + let hasLoadedRoute = false + const showChatHistoryWindow = () => { + if (hasShown || !isReadyToShow || !hasLoadedRoute || win.isDestroyed()) return + hasShown = true win.show() + } + + win.webContents.once('did-finish-load', () => { + hasLoadedRoute = true + setTimeout(showChatHistoryWindow, 30) + }) + win.webContents.once('did-fail-load', () => { + hasLoadedRoute = true + showChatHistoryWindow() + }) + win.once('ready-to-show', () => { + isReadyToShow = true + showChatHistoryWindow() }) if (process.env.VITE_DEV_SERVER_URL) { diff --git a/src/components/MessageBubble.tsx b/src/components/MessageBubble.tsx deleted file mode 100644 index c807584..0000000 --- a/src/components/MessageBubble.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import { Bot, User } from 'lucide-react' - -interface ChatMessage { - id: string; - role: 'user' | 'ai'; - content: string; - timestamp: number; -} - -interface MessageBubbleProps { - message: ChatMessage; -} - -/** - * 优化后的消息气泡组件 - * 使用 React.memo 避免不必要的重新渲染 - */ -export const MessageBubble = React.memo(({ message }) => { - return ( -
-
- {message.role === 'ai' ? : } -
-
-
{message.content}
-
-
- ) -}, (prevProps, nextProps) => { - // 自定义比较函数:只有内容或ID变化时才重新渲染 - return prevProps.message.content === nextProps.message.content && - prevProps.message.id === nextProps.message.id -}) - -MessageBubble.displayName = 'MessageBubble' diff --git a/src/pages/Chat/ChatInputArea.tsx b/src/pages/Chat/ChatInputArea.tsx deleted file mode 100644 index c8303d5..0000000 --- a/src/pages/Chat/ChatInputArea.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react' -import { Lock, Search } from 'lucide-react' - -export interface ChatInputAreaProps { - disabled?: boolean - placeholder?: string - onFocusSearch?: () => void -} - -function ChatInputArea({ - disabled = true, - placeholder = '聊天记录', - onFocusSearch -}: ChatInputAreaProps) { - return ( -
- -
- - {placeholder} -
-
- ) -} - -function areEqual(prev: ChatInputAreaProps, next: ChatInputAreaProps) { - return ( - prev.disabled === next.disabled && - prev.placeholder === next.placeholder && - prev.onFocusSearch === next.onFocusSearch - ) -} - -export default React.memo(ChatInputArea, areEqual) diff --git a/src/pages/ChatHistoryPage.scss b/src/pages/ChatHistoryPage.scss index 7465fae..3bc96b5 100644 --- a/src/pages/ChatHistoryPage.scss +++ b/src/pages/ChatHistoryPage.scss @@ -2,8 +2,8 @@ display: flex; flex-direction: column; height: 100vh; - background: - linear-gradient(180deg, color-mix(in srgb, var(--bg-primary) 96%, white) 0%, var(--bg-primary) 100%); + color: var(--text-primary); + background: var(--bg-primary); .history-list { flex: 1; @@ -149,7 +149,7 @@ .nested-chat-record-card { min-width: 220px; max-width: 320px; - background: color-mix(in srgb, var(--bg-secondary) 97%, #f5f7fb); + background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 14px; overflow: hidden; diff --git a/src/pages/ChatPage.scss b/src/pages/ChatPage.scss index 39ad989..9b79cd2 100644 --- a/src/pages/ChatPage.scss +++ b/src/pages/ChatPage.scss @@ -2730,13 +2730,9 @@ width: clamp(280px, 25vw, 360px); min-width: 280px; max-width: 360px; - background: linear-gradient( - 180deg, - color-mix(in srgb, var(--card-bg) 94%, #fff 6%) 0%, - var(--card-bg) 100% - ); + background: var(--bg-primary); border-left: 1px solid color-mix(in srgb, var(--border-color) 82%, transparent); - box-shadow: -14px 0 28px rgba(0, 0, 0, 0.07); + box-shadow: var(--shadow-sm); display: flex; flex-direction: column; overflow: hidden; @@ -2749,7 +2745,7 @@ justify-content: space-between; gap: 8px; padding: 14px 14px 12px; - background: color-mix(in srgb, var(--card-bg) 92%, #fff 8%); + background: var(--bg-primary); border-bottom: 1px solid var(--border-color); position: sticky; top: 0; @@ -2850,7 +2846,7 @@ padding: 12px; border-radius: 12px; border: 1px solid color-mix(in srgb, var(--border-color) 80%, transparent); - background: color-mix(in srgb, var(--bg-secondary) 84%, transparent); + background: var(--bg-secondary); animation: detailCardEnter 0.24s ease both; .detail-overview-avatar { @@ -2891,7 +2887,7 @@ padding: 12px; border-radius: 12px; border: 1px solid color-mix(in srgb, var(--border-color) 72%, transparent); - background: color-mix(in srgb, var(--bg-secondary) 86%, transparent); + background: var(--bg-secondary); animation: detailCardEnter 0.24s ease both; .section-title { @@ -2917,7 +2913,7 @@ border-radius: 8px; font-size: 12px; color: var(--text-tertiary); - background: color-mix(in srgb, var(--card-bg) 84%, transparent); + background: var(--card-bg); } } @@ -5384,8 +5380,8 @@ .message-list { background: var(--bg-primary); - padding: 18px clamp(16px, 3vw, 48px) 104px; - padding-bottom: calc(104px + env(safe-area-inset-bottom)); + padding: 18px clamp(16px, 3vw, 48px) 28px; + padding-bottom: calc(28px + env(safe-area-inset-bottom)); } } } @@ -5447,8 +5443,8 @@ .message-list { background: var(--bg-primary); - padding: 18px clamp(16px, 3vw, 48px) 104px; - padding-bottom: calc(104px + env(safe-area-inset-bottom)); + padding: 18px clamp(16px, 3vw, 48px) 28px; + padding-bottom: calc(28px + env(safe-area-inset-bottom)); gap: 0; } @@ -5536,8 +5532,8 @@ &.sent { .bubble-content { - background: #3b82f6; - color: #fff; + background: var(--primary); + color: var(--on-primary); border-radius: 18px; } @@ -5624,12 +5620,12 @@ } .message-bubble.sent .quoted-message { - background: color-mix(in srgb, #fff 12%, transparent); - border-left-color: color-mix(in srgb, #fff 62%, #3b82f6); + background: color-mix(in srgb, var(--on-primary) 12%, transparent); + border-left-color: color-mix(in srgb, var(--on-primary) 62%, var(--primary)); .quoted-sender, .quoted-text { - color: color-mix(in srgb, #fff 82%, #3b82f6); + color: color-mix(in srgb, var(--on-primary) 82%, var(--primary)); } } @@ -5765,82 +5761,18 @@ .hongbao-message, .transfer-message, .gift-message { - background: #2b2b2b; - border-color: rgba(255, 255, 255, 0.08); + background: var(--card-bg); + border-color: var(--border-color); } .message-bubble.received .bubble-content, .message-bubble.voice.sent .bubble-content { - background: #2f2f2f; + background: var(--bg-secondary); } } -.chat-input-area { - position: absolute; - left: max(18px, env(safe-area-inset-left)); - right: max(18px, env(safe-area-inset-right)); - bottom: calc(14px + env(safe-area-inset-bottom)); - z-index: 5; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - pointer-events: none; - - &::before { - content: ''; - position: absolute; - left: -18px; - right: -18px; - bottom: -14px; - height: 86px; - background: linear-gradient(to top, var(--bg-primary) 62%, transparent); - pointer-events: none; - z-index: -1; - } -} - -.chat-input-search-btn, -.chat-input-shell { - height: 44px; - border: 1px solid var(--border-color); - background: color-mix(in srgb, var(--bg-primary) 92%, transparent); - color: var(--text-secondary); - box-shadow: var(--shadow-sm); - backdrop-filter: blur(14px); -} - -.chat-input-search-btn { - width: 44px; - border-radius: 12px; - display: grid; - place-items: center; - cursor: pointer; - pointer-events: auto; - - &:hover:not(:disabled) { - background: var(--bg-hover); - color: var(--text-primary); - } - - &:disabled { - cursor: default; - opacity: 0.72; - } -} - -.chat-input-shell { - width: min(680px, 100%); - border-radius: 14px; - padding: 0 14px; - display: flex; - align-items: center; - gap: 8px; - font-size: 13px; -} - .scroll-to-bottom { - bottom: 74px; + bottom: 20px; background: color-mix(in srgb, var(--bg-primary) 92%, transparent); color: var(--text-primary); border: 1px solid var(--border-color); @@ -5873,9 +5805,4 @@ .message-bubble { max-width: 88%; } - - .chat-input-area { - left: 12px; - right: 12px; - } } diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index e8b320f..714c2a2 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -30,7 +30,6 @@ import { requestExportSessionStatus } from '../services/exportBridge' import ChatHeader from './Chat/ChatHeader' -import ChatInputArea from './Chat/ChatInputArea' import ChatMessageBubble from './Chat/ChatMessageBubble' import '../styles/batchTranscribe.scss' import './ChatPage.scss' @@ -7202,7 +7201,6 @@ function ChatPage(props: ChatPageProps) { 回到底部 - {/* 群成员面板 */} {showGroupMembersPanel && isCurrentSessionGroup && (