import { getWaveformPreviewContent } from "./waveformPreviewContent";
import {
getModelSelectorContent,
getModelSelectorStyles,
getModelSelectorScript,
} from "./modelSelector";
import {
getModeSelectorContent,
getModeSelectorStyles,
getModeSelectorScript,
} from "./agentModeSelector";
import {
getContextButtonContent,
getContextButtonStyles,
getContextButtonScript,
} from "./contextButton";
import {
getContextDisplayContent,
getContextDisplayStyles,
getContextDisplayScript,
} from "./contextDisplay";
import {
getContextCompressContent,
getContextCompressStyles,
getContextCompressScript,
} from "./contextCompress";
import {
getFilePathTagStyles,
getFilePathTagScript,
} from "./filePathTag";
import {
getOptimizeButtonContent,
getOptimizeButtonStyles,
getOptimizeButtonScript,
} from "./optimizeButton";
import {
getExampleShowcaseContent,
getExampleShowcaseStyles,
getExampleShowcaseScript,
} from "./exampleShowcase";
import {
getChangePanelContent,
getChangePanelStyles,
getChangePanelScript,
} from "./changePanel";
import { sendIconSvg, stopIconSvg } from "../constants/toolIcons";
/**
* 获取输入区域的 HTML 内容
*/
export function getInputAreaContent(
autoIcon: string = "",
liteIcon: string = "",
syIcon: string = "",
maxIcon: string = ""
): string {
return `
`;
}
/**
* 获取输入区域的样式
*/
export function getInputAreaStyles(): string {
return `
${getModeSelectorStyles()}
${getModelSelectorStyles()}
${getContextButtonStyles()}
${getContextDisplayStyles()}
${getFilePathTagStyles()}
${getContextCompressStyles()}
${getOptimizeButtonStyles()}
${getExampleShowcaseStyles()}
${getChangePanelStyles()}
.input-area {
border-top: 1px solid var(--vscode-panel-border);
padding-top: 15px;
flex-shrink: 0;
transition: all 0.3s ease;
}
/* 居中模式:未发起对话时 */
.input-area.centered {
position: absolute;
top: 60%;
left: 50%;
transform: translate(-50%, -50%);
width: calc(100% - 40px);
max-width: 800px;
border-top: none;
padding-top: 0;
}
/* 底部模式:发起对话后 */
.input-area.bottom {
position: relative;
transform: none;
}
.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:disabled {
opacity: 0.5;
cursor: not-allowed;
background: rgba(128, 128, 128, 0.1);
}
/* 简洁的滚动条样式 */
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() 已在 webviewContent.ts 开头加载,这里不再重复加载
${getModelSelectorScript()}
${getContextDisplayScript()}
${getContextButtonScript()}
${getContextCompressScript()}
${getOptimizeButtonScript()}
${getChangePanelScript()}
${getFilePathTagScript()}
// 对话状态管理
let isConversationActive = false;
let hasMessages = false; // 是否已有消息
// 工作区检测状态
let hasCheckedWorkspace = false; // 是否已经检测过工作区
let hasWorkspace = true; // 工作区状态
${getExampleShowcaseScript()}
// 切换输入框布局模式
function updateInputAreaLayout() {
const inputArea = document.getElementById('inputArea');
if (!inputArea) return;
if (hasMessages) {
// 有消息时,移到底部
inputArea.classList.remove('centered');
inputArea.classList.add('bottom');
} else {
// 无消息时,居中显示
inputArea.classList.add('centered');
inputArea.classList.remove('bottom');
}
}
// 自动调整 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' });
}
// 检查试用期是否过期
vscode.postMessage({ command: 'checkTrialExpiration' });
// 检查邀请码验证状态
vscode.postMessage({ command: 'checkInvitationCode' });
});
// 初始化时调整一次高度
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;
// 禁用输入框
messageInput.disabled = true;
messageInput.placeholder = '正在处理中,请稍候...';
} else {
sendButton.classList.remove('sending');
sendIconContainer.style.display = 'block';
stopIconContainer.style.display = 'none';
isConversationActive = false;
// 启用输入框
messageInput.disabled = false;
messageInput.placeholder = '输入您的问题,按 Enter 发送,Shift + Enter 换行...';
}
}
// 处理发送或停止
function handleSendOrStop() {
if (isConversationActive) {
// 当前正在对话,执行停止操作
vscode.postMessage({ command: 'abortDialog' });
setSendButtonState(false);
} else {
// 当前未在对话,执行发送操作
sendMessage();
}
}
function sendMessage() {
const text = messageInput.value.trim();
if (!text) return;
// 如果正在对话中,阻止发送新消息
if (isConversationActive) {
return;
}
// 检查工作区状态
if (!hasWorkspace) {
// 如果没有工作区,阻止发送并清空输入框
messageInput.value = '';
autoResizeTextarea();
return;
}
const mode = getCurrentMode(); // 从模式选择器组件获取当前模式
const model = getCurrentModel(); // 从模型选择器组件获取当前模型
const planMode = document.getElementById('planToggle')?.checked || false;
// 获取上下文项
const contextItems = window.getContextItems ? window.getContextItems() : [];
// 构建显示消息:如果有上下文项,添加路径前缀
let displayText = text;
if (contextItems.length > 0) {
const contextPaths = contextItems
.map(item => item.displayPath || item.path)
.join(' ');
if (contextPaths) {
displayText = contextPaths + ' ' + text;
}
}
addMessage(displayText, 'user');
// 重置分段消息容器,强制下次创建新容器
currentSegmentedMessage = null;
// 标记已有消息,切换布局到底部
hasMessages = true;
updateInputAreaLayout();
// 切换按钮为暂停状态
setSendButtonState(true);
vscode.postMessage({
command: 'sendMessage',
text: text,
mode: mode,
model: model,
planMode: planMode,
contextItems: contextItems
});
messageInput.value = '';
autoResizeTextarea(); // 重置输入框高度
messageInput.focus();
// 清空上下文项
if (window.clearContextItems) {
window.clearContextItems();
}
// 重置优化状态
resetOptimizeButton();
}
// 全局函数:重置输入框布局(用于清空对话时)
window.resetInputAreaLayout = function() {
hasMessages = false;
updateInputAreaLayout();
};
// 全局函数:检查是否有消息(用于页面加载时)
window.checkMessagesAndUpdateLayout = function() {
const messagesContainer = document.getElementById('messages');
if (messagesContainer) {
const messageElements = messagesContainer.querySelectorAll('.message');
hasMessages = messageElements.length > 0;
updateInputAreaLayout();
}
};
// 页面加载时检查消息状态
setTimeout(() => {
if (window.checkMessagesAndUpdateLayout) {
window.checkMessagesAndUpdateLayout();
}
}, 100);
`;
}