fix(frontend): 修复工具参数换行、记忆片段溢出与右侧侧边栏拖拽

- 工具参数区补 white-space: pre-wrap,多行参数(如 run_command 指令)真实换行而非挤作一团被动折行

- 记忆搜索匹配片段改逐行渲染 + nowrap/ellipsis 截断(pre 不换行会溢出容器),悬停 title 看全文

- 恢复 resize-handle--right-panels 基础样式(b593d638 删 _left-panel.scss 时误删,手柄零宽导致 git/终端面板无法拖宽),热区扩至 10px

- FilePreviewPanel 新增左缘拖拽调宽(320-860px,localStorage 持久化),此前从未有过该能力
This commit is contained in:
JOJO 2026-07-31 22:39:18 +08:00
parent 7aab7da8aa
commit 89effa71a8
5 changed files with 129 additions and 6 deletions

View File

@ -89,6 +89,10 @@ function renderToolResult(): string {
.tool-result-meta > div {
margin: 4px 0;
/* command/content
否则多行内容会挤成一行仅靠容器宽度被动折行 */
white-space: pre-wrap;
word-break: break-word;
}
.tool-result-content {
@ -436,6 +440,16 @@ function renderToolResult(): string {
line-height: 1.5;
}
/* 记忆搜索匹配片段单行展示过长不折行直接省略号截断hover title 看全文) */
.search-match-snippet {
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
font-size: 12px;
line-height: 1.5;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 提取片段 */
.segment-separator {
text-align: center;

View File

@ -1029,11 +1029,14 @@ function renderSearchProjectMemory(result: any, args: any): string {
}
const snippets = Array.isArray(item.snippets) ? item.snippets : [];
if (snippets.length > 0) {
const snippetText = snippets
.map((snippet: any) => `L${snippet.line ?? '?'}: ${snippet.text || ''}`)
.join('\n');
// 每条匹配片段独立成行渲染pre 整体渲染时长行不换行会溢出容器),
// 配合 .search-match-snippet 的 nowrap + ellipsis过长片段直接省略号截断
html += '<div class="search-match-item">';
html += `<pre>${escapeHtml(snippetText)}</pre>`;
snippets.forEach((snippet: any) => {
const lineText = `L${snippet.line ?? '?'}: ${snippet.text || ''}`;
const escaped = escapeHtml(lineText);
html += `<div class="search-match-snippet" title="${escaped.replace(/"/g, '&quot;')}">${escaped}</div>`;
});
html += '</div>';
}
html += '</div>';

View File

@ -1,6 +1,12 @@
<template>
<transition name="qd-preview-slide">
<aside v-if="previewPath" class="qd-preview">
<aside v-if="previewPath" class="qd-preview" :style="{ width: previewWidth + 'px' }">
<!-- 左缘拖拽手柄拖动调整面板宽度localStorage 持久化 -->
<div
class="qd-preview__resize"
title="拖拽调整宽度"
@mousedown="startPreviewResize"
></div>
<section class="qd-preview__panel">
<header class="qd-preview__header">
<svg viewBox="0 0 16 16" fill="none">
@ -122,6 +128,51 @@ const PREVIEWABLE_EXTS = new Set([
const quickDock = useQuickDockStore();
const { previewPath } = storeToRefs(quickDock);
/** 预览面板宽度(含右侧 12px paddinglocalStorage 持久化 */
const PREVIEW_WIDTH_STORAGE_KEY = 'agents_qd_preview_width';
const PREVIEW_WIDTH_MIN = 320;
const PREVIEW_WIDTH_MAX = 860;
const PREVIEW_WIDTH_DEFAULT = 452;
const loadPreviewWidth = (): number => {
if (typeof window === 'undefined' || !window.localStorage) return PREVIEW_WIDTH_DEFAULT;
try {
const raw = Number(window.localStorage.getItem(PREVIEW_WIDTH_STORAGE_KEY));
if (!Number.isFinite(raw) || raw <= 0) return PREVIEW_WIDTH_DEFAULT;
return Math.max(PREVIEW_WIDTH_MIN, Math.min(PREVIEW_WIDTH_MAX, raw));
} catch {
return PREVIEW_WIDTH_DEFAULT;
}
};
const previewWidth = ref(loadPreviewWidth());
function startPreviewResize(event: MouseEvent) {
event.preventDefault();
const startX = event.clientX;
const startWidth = previewWidth.value;
const onMove = (e: MouseEvent) => {
//
const next = startWidth + (startX - e.clientX);
previewWidth.value = Math.max(PREVIEW_WIDTH_MIN, Math.min(PREVIEW_WIDTH_MAX, next));
};
const onUp = () => {
document.removeEventListener('mousemove', onMove);
document.removeEventListener('mouseup', onUp);
document.body.style.cursor = '';
document.body.style.userSelect = '';
try {
window.localStorage.setItem(PREVIEW_WIDTH_STORAGE_KEY, String(previewWidth.value));
} catch {
/* 持久化失败不影响本次调整 */
}
};
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', onUp);
document.body.style.cursor = 'col-resize';
document.body.style.userSelect = 'none';
}
const rawText = ref('');
const loading = ref(false);
const error = ref('');

View File

@ -733,13 +733,42 @@
.qd-preview {
flex: none;
width: 452px; /* 440 + 右 12 padding */
width: 452px; /* 440 + 右 12 padding;内联 width拖拽调宽优先于此处默认值 */
max-width: calc(100vw - 200px);
padding: 20px 12px 20px 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
position: relative; /* 容纳左缘拖拽手柄 */
}
/* 左缘拖拽手柄10px 热区骑跨面板左缘,可视 4px 高亮条仅在 hover/拖拽时显现 */
.qd-preview__resize {
position: absolute;
top: 0;
bottom: 0;
left: -5px;
width: 10px;
cursor: col-resize;
z-index: 5;
}
.qd-preview__resize::after {
content: '';
position: absolute;
top: 20px;
bottom: 20px;
left: 3px;
width: 4px;
border-radius: 999px;
background: transparent;
transition: background 0.2s;
}
.qd-preview__resize:hover::after,
.qd-preview__resize:active::after {
background: color-mix(in srgb, var(--accent) 24%, transparent);
}
.qd-preview__panel {

View File

@ -553,6 +553,32 @@ body[data-theme='dark'] .git-change-file__open-icon {
cursor: row-resize;
}
/* 右侧面板左右拖拽手柄基础样式曾随 _left-panel.scss b593d638 中被误删
导致手柄零宽不可见git/终端面板无法拖宽此处按现代 token 恢复
视觉 4px 透明条::before 向两侧扩 3px 热区便于瞄准hover/拖拽时高亮 */
.resize-handle--right-panels {
width: 4px;
flex-shrink: 0;
cursor: col-resize;
position: relative;
background: transparent;
transition: background 0.2s;
}
.resize-handle--right-panels::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: -3px;
right: -3px;
}
.resize-handle--right-panels:hover,
.resize-handle--right-panels:active {
background: color-mix(in srgb, var(--accent) 24%, transparent);
}
/* 拖拽期间禁用所有过渡,确保跟手 */
.right-panels--resizing {
transition: none !important;