diff --git a/src/constants/toolIcons.ts b/src/constants/toolIcons.ts index f8ad1a7..f551a16 100644 --- a/src/constants/toolIcons.ts +++ b/src/constants/toolIcons.ts @@ -175,3 +175,8 @@ export const stateTransitionIconSvg = ` * 用户提问图标 SVG */ export const userQuestionIconSvg = ``; + +/** + * 用户头像图标 SVG + */ +export const userAvatarIconSvg = ``; diff --git a/src/views/conversationHistoryBar.ts b/src/views/conversationHistoryBar.ts index 15ac3ae..1e8cde0 100644 --- a/src/views/conversationHistoryBar.ts +++ b/src/views/conversationHistoryBar.ts @@ -1,3 +1,10 @@ +import { + getUserInfoComponentContent, + getUserInfoComponentStyles, + getUserInfoComponentScript, +} from "./userInfoComponent"; +import { userAvatarIconSvg } from "../constants/toolIcons"; + /** * 获取会话历史栏的 HTML 内容 */ @@ -6,7 +13,7 @@ export function getConversationHistoryBarContent(): string {
- - - - + +
`; @@ -63,48 +68,56 @@ export function getConversationHistoryBarStyles(): string { .right-actions { display: flex; align-items: center; - gap: 12px; + gap: 8px; } - .user-info { + .user-info-container { + position: relative; + } + + .user-avatar-icon-button { + width: 36px; + height: 36px; + padding: 0; + background: transparent; + color: var(--vscode-foreground); + border: none; + border-radius: 50%; + cursor: pointer; display: flex; align-items: center; - gap: 6px; - padding: 6px 10px; - background: var(--vscode-button-secondaryBackground); - border-radius: 4px; - font-size: 13px; - color: var(--vscode-button-secondaryForeground); - } - - .user-icon { - width: 16px; - height: 16px; + justify-content: center; + transition: all 0.2s ease; flex-shrink: 0; } - .user-nickname { - white-space: nowrap; - max-width: 120px; - overflow: hidden; - text-overflow: ellipsis; + .user-avatar-icon-button:hover { + background: var(--vscode-toolbar-hoverBackground); + transform: scale(1.1); } - .tier-icon { - width: 110px; - height: 35px; - flex-shrink: 0; - object-fit: contain; - border-radius: 4px; + .user-avatar-icon-button:active { + transform: scale(0.95); } + .user-avatar-icon-button.active { + background: var(--vscode-toolbar-hoverBackground); + } + + .user-avatar-icon-button svg { + width: 20px; + height: 20px; + } + + ${getUserInfoComponentStyles()} + .history-dropdown-button { display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; background: transparent; - color: var(--vscode-input-foreground); + color: var(--vscode-foreground); border: none; border-radius: 4px; cursor: pointer; @@ -113,7 +126,7 @@ export function getConversationHistoryBarStyles(): string { } .history-dropdown-button:hover { - opacity: 0.8; + background: var(--vscode-toolbar-hoverBackground); } .dropdown-label { @@ -212,7 +225,7 @@ export function getConversationHistoryBarStyles(): string { background: transparent; color: var(--vscode-foreground); border: none; - border-radius: 4px; + border-radius: 50%; cursor: pointer; display: flex; align-items: center; @@ -222,11 +235,12 @@ export function getConversationHistoryBarStyles(): string { } .new-conversation-button:hover { - opacity: 0.7; + background: var(--vscode-toolbar-hoverBackground); + transform: scale(1.1); } .new-conversation-button:active { - opacity: 0.5; + transform: scale(0.95); } .new-conversation-button svg { @@ -259,6 +273,29 @@ export function getConversationHistoryBarStyles(): string { */ export function getConversationHistoryBarScript(): string { return ` + ${getUserInfoComponentScript()} + + // 更新用户头像图标按钮显示 + function updateUserAvatarIconButton(userInfo) { + const userAvatarIconButton = document.getElementById('userAvatarIconButton'); + + if (userInfo && userInfo.nickname) { + // 显示用户头像图标按钮 + if (userAvatarIconButton) { + userAvatarIconButton.style.display = 'flex'; + } + // 同时更新用户详情弹窗的数据 + if (typeof updateUserInfoDisplay === 'function') { + updateUserInfoDisplay(userInfo); + } + } else { + // 隐藏用户头像图标按钮 + if (userAvatarIconButton) { + userAvatarIconButton.style.display = 'none'; + } + } + } + // 会话历史相关变量 let conversationHistory = []; let currentConversationId = null; diff --git a/src/views/userInfoComponent.ts b/src/views/userInfoComponent.ts new file mode 100644 index 0000000..444ad59 --- /dev/null +++ b/src/views/userInfoComponent.ts @@ -0,0 +1,287 @@ +/** + * 用户信息组件 + * 包含用户头像、昵称、会员等级等信息 + */ + +/** + * 获取用户信息组件的 HTML 内容 + * 只包含用户详情下拉面板,不包含触发按钮 + */ +export function getUserInfoComponentContent(): string { + return ` +
+ +
+
+
+
+ + + +
+
+
加载中...
+ +
+
+ +
+
+ 剩余 Credits + - +
+
+
+
+
+ `; +} + +/** + * 获取用户信息组件的 CSS 样式 + */ +export function getUserInfoComponentStyles(): string { + return ` + .user-info-wrapper { + position: relative; + } + + /* 用户详情下拉面板 */ + .user-detail-dropdown { + display: none; + position: absolute; + top: calc(100% + 8px); + right: 0; + z-index: 10000; + min-width: 250px; + max-width: 320px; + } + + .user-detail-dropdown.active { + display: block; + animation: dropdownSlideIn 0.2s ease-out; + } + + @keyframes dropdownSlideIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + .user-detail-content { + background: var(--vscode-sideBar-background); + border: 1px solid var(--vscode-widget-border); + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + overflow: hidden; + } + + .user-detail-header { + padding: 16px; + display: flex; + align-items: center; + gap: 12px; + background: linear-gradient(135deg, rgba(0, 122, 204, 0.1) 0%, rgba(88, 166, 255, 0.05) 100%); + border-bottom: 1px solid var(--vscode-widget-border); + } + + .user-avatar-small { + width: 26px; + height: 26px; + flex-shrink: 0; + background: linear-gradient(135deg, #007acc 0%, #58a6ff 100%); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 8px rgba(0, 122, 204, 0.3); + } + + .user-avatar-small svg { + width: 18px; + height: 18px; + color: #ffffff; + } + + .user-name-tier { + flex: 1; + display: flex; + align-items: center; + gap: 8px; + } + + .user-detail-name { + font-size: 14px; + font-weight: 600; + color: var(--vscode-foreground); + } + + .tier-icon-inline { + height: 26px; + object-fit: contain; + } + + .user-detail-body { + padding: 12px; + background: var(--vscode-sideBar-background); + } + + .user-detail-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 12px; + margin-bottom: 6px; + background: var(--vscode-editor-background); + border-radius: 6px; + border: 1px solid var(--vscode-widget-border); + transition: all 0.2s ease; + } + + .user-detail-item:hover { + background: var(--vscode-list-hoverBackground); + border-color: rgba(0, 122, 204, 0.3); + } + + .user-detail-item:last-child { + margin-bottom: 0; + } + + .detail-label { + font-size: 12px; + font-weight: 500; + color: var(--vscode-descriptionForeground); + opacity: 0.8; + } + + .detail-value { + font-size: 12px; + font-weight: 500; + color: var(--vscode-foreground); + display: flex; + align-items: center; + gap: 6px; + } + + .tier-icon-large { + height: 20px; + object-fit: contain; + } + + .tier-icon { + width: 110px; + height: 35px; + flex-shrink: 0; + object-fit: contain; + border-radius: 4px; + } + `; +} + +/** + * 获取用户信息组件的 JavaScript 脚本 + */ +export function getUserInfoComponentScript(): string { + return ` + // 用户信息数据 + let currentUserInfo = null; + + // 切换用户详情下拉面板 + function openUserDetailModal() { + const dropdown = document.getElementById('userDetailDropdown'); + const userButton = document.getElementById('userAvatarIconButton'); + + if (dropdown) { + const isActive = dropdown.classList.contains('active'); + if (isActive) { + dropdown.classList.remove('active'); + if (userButton) { + userButton.classList.remove('active'); + } + } else { + dropdown.classList.add('active'); + if (userButton) { + userButton.classList.add('active'); + } + // 更新下拉面板中的用户信息 + updateUserDetailModal(); + } + } + } + + // 关闭用户详情下拉面板 + function closeUserDetailModal() { + const dropdown = document.getElementById('userDetailDropdown'); + const userButton = document.getElementById('userAvatarIconButton'); + + if (dropdown) { + dropdown.classList.remove('active'); + } + if (userButton) { + userButton.classList.remove('active'); + } + } + + // 更新用户详情下拉面板内容 + function updateUserDetailModal() { + if (!currentUserInfo) { + return; + } + + // 更新用户名 + const userDetailName = document.getElementById('userDetailName'); + if (userDetailName) { + userDetailName.textContent = currentUserInfo.nickname || '未知用户'; + } + + // 更新会员等级图标(显示在用户名旁边) + const tierIconInline = document.getElementById('tierIconInline'); + if (tierIconInline && currentUserInfo.tierIconUrl) { + tierIconInline.src = currentUserInfo.tierIconUrl; + tierIconInline.style.display = 'block'; + } else if (tierIconInline) { + tierIconInline.style.display = 'none'; + } + + // 更新剩余 Credits + const creditsDetail = document.getElementById('creditsDetail'); + if (creditsDetail) { + creditsDetail.textContent = currentUserInfo.credits !== undefined ? currentUserInfo.credits.toString() : '-'; + } + } + + // 更新用户信息显示 + function updateUserInfoDisplay(userInfo) { + currentUserInfo = userInfo; + } + + // 绑定下拉面板事件 + document.addEventListener('DOMContentLoaded', () => { + // 点击页面其他地方关闭下拉面板 + document.addEventListener('click', (e) => { + const dropdown = document.getElementById('userDetailDropdown'); + const userButton = document.getElementById('userAvatarIconButton'); + + if (dropdown && dropdown.classList.contains('active')) { + // 如果点击的不是用户按钮和下拉面板内容,则关闭 + if (!userButton?.contains(e.target) && !dropdown.contains(e.target)) { + closeUserDetailModal(); + } + } + }); + + // 阻止下拉面板内容点击事件冒泡 + const dropdownContent = document.querySelector('.user-detail-content'); + if (dropdownContent) { + dropdownContent.addEventListener('click', (e) => { + e.stopPropagation(); + }); + } + }); + `; +} diff --git a/src/views/webviewContent.ts b/src/views/webviewContent.ts index d6b05e2..9cd5e20 100644 --- a/src/views/webviewContent.ts +++ b/src/views/webviewContent.ts @@ -588,22 +588,21 @@ export function getWebviewContent( case 'updateUserInfo': // 更新用户信息 console.log('[WebView] 收到用户信息:', message.userInfo); - const userInfo = document.getElementById('userInfo'); - const userNickname = document.getElementById('userNickname'); - const tierIcon = document.getElementById('tierIcon'); - if (userInfo && userNickname && message.userInfo) { - const displayName = message.userInfo.nickname || message.userInfo.username || '用户'; - console.log('[WebView] 显示用户名:', displayName); - userNickname.textContent = displayName; + if (message.userInfo) { + const userInfoData = { + nickname: message.userInfo.nickname || message.userInfo.username || '用户', + userId: message.userInfo.userId || message.userInfo.id, + tierName: message.userInfo.tierName, + tierIconUrl: message.tierIconUrl, + registerTime: message.userInfo.registerTime || message.userInfo.createdAt + }; - // 显示会员等级图标 - if (tierIcon && message.tierIconUrl) { - tierIcon.src = message.tierIconUrl; - tierIcon.style.display = 'block'; - console.log('[WebView] 显示会员图标:', message.tierIconUrl); + console.log('[WebView] 显示用户信息:', userInfoData); + + // 调用更新用户头像图标按钮的函数 + if (typeof updateUserAvatarIconButton === 'function') { + updateUserAvatarIconButton(userInfoData); } - - userInfo.style.display = 'flex'; } break;