mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix(vscode-ide-companion): 修复 Tailwind 可重用组件类和 ESLint 配置, 调整 ChatHeader 按钮样式
- 在 tailwind.css 中正确定义可重用的 Tailwind 组件类 - 修复 ChatHeader 组件中的按钮样式,确保 hover 效果正常工作 - 修复 ESLint 配置中的 importPlugin 导入问题 - 清理 App.css 中重复的 CSS 变量定义 - 为 btn-ghost 类设置 4px border radius - 为按钮内的 span 添加左右 4px padding (使用 px-1) - 确保按钮 hover 时有背景色效果
This commit is contained in:
@@ -1,199 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Session Manager Styles */
|
||||
.session-manager {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
}
|
||||
|
||||
.session-manager-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid var(--app-primary-border-color);
|
||||
}
|
||||
|
||||
.session-manager-header h3 {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
color: var(--app-primary-foreground);
|
||||
}
|
||||
|
||||
.session-manager-actions {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid var(--app-primary-border-color);
|
||||
}
|
||||
|
||||
.session-manager-actions .secondary-button {
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
background: var(--vscode-button-secondaryBackground);
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.session-manager-actions .secondary-button:hover {
|
||||
background: var(--vscode-button-secondaryHoverBackground);
|
||||
}
|
||||
|
||||
.session-search {
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-bottom: 1px solid var(--app-primary-border-color);
|
||||
}
|
||||
|
||||
.session-search svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.5;
|
||||
flex-shrink: 0;
|
||||
color: var(--app-primary-foreground);
|
||||
}
|
||||
|
||||
.session-search input {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: var(--app-primary-foreground);
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.session-search input::placeholder {
|
||||
color: var(--app-input-placeholder-foreground);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.session-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.session-list-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 32px;
|
||||
gap: 8px;
|
||||
color: var(--app-secondary-foreground);
|
||||
}
|
||||
|
||||
.session-list-empty {
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
color: var(--app-secondary-foreground);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.session-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
color: var(--app-primary-foreground);
|
||||
transition: background 0.1s ease;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.session-item:hover {
|
||||
background: var(--app-list-hover-background);
|
||||
}
|
||||
|
||||
.session-item.active {
|
||||
background: var(--app-list-active-background);
|
||||
color: var(--app-list-active-foreground);
|
||||
}
|
||||
|
||||
.session-item-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.session-item-name {
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.session-item-meta {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
font-size: 0.9em;
|
||||
color: var(--app-secondary-foreground);
|
||||
}
|
||||
|
||||
.session-item-date,
|
||||
.session-item-count {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.session-item-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.session-item-actions .icon-button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.session-item-actions .icon-button:hover {
|
||||
background: var(--app-ghost-button-hover-background);
|
||||
}
|
||||
|
||||
.session-item-actions .icon-button svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--app-primary-foreground);
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid transparent;
|
||||
border-top: 2px solid currentColor;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useVSCode } from '../hooks/useVSCode.js';
|
||||
import {
|
||||
RefreshIcon,
|
||||
SaveDocumentIcon,
|
||||
SearchIcon,
|
||||
PlayIcon,
|
||||
SwitchIcon,
|
||||
} from './icons/index.js';
|
||||
|
||||
interface Session {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdated: string;
|
||||
messageCount: number;
|
||||
}
|
||||
|
||||
interface SessionManagerProps {
|
||||
currentSessionId: string | null;
|
||||
onSwitchSession: (sessionId: string) => void;
|
||||
onSaveSession: () => void;
|
||||
onResumeSession: (sessionId: string) => void;
|
||||
}
|
||||
|
||||
export const SessionManager: React.FC<SessionManagerProps> = ({
|
||||
currentSessionId,
|
||||
onSwitchSession,
|
||||
onSaveSession,
|
||||
onResumeSession,
|
||||
}) => {
|
||||
const vscode = useVSCode();
|
||||
const [sessions, setSessions] = useState<Session[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
const loadSessions = React.useCallback(() => {
|
||||
setIsLoading(true);
|
||||
vscode.postMessage({
|
||||
type: 'listSavedSessions',
|
||||
data: {},
|
||||
});
|
||||
}, [vscode]);
|
||||
|
||||
// Load sessions when component mounts
|
||||
useEffect(() => {
|
||||
loadSessions();
|
||||
}, [loadSessions]);
|
||||
|
||||
// Listen for session list updates
|
||||
useEffect(() => {
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
const message = event.data;
|
||||
|
||||
if (message.type === 'savedSessionsList') {
|
||||
setIsLoading(false);
|
||||
setSessions(message.data.sessions || []);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', handleMessage);
|
||||
return () => window.removeEventListener('message', handleMessage);
|
||||
}, []);
|
||||
|
||||
const filteredSessions = sessions.filter((session) =>
|
||||
session.name.toLowerCase().includes(searchQuery.toLowerCase()),
|
||||
);
|
||||
|
||||
const handleSaveCurrent = () => {
|
||||
onSaveSession();
|
||||
};
|
||||
|
||||
const handleResumeSession = (sessionId: string) => {
|
||||
onResumeSession(sessionId);
|
||||
};
|
||||
|
||||
const handleSwitchSession = (sessionId: string) => {
|
||||
onSwitchSession(sessionId);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="session-manager">
|
||||
<div className="session-manager-header">
|
||||
<h3>Saved Conversations</h3>
|
||||
<button
|
||||
className="icon-button"
|
||||
onClick={loadSessions}
|
||||
disabled={isLoading}
|
||||
title="Refresh sessions"
|
||||
>
|
||||
<RefreshIcon width="16" height="16" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="session-manager-actions">
|
||||
<button className="secondary-button" onClick={handleSaveCurrent}>
|
||||
<SaveDocumentIcon width="16" height="16" />
|
||||
Save Current
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="session-search">
|
||||
<SearchIcon width="16" height="16" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search conversations..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="session-list">
|
||||
{isLoading ? (
|
||||
<div className="session-list-loading">
|
||||
<div className="loading-spinner"></div>
|
||||
<span>Loading conversations...</span>
|
||||
</div>
|
||||
) : filteredSessions.length === 0 ? (
|
||||
<div className="session-list-empty">
|
||||
{searchQuery
|
||||
? 'No matching conversations'
|
||||
: 'No saved conversations yet'}
|
||||
</div>
|
||||
) : (
|
||||
filteredSessions.map((session) => (
|
||||
<div
|
||||
key={session.id}
|
||||
className={`session-item ${session.id === currentSessionId ? 'active' : ''}`}
|
||||
>
|
||||
<div className="session-item-info">
|
||||
<div className="session-item-name">{session.name}</div>
|
||||
<div className="session-item-meta">
|
||||
<span className="session-item-date">
|
||||
{new Date(session.lastUpdated).toLocaleDateString()}
|
||||
</span>
|
||||
<span className="session-item-count">
|
||||
{session.messageCount}{' '}
|
||||
{session.messageCount === 1 ? 'message' : 'messages'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="session-item-actions">
|
||||
<button
|
||||
className="icon-button"
|
||||
onClick={() => handleResumeSession(session.id)}
|
||||
title="Resume this conversation"
|
||||
>
|
||||
<PlayIcon width="16" height="16" />
|
||||
</button>
|
||||
<button
|
||||
className="icon-button"
|
||||
onClick={() => handleSwitchSession(session.id)}
|
||||
title="Switch to this conversation"
|
||||
>
|
||||
<SwitchIcon width="16" height="16" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -21,39 +21,26 @@ export const ChatHeader: React.FC<ChatHeaderProps> = ({
|
||||
onNewSession,
|
||||
}) => (
|
||||
<div
|
||||
className="flex gap-1 select-none py-1.5 px-2.5"
|
||||
className="chat-header flex items-center select-none py-1.5 px-2.5 w-full"
|
||||
style={{
|
||||
backgroundColor: 'var(--app-header-background)',
|
||||
}}
|
||||
>
|
||||
{/* Past Conversations Button */}
|
||||
<button
|
||||
className="flex-none py-1 px-2 bg-transparent border border-transparent rounded cursor-pointer flex items-center justify-center outline-none font-medium transition-colors duration-200 hover:bg-[var(--app-ghost-button-hover-background)] focus:bg-[var(--app-ghost-button-hover-background)]"
|
||||
style={{
|
||||
borderRadius: 'var(--corner-radius-small)',
|
||||
color: 'var(--app-primary-foreground)',
|
||||
fontSize: 'var(--vscode-chat-font-size, 13px)',
|
||||
}}
|
||||
className="btn-ghost btn-md px-2 flex items-center outline-none font-medium max-w-[70%] min-w-0 overflow-hidden rounded hover:bg-[var(--app-ghost-button-hover-background)] h-6 leading-6"
|
||||
onClick={onLoadSessions}
|
||||
title="Past conversations"
|
||||
>
|
||||
<span className="flex items-center gap-1">
|
||||
<span style={{ fontSize: 'var(--vscode-chat-font-size, 13px)' }}>
|
||||
{currentSessionTitle}
|
||||
</span>
|
||||
<ChevronDownIcon className="w-3.5 h-3.5" />
|
||||
<span className="whitespace-nowrap overflow-hidden text-ellipsis min-w-0">
|
||||
{currentSessionTitle}
|
||||
</span>
|
||||
<ChevronDownIcon className="w-4 h-4 flex-shrink-0 ml-1" />
|
||||
</button>
|
||||
|
||||
{/* Spacer */}
|
||||
<div className="flex-1"></div>
|
||||
<div className="flex-1 min-w-2"></div>
|
||||
|
||||
{/* New Session Button */}
|
||||
<button
|
||||
className="flex-none p-0 bg-transparent border border-transparent rounded cursor-pointer flex items-center justify-center outline-none w-6 h-6 hover:bg-[var(--app-ghost-button-hover-background)] focus:bg-[var(--app-ghost-button-hover-background)]"
|
||||
style={{
|
||||
color: 'var(--app-primary-foreground)',
|
||||
}}
|
||||
className="btn-ghost btn-sm flex items-center justify-center outline-none rounded hover:bg-[var(--app-ghost-button-hover-background)] h-6 leading-6 w-6"
|
||||
onClick={onNewSession}
|
||||
title="New Session"
|
||||
>
|
||||
|
||||
@@ -40,22 +40,25 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="session-selector-backdrop" onClick={onClose} />
|
||||
<div
|
||||
className="session-dropdown"
|
||||
className="session-selector-backdrop fixed top-0 left-0 right-0 bottom-0 z-[999] bg-transparent"
|
||||
onClick={onClose}
|
||||
/>
|
||||
<div
|
||||
className="session-dropdown fixed bg-[var(--app-menu-background)] rounded-[var(--corner-radius-small)] w-[min(400px,calc(100vw-32px))] max-h-[min(500px,50vh)] flex flex-col shadow-[0_4px_16px_rgba(0,0,0,0.1)] z-[1000] outline-none text-[var(--vscode-chat-font-size,13px)] font-[var(--vscode-chat-font-family)]"
|
||||
tabIndex={-1}
|
||||
style={{
|
||||
top: '34px',
|
||||
top: '30px',
|
||||
left: '10px',
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Search Box */}
|
||||
<div className="session-search">
|
||||
<SearchIcon className="session-search-icon" />
|
||||
<div className="session-search p-2 flex items-center gap-2">
|
||||
<SearchIcon className="session-search-icon w-4 h-4 opacity-50 flex-shrink-0 text-[var(--app-primary-foreground)]" />
|
||||
<input
|
||||
type="text"
|
||||
className="session-search-input"
|
||||
className="session-search-input flex-1 bg-transparent border-none outline-none text-[var(--app-menu-foreground)] text-[var(--vscode-chat-font-size,13px)] font-[var(--vscode-chat-font-family)] p-0 placeholder:text-[var(--app-input-placeholder-foreground)] placeholder:opacity-60"
|
||||
placeholder="Search sessions…"
|
||||
value={searchQuery}
|
||||
onChange={(e) => onSearchChange(e.target.value)}
|
||||
@@ -63,9 +66,10 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
||||
</div>
|
||||
|
||||
{/* Session List with Grouping */}
|
||||
<div className="session-list-content">
|
||||
<div className="session-list-content overflow-y-auto flex-1 select-none p-2">
|
||||
{hasNoSessions ? (
|
||||
<div
|
||||
className="p-5 text-center text-[var(--app-secondary-foreground)]"
|
||||
style={{
|
||||
padding: '20px',
|
||||
textAlign: 'center',
|
||||
@@ -77,8 +81,10 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
||||
) : (
|
||||
groupSessionsByDate(sessions).map((group) => (
|
||||
<React.Fragment key={group.label}>
|
||||
<div className="session-group-label">{group.label}</div>
|
||||
<div className="session-group">
|
||||
<div className="session-group-label p-1 px-2 text-[var(--app-primary-foreground)] opacity-50 text-[0.9em] font-medium [&:not(:first-child)]:mt-2">
|
||||
{group.label}
|
||||
</div>
|
||||
<div className="session-group flex flex-col gap-[2px]">
|
||||
{group.sessions.map((session) => {
|
||||
const sessionId =
|
||||
(session.id as string) ||
|
||||
@@ -97,14 +103,20 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
||||
return (
|
||||
<button
|
||||
key={sessionId}
|
||||
className={`session-item ${isActive ? 'active' : ''}`}
|
||||
className={`session-item flex items-center justify-between py-1.5 px-2 bg-transparent border-none rounded-md cursor-pointer text-left w-full text-[var(--vscode-chat-font-size,13px)] font-[var(--vscode-chat-font-family)] text-[var(--app-primary-foreground)] transition-colors duration-100 hover:bg-[var(--app-list-hover-background)] ${
|
||||
isActive
|
||||
? 'active bg-[var(--app-list-active-background)] text-[var(--app-list-active-foreground)] font-[600]'
|
||||
: ''
|
||||
}`}
|
||||
onClick={() => {
|
||||
onSelectSession(sessionId);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<span className="session-item-title">{title}</span>
|
||||
<span className="session-item-time">
|
||||
<span className="session-item-title flex-1 overflow-hidden text-ellipsis whitespace-nowrap min-w-0">
|
||||
{title}
|
||||
</span>
|
||||
<span className="session-item-time opacity-60 text-[0.9em] flex-shrink-0 ml-3">
|
||||
{getTimeAgo(lastUpdated)}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@@ -88,9 +88,6 @@
|
||||
/* Widget */
|
||||
--app-widget-border: var(--vscode-editorWidget-border);
|
||||
--app-widget-shadow: var(--vscode-widget-shadow);
|
||||
|
||||
/* Ghost Button (from Claude Code) */
|
||||
--app-ghost-button-hover-background: var(--vscode-toolbar-hoverBackground);
|
||||
}
|
||||
|
||||
/* Light Theme Overrides */
|
||||
@@ -592,4 +589,4 @@ button {
|
||||
.permission-success-text {
|
||||
color: #4caf50;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
/* Import component styles */
|
||||
@import '../components/SaveSessionDialog.css';
|
||||
@import '../components/SessionManager.css';
|
||||
@import '../components/EmptyState.css';
|
||||
@import '../components/CompletionMenu.css';
|
||||
@import '../components/ContextPills.css';
|
||||
@@ -19,220 +18,6 @@
|
||||
@import '../components/toolcalls/shared/DiffDisplay.css';
|
||||
@import '../components/messages/AssistantMessage.css';
|
||||
|
||||
/* ===========================
|
||||
Session Selector Button (from Claude Code .E)
|
||||
=========================== */
|
||||
.session-selector-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 2px 8px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
}
|
||||
|
||||
.session-selector-button:focus,
|
||||
.session-selector-button:hover {
|
||||
background: var(--app-ghost-button-hover-background);
|
||||
}
|
||||
|
||||
/* Session Selector Button Internal Elements */
|
||||
.session-selector-button-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.session-selector-button-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.session-selector-button-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.session-selector-button-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Icon Button (from Claude Code .j)
|
||||
=========================== */
|
||||
.icon-button {
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
outline: none;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.icon-button:focus,
|
||||
.icon-button:hover {
|
||||
background: var(--app-ghost-button-hover-background);
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Session Dropdown (from Claude Code .St/.Wt)
|
||||
=========================== */
|
||||
.session-dropdown {
|
||||
position: fixed;
|
||||
background: var(--app-menu-background);
|
||||
border: 1px solid var(--app-menu-border);
|
||||
border-radius: var(--corner-radius-small);
|
||||
width: min(400px, calc(100vw - 32px));
|
||||
max-height: min(500px, 50vh);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
outline: none;
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Search Box Container (from Claude Code .Lt)
|
||||
=========================== */
|
||||
.session-search {
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-bottom: 1px solid var(--app-menu-border);
|
||||
}
|
||||
|
||||
.session-search svg,
|
||||
.session-search-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.5;
|
||||
flex-shrink: 0;
|
||||
color: var(--app-primary-foreground);
|
||||
}
|
||||
|
||||
/* Search Input (from Claude Code .U) */
|
||||
.session-search-input {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: var(--app-menu-foreground);
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.session-search-input::placeholder {
|
||||
color: var(--app-input-placeholder-foreground);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* Session List Content Area (from Claude Code .jt/.It) */
|
||||
.session-list-content {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
/* Group Label (from Claude Code .ae) */
|
||||
.session-group-label {
|
||||
padding: 4px 8px;
|
||||
color: var(--app-primary-foreground);
|
||||
opacity: 0.5;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.session-group-label:not(:first-child) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Session Group Container (from Claude Code .At) */
|
||||
.session-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
/* Session Item Button (from Claude Code .s) */
|
||||
.session-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 6px 8px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
color: var(--app-primary-foreground);
|
||||
transition: background 0.1s ease;
|
||||
}
|
||||
|
||||
.session-item:hover {
|
||||
background: var(--app-list-hover-background);
|
||||
}
|
||||
|
||||
/* Active Session (from Claude Code .N) */
|
||||
.session-item.active {
|
||||
background: var(--app-list-active-background);
|
||||
color: var(--app-list-active-foreground);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Session Title (from Claude Code .ce) */
|
||||
.session-item-title {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Session Time (from Claude Code .Dt) */
|
||||
.session-item-time {
|
||||
opacity: 0.6;
|
||||
font-size: 0.9em;
|
||||
flex-shrink: 0;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
/* Backdrop for dropdown */
|
||||
.session-selector-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
CSS Variables (from Claude Code root styles)
|
||||
|
||||
@@ -6,4 +6,33 @@
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ===========================
|
||||
Reusable Component Classes
|
||||
=========================== */
|
||||
@layer components {
|
||||
.btn-ghost {
|
||||
@apply bg-transparent border border-transparent rounded cursor-pointer outline-none transition-colors duration-200;
|
||||
color: var(--app-primary-foreground);
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.btn-ghost:hover,
|
||||
.btn-ghost:focus {
|
||||
background: var(--app-ghost-button-hover-background);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
@apply p-small;
|
||||
}
|
||||
|
||||
.btn-md {
|
||||
@apply py-small px-medium;
|
||||
}
|
||||
|
||||
.icon-sm {
|
||||
@apply w-4 h-4;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user