364 lines
9.7 KiB
TypeScript
364 lines
9.7 KiB
TypeScript
import { getWaveformPreviewContent } from "./waveformPreviewContent";
|
|
import {
|
|
getModelSelectorContent,
|
|
getModelSelectorStyles,
|
|
getModelSelectorScript
|
|
} from "./modelSelector";
|
|
import {
|
|
getModeSelectorContent,
|
|
getModeSelectorStyles,
|
|
getModeSelectorScript
|
|
} from "./agentModeSelector";
|
|
import {
|
|
getContextButtonContent,
|
|
getContextButtonStyles,
|
|
getContextButtonScript
|
|
} from "./contextButton";
|
|
import {
|
|
getContextCompressContent,
|
|
getContextCompressStyles,
|
|
getContextCompressScript
|
|
} from "./contextCompress";
|
|
import {
|
|
getPlanToggleContent,
|
|
getPlanToggleStyles,
|
|
getPlanToggleScript
|
|
} from "./planToggle";
|
|
import {
|
|
getOptimizeButtonContent,
|
|
getOptimizeButtonStyles,
|
|
getOptimizeButtonScript
|
|
} from "./optimizeButton";
|
|
import {
|
|
sendIconSvg,
|
|
stopIconSvg
|
|
} from "../constants/toolIcons";
|
|
|
|
/**
|
|
* 获取输入区域的 HTML 内容
|
|
*/
|
|
export function getInputAreaContent(): string {
|
|
return `
|
|
<div class="input-area">
|
|
<div class="input-group">
|
|
<div class="input-wrapper">
|
|
<!-- 顶部工具栏 -->
|
|
<div class="input-top-toolbar">
|
|
${getContextButtonContent()}
|
|
${getPlanToggleContent()}
|
|
</div>
|
|
<textarea
|
|
id="messageInput"
|
|
placeholder="输入您的问题..."
|
|
onkeydown="if(event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); sendMessage(); }"
|
|
></textarea>
|
|
<div class="input-bottom-row">
|
|
<div class="mode-selector">
|
|
${getModeSelectorContent()}
|
|
${getModelSelectorContent()}
|
|
</div>
|
|
<div class="input-actions">
|
|
${getContextCompressContent()}
|
|
${getOptimizeButtonContent()}
|
|
<button id="sendButton" onclick="handleSendOrStop()">
|
|
${sendIconSvg}
|
|
<span style="display: none;">${stopIconSvg}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 获取输入区域的样式
|
|
*/
|
|
export function getInputAreaStyles(): string {
|
|
return `
|
|
${getModeSelectorStyles()}
|
|
${getModelSelectorStyles()}
|
|
${getContextButtonStyles()}
|
|
${getContextCompressStyles()}
|
|
${getPlanToggleStyles()}
|
|
${getOptimizeButtonStyles()}
|
|
.input-area {
|
|
border-top: 1px solid var(--vscode-panel-border);
|
|
padding-top: 15px;
|
|
flex-shrink: 0;
|
|
}
|
|
.input-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
background: var(--vscode-input-background);
|
|
border: 1px solid var(--vscode-input-border);
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 6px rgba(0, 0, 0, 0.1);
|
|
transition: all 0.3s ease;
|
|
}
|
|
.input-group:hover {
|
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 8px rgba(0, 0, 0, 0.15);
|
|
}
|
|
.input-group:focus-within {
|
|
border-color: var(--vscode-focusBorder);
|
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25), 0 3px 10px rgba(0, 0, 0, 0.2);
|
|
}
|
|
.input-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
width: 100%;
|
|
}
|
|
/* 顶部工具栏样式 */
|
|
.input-top-toolbar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 8px;
|
|
gap: 12px;
|
|
}
|
|
.input-bottom-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
margin-bottom: -17px;
|
|
}
|
|
.mode-selector {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
position: relative;
|
|
}
|
|
.input-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
/* Tooltip 样式 */
|
|
.tooltip {
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
.tooltip .tooltiptext {
|
|
visibility: hidden;
|
|
width: auto;
|
|
background: #1e1e1e;
|
|
color: #ffffff;
|
|
text-align: center;
|
|
border-radius: 6px;
|
|
padding: 6px 12px;
|
|
position: absolute;
|
|
z-index: 1000;
|
|
bottom: 150%;
|
|
left: 50%;
|
|
transform: translateX(-50%) translateY(10px);
|
|
opacity: 0;
|
|
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.6), 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
white-space: nowrap;
|
|
letter-spacing: 0.3px;
|
|
}
|
|
.tooltip .tooltiptext::after {
|
|
content: "";
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 50%;
|
|
margin-left: -6px;
|
|
border-width: 6px;
|
|
border-style: solid;
|
|
border-color: #1e1e1e transparent transparent transparent;
|
|
}
|
|
.tooltip .tooltiptext::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 50%;
|
|
margin-left: -7px;
|
|
border-width: 7px;
|
|
border-style: solid;
|
|
border-color: rgba(255, 255, 255, 0.2) transparent transparent transparent;
|
|
z-index: -1;
|
|
}
|
|
.tooltip:hover .tooltiptext {
|
|
visibility: visible;
|
|
opacity: 1;
|
|
transform: translateX(-50%) translateY(0);
|
|
}
|
|
textarea {
|
|
width: 100%;
|
|
padding: 10px;
|
|
background: transparent;
|
|
color: var(--vscode-input-foreground);
|
|
border: none;
|
|
border-radius: 4px;
|
|
font-family: inherit;
|
|
resize: none;
|
|
min-height: 40px;
|
|
max-height: 200px;
|
|
outline: none;
|
|
box-sizing: border-box;
|
|
overflow-y: auto;
|
|
line-height: 1.5;
|
|
}
|
|
/* 简洁的滚动条样式 */
|
|
textarea::-webkit-scrollbar {
|
|
width: 8px;
|
|
}
|
|
textarea::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
textarea::-webkit-scrollbar-thumb {
|
|
background: rgba(128, 128, 128, 0.5);
|
|
border-radius: 4px;
|
|
}
|
|
textarea::-webkit-scrollbar-button {
|
|
display: none;
|
|
}
|
|
button {
|
|
padding: 0 20px;
|
|
background: var(--vscode-button-background);
|
|
color: var(--vscode-button-foreground);
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: background 0.2s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
button:hover {
|
|
background: var(--vscode-button-hoverBackground);
|
|
}
|
|
/* 发送按钮状态样式 */
|
|
#sendButton {
|
|
position: relative;
|
|
min-width: 32px;
|
|
padding: 6px 8px;
|
|
}
|
|
#sendButton svg {
|
|
width: 14px;
|
|
height: 14px;
|
|
display: block;
|
|
}
|
|
#sendButton.sending {
|
|
background: var(--vscode-button-background);
|
|
}
|
|
#sendButton.sending:hover {
|
|
background: var(--vscode-button-hoverBackground);
|
|
}
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 获取输入区域的脚本
|
|
*/
|
|
export function getInputAreaScript(): string {
|
|
return `
|
|
${getModeSelectorScript()}
|
|
${getModelSelectorScript()}
|
|
${getContextButtonScript()}
|
|
${getContextCompressScript()}
|
|
${getPlanToggleScript()}
|
|
${getOptimizeButtonScript()}
|
|
|
|
// 对话状态管理
|
|
let isConversationActive = false;
|
|
|
|
// 工作区检测状态
|
|
let hasCheckedWorkspace = false; // 是否已经检测过工作区
|
|
let hasWorkspace = true; // 工作区状态
|
|
|
|
// 自动调整 textarea 高度
|
|
function autoResizeTextarea() {
|
|
if (messageInput) {
|
|
messageInput.style.height = 'auto';
|
|
messageInput.style.height = messageInput.scrollHeight + 'px';
|
|
}
|
|
}
|
|
|
|
// 监听输入事件,自动调整高度
|
|
if (messageInput) {
|
|
messageInput.addEventListener('input', autoResizeTextarea);
|
|
|
|
// 监听点击事件,检测工作区状态
|
|
messageInput.addEventListener('focus', () => {
|
|
if (!hasCheckedWorkspace) {
|
|
hasCheckedWorkspace = true;
|
|
vscode.postMessage({ command: 'checkWorkspace' });
|
|
}
|
|
});
|
|
|
|
// 初始化时调整一次高度
|
|
autoResizeTextarea();
|
|
}
|
|
|
|
// 切换发送按钮状态
|
|
function setSendButtonState(isSending) {
|
|
const sendButton = document.getElementById('sendButton');
|
|
const children = sendButton.children;
|
|
const sendIconContainer = children[0]; // 第一个子元素是发送图标的 SVG
|
|
const stopIconContainer = children[1]; // 第二个子元素是包含暂停图标的 span
|
|
|
|
if (isSending) {
|
|
sendButton.classList.add('sending');
|
|
sendIconContainer.style.display = 'none';
|
|
stopIconContainer.style.display = 'block';
|
|
isConversationActive = true;
|
|
} else {
|
|
sendButton.classList.remove('sending');
|
|
sendIconContainer.style.display = 'block';
|
|
stopIconContainer.style.display = 'none';
|
|
isConversationActive = false;
|
|
}
|
|
}
|
|
|
|
// 处理发送或停止
|
|
function handleSendOrStop() {
|
|
if (isConversationActive) {
|
|
// 当前正在对话,执行停止操作
|
|
vscode.postMessage({ command: 'abortDialog' });
|
|
setSendButtonState(false);
|
|
} else {
|
|
// 当前未在对话,执行发送操作
|
|
sendMessage();
|
|
}
|
|
}
|
|
|
|
function sendMessage() {
|
|
const text = messageInput.value.trim();
|
|
if (!text) return;
|
|
|
|
// 检查工作区状态
|
|
if (!hasWorkspace) {
|
|
// 如果没有工作区,阻止发送并清空输入框
|
|
messageInput.value = '';
|
|
autoResizeTextarea();
|
|
return;
|
|
}
|
|
|
|
const mode = getCurrentMode(); // 从模式选择器组件获取当前模式
|
|
const model = getCurrentModel(); // 从模型选择器组件获取当前模型
|
|
|
|
addMessage(text, 'user');
|
|
|
|
// 切换按钮为暂停状态
|
|
setSendButtonState(true);
|
|
|
|
vscode.postMessage({ command: 'sendMessage', text: text, mode: mode, model: model });
|
|
messageInput.value = '';
|
|
autoResizeTextarea(); // 重置输入框高度
|
|
messageInput.focus();
|
|
|
|
// 重置优化状态
|
|
resetOptimizeButton();
|
|
}
|
|
`;
|
|
}
|