style: 优化界面样式和用户体验

- 调整工具调用显示的间距和字体大小
   - 优化低调工具调用的视觉效果
   - 改进整体界面的可读性
This commit is contained in:
Roe-xin
2026-02-26 21:44:58 +08:00
parent c3e3012a94
commit a479e81682
6 changed files with 90 additions and 51 deletions

View File

@ -6,8 +6,13 @@ import { VCDFileServer } from "../services/vcdFileServer";
/** /**
* VCD 波形查看器自定义编辑器提供者 * VCD 波形查看器自定义编辑器提供者
*/ */
export class VCDViewerEditorProvider implements vscode.CustomReadonlyEditorProvider { export class VCDViewerEditorProvider
public static register(context: vscode.ExtensionContext, vcdFileServer: VCDFileServer): vscode.Disposable { implements vscode.CustomReadonlyEditorProvider
{
public static register(
context: vscode.ExtensionContext,
vcdFileServer: VCDFileServer,
): vscode.Disposable {
const provider = new VCDViewerEditorProvider(context, vcdFileServer); const provider = new VCDViewerEditorProvider(context, vcdFileServer);
const providerRegistration = vscode.window.registerCustomEditorProvider( const providerRegistration = vscode.window.registerCustomEditorProvider(
"ic-coder.vcdViewer", "ic-coder.vcdViewer",
@ -16,20 +21,20 @@ export class VCDViewerEditorProvider implements vscode.CustomReadonlyEditorProvi
webviewOptions: { webviewOptions: {
retainContextWhenHidden: true, retainContextWhenHidden: true,
}, },
} },
); );
return providerRegistration; return providerRegistration;
} }
constructor( constructor(
private readonly context: vscode.ExtensionContext, private readonly context: vscode.ExtensionContext,
private readonly vcdFileServer: VCDFileServer private readonly vcdFileServer: VCDFileServer,
) {} ) {}
async openCustomDocument( async openCustomDocument(
uri: vscode.Uri, uri: vscode.Uri,
openContext: vscode.CustomDocumentOpenContext, openContext: vscode.CustomDocumentOpenContext,
token: vscode.CancellationToken token: vscode.CancellationToken,
): Promise<vscode.CustomDocument> { ): Promise<vscode.CustomDocument> {
return { return {
uri, uri,
@ -40,7 +45,7 @@ export class VCDViewerEditorProvider implements vscode.CustomReadonlyEditorProvi
async resolveCustomEditor( async resolveCustomEditor(
document: vscode.CustomDocument, document: vscode.CustomDocument,
webviewPanel: vscode.WebviewPanel, webviewPanel: vscode.WebviewPanel,
token: vscode.CancellationToken token: vscode.CancellationToken,
): Promise<void> { ): Promise<void> {
webviewPanel.webview.options = { webviewPanel.webview.options = {
enableScripts: true, enableScripts: true,
@ -52,7 +57,7 @@ export class VCDViewerEditorProvider implements vscode.CustomReadonlyEditorProvi
webviewPanel, webviewPanel,
this.context.extensionUri, this.context.extensionUri,
document.uri.fsPath, document.uri.fsPath,
this.vcdFileServer this.vcdFileServer,
); );
} }
} }
@ -68,7 +73,11 @@ export class VCDViewerPanel {
private _currentVcdPath: string | undefined; private _currentVcdPath: string | undefined;
private _vcdFileServer: VCDFileServer | undefined; private _vcdFileServer: VCDFileServer | undefined;
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri, vcdFileServer?: VCDFileServer) { private constructor(
panel: vscode.WebviewPanel,
extensionUri: vscode.Uri,
vcdFileServer?: VCDFileServer,
) {
this._panel = panel; this._panel = panel;
this._extensionUri = extensionUri; this._extensionUri = extensionUri;
this._vcdFileServer = vcdFileServer; this._vcdFileServer = vcdFileServer;
@ -91,7 +100,10 @@ export class VCDViewerPanel {
break; break;
case "loaded": case "loaded":
// Surfer iframe 加载完成,发送 VCD 文件 // Surfer iframe 加载完成,发送 VCD 文件
console.log("[VCDViewerPanel] Surfer 已加载,当前 VCD 路径:", this._currentVcdPath); console.log(
"[VCDViewerPanel] Surfer 已加载,当前 VCD 路径:",
this._currentVcdPath,
);
if (this._currentVcdPath) { if (this._currentVcdPath) {
this.sendVcdToSurfer(this._currentVcdPath); this.sendVcdToSurfer(this._currentVcdPath);
} }
@ -99,14 +111,18 @@ export class VCDViewerPanel {
} }
}, },
null, null,
this._disposables this._disposables,
); );
} }
/** /**
* 创建或显示 VCD 查看器面板 * 创建或显示 VCD 查看器面板
*/ */
public static createOrShow(extensionUri: vscode.Uri, vcdFilePath?: string, vcdFileServer?: VCDFileServer) { public static createOrShow(
extensionUri: vscode.Uri,
vcdFilePath?: string,
vcdFileServer?: VCDFileServer,
) {
// 在当前活动编辑器旁边打开新列 // 在当前活动编辑器旁边打开新列
const column = vscode.ViewColumn.Beside; const column = vscode.ViewColumn.Beside;
@ -128,10 +144,14 @@ export class VCDViewerPanel {
enableScripts: true, enableScripts: true,
retainContextWhenHidden: true, retainContextWhenHidden: true,
localResourceRoots: [extensionUri], localResourceRoots: [extensionUri],
} },
); );
VCDViewerPanel.currentPanel = new VCDViewerPanel(panel, extensionUri, vcdFileServer); VCDViewerPanel.currentPanel = new VCDViewerPanel(
panel,
extensionUri,
vcdFileServer,
);
// 如果提供了 VCD 文件路径,加载它 // 如果提供了 VCD 文件路径,加载它
if (vcdFilePath) { if (vcdFilePath) {
@ -146,7 +166,7 @@ export class VCDViewerPanel {
panel: vscode.WebviewPanel, panel: vscode.WebviewPanel,
extensionUri: vscode.Uri, extensionUri: vscode.Uri,
vcdFilePath: string, vcdFilePath: string,
vcdFileServer?: VCDFileServer vcdFileServer?: VCDFileServer,
) { ) {
const viewer = new VCDViewerPanel(panel, extensionUri, vcdFileServer); const viewer = new VCDViewerPanel(panel, extensionUri, vcdFileServer);
viewer.loadVCDFile(vcdFilePath); viewer.loadVCDFile(vcdFilePath);
@ -172,14 +192,14 @@ export class VCDViewerPanel {
// 更新面板标题 // 更新面板标题
const fileName = path.basename(vcdFilePath); const fileName = path.basename(vcdFilePath);
this._panel.title = `Surfer 波形查看器 - ${fileName}`; this._panel.title = `波形查看器 - ${fileName}`;
// 设置 HTML 内容 // 设置 HTML 内容
this._panel.webview.html = this._getWebviewContent(); this._panel.webview.html = this._getWebviewContent();
console.log("[VCDViewerPanel] Webview HTML 已设置"); console.log("[VCDViewerPanel] Webview HTML 已设置");
} catch (error) { } catch (error) {
vscode.window.showErrorMessage( vscode.window.showErrorMessage(
`加载 VCD 文件失败: ${error instanceof Error ? error.message : "未知错误"}` `加载 VCD 文件失败: ${error instanceof Error ? error.message : "未知错误"}`,
); );
} }
} }
@ -190,8 +210,8 @@ export class VCDViewerPanel {
private parseVcdRootScope(vcdFilePath: string): string[] { private parseVcdRootScope(vcdFilePath: string): string[] {
try { try {
// 读取 VCD 文件 // 读取 VCD 文件
const buffer = fs.readFileSync(vcdFilePath, { encoding: 'utf8' }); const buffer = fs.readFileSync(vcdFilePath, { encoding: "utf8" });
const lines = buffer.split('\n'); const lines = buffer.split("\n");
const scopeNames: string[] = []; const scopeNames: string[] = [];
let scopeDepth = 0; let scopeDepth = 0;
@ -201,7 +221,7 @@ export class VCDViewerPanel {
const trimmed = line.trim(); const trimmed = line.trim();
// 遇到 $enddefinitions 就停止解析 // 遇到 $enddefinitions 就停止解析
if (trimmed.startsWith('$enddefinitions')) { if (trimmed.startsWith("$enddefinitions")) {
break; break;
} }
@ -212,22 +232,22 @@ export class VCDViewerPanel {
const scopeName = scopeMatch[2]; const scopeName = scopeMatch[2];
// 记录顶层 module (depth = 0) // 记录顶层 module (depth = 0)
if (scopeDepth === 0 && scopeType === 'module') { if (scopeDepth === 0 && scopeType === "module") {
scopeStack.push(scopeName); scopeStack.push(scopeName);
console.log("[VCDViewerPanel] 找到顶层作用域:", scopeName); console.log("[VCDViewerPanel] 找到顶层作用域:", scopeName);
} }
// 记录顶层下的直接子模块 (depth = 1) // 记录顶层下的直接子模块 (depth = 1)
else if (scopeDepth === 1 && scopeType === 'module') { else if (scopeDepth === 1 && scopeType === "module") {
const fullPath = [...scopeStack, scopeName]; const fullPath = [...scopeStack, scopeName];
scopeNames.push(fullPath.join('.')); scopeNames.push(fullPath.join("."));
console.log("[VCDViewerPanel] 找到子模块:", fullPath.join('.')); console.log("[VCDViewerPanel] 找到子模块:", fullPath.join("."));
} }
scopeDepth++; scopeDepth++;
} }
// 遇到 $upscope 减少深度 // 遇到 $upscope 减少深度
if (trimmed.startsWith('$upscope')) { if (trimmed.startsWith("$upscope")) {
scopeDepth--; scopeDepth--;
if (scopeDepth === 0) { if (scopeDepth === 0) {
scopeStack.pop(); scopeStack.pop();
@ -277,7 +297,7 @@ export class VCDViewerPanel {
} catch (error) { } catch (error) {
console.error("[VCDViewerPanel] 发送 VCD 数据失败:", error); console.error("[VCDViewerPanel] 发送 VCD 数据失败:", error);
vscode.window.showErrorMessage( vscode.window.showErrorMessage(
`发送 VCD 数据失败: ${error instanceof Error ? error.message : "未知错误"}` `发送 VCD 数据失败: ${error instanceof Error ? error.message : "未知错误"}`,
); );
} }
} }
@ -352,13 +372,23 @@ export class VCDViewerPanel {
private _getWebviewContent(): string { private _getWebviewContent(): string {
// 获取 surfer 资源 URI // 获取 surfer 资源 URI
const surferJsUri = this._panel.webview.asWebviewUri( const surferJsUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "surfer", "surfer.js") vscode.Uri.joinPath(this._extensionUri, "media", "surfer", "surfer.js"),
); );
const surferWasmUri = this._panel.webview.asWebviewUri( const surferWasmUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "surfer", "surfer_bg.wasm") vscode.Uri.joinPath(
this._extensionUri,
"media",
"surfer",
"surfer_bg.wasm",
),
); );
const integrationJsUri = this._panel.webview.asWebviewUri( const integrationJsUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "surfer", "integration.js") vscode.Uri.joinPath(
this._extensionUri,
"media",
"surfer",
"integration.js",
),
); );
return `<!DOCTYPE html> return `<!DOCTYPE html>
@ -367,7 +397,7 @@ export class VCDViewerPanel {
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline' 'unsafe-eval' ${this._panel.webview.cspSource}; worker-src blob:; connect-src ${this._panel.webview.cspSource} blob: http://127.0.0.1:*;"> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline' 'unsafe-eval' ${this._panel.webview.cspSource}; worker-src blob:; connect-src ${this._panel.webview.cspSource} blob: http://127.0.0.1:*;">
<title>Surfer 波形查看器</title> <title>波形查看器</title>
<script> <script>
// 获取 VS Code API只能调用一次 // 获取 VS Code API只能调用一次

View File

@ -5,7 +5,7 @@ import * as vscode from "vscode";
/** /**
* VCD 文件 HTTP 服务器 * VCD 文件 HTTP 服务器
* 用于为 Surfer 波形查看器提供 VCD 文件访问 * 用于为 波形查看器提供 VCD 文件访问
*/ */
export class VCDFileServer { export class VCDFileServer {
private server: http.Server | null = null; private server: http.Server | null = null;
@ -98,7 +98,10 @@ export class VCDFileServer {
/** /**
* 处理 HTTP 请求 * 处理 HTTP 请求
*/ */
private handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void { private handleRequest(
req: http.IncomingMessage,
res: http.ServerResponse,
): void {
const url = req.url || ""; const url = req.url || "";
console.log(`[VCDFileServer] 收到请求: ${url}`); console.log(`[VCDFileServer] 收到请求: ${url}`);
@ -214,7 +217,12 @@ export class VCDFileServer {
} }
const fileName = match[1]; const fileName = match[1];
const filePath = path.join(this.extensionUri.fsPath, "media", "surfer", fileName); const filePath = path.join(
this.extensionUri.fsPath,
"media",
"surfer",
fileName,
);
if (!fs.existsSync(filePath)) { if (!fs.existsSync(filePath)) {
console.error(`[VCDFileServer] 静态文件不存在: ${filePath}`); console.error(`[VCDFileServer] 静态文件不存在: ${filePath}`);
@ -257,8 +265,8 @@ export class VCDFileServer {
*/ */
private parseVcdRootScope(vcdFilePath: string): string[] { private parseVcdRootScope(vcdFilePath: string): string[] {
try { try {
const buffer = fs.readFileSync(vcdFilePath, { encoding: 'utf8' }); const buffer = fs.readFileSync(vcdFilePath, { encoding: "utf8" });
const lines = buffer.split('\n'); const lines = buffer.split("\n");
const scopeNames: string[] = []; const scopeNames: string[] = [];
let scopeDepth = 0; let scopeDepth = 0;
@ -267,7 +275,7 @@ export class VCDFileServer {
for (const line of lines) { for (const line of lines) {
const trimmed = line.trim(); const trimmed = line.trim();
if (trimmed.startsWith('$enddefinitions')) { if (trimmed.startsWith("$enddefinitions")) {
break; break;
} }
@ -276,17 +284,17 @@ export class VCDFileServer {
const scopeType = scopeMatch[1]; const scopeType = scopeMatch[1];
const scopeName = scopeMatch[2]; const scopeName = scopeMatch[2];
if (scopeDepth === 0 && scopeType === 'module') { if (scopeDepth === 0 && scopeType === "module") {
scopeStack.push(scopeName); scopeStack.push(scopeName);
} else if (scopeDepth === 1 && scopeType === 'module') { } else if (scopeDepth === 1 && scopeType === "module") {
const fullPath = [...scopeStack, scopeName]; const fullPath = [...scopeStack, scopeName];
scopeNames.push(fullPath.join('.')); scopeNames.push(fullPath.join("."));
} }
scopeDepth++; scopeDepth++;
} }
if (trimmed.startsWith('$upscope')) { if (trimmed.startsWith("$upscope")) {
scopeDepth--; scopeDepth--;
if (scopeDepth === 0) { if (scopeDepth === 0) {
scopeStack.pop(); scopeStack.pop();
@ -323,7 +331,7 @@ export class VCDFileServer {
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Surfer 波形查看器 - ${fileName}</title> <title>波形查看器 - ${fileName}</title>
<script> <script>
window.surferReady = false; window.surferReady = false;
window.pendingVcdData = null; window.pendingVcdData = null;

View File

@ -38,6 +38,7 @@ export function getAgentCardStyles(): string {
.agent-name { .agent-name {
font-weight: 500; font-weight: 500;
flex: 1; flex: 1;
font-size:14px
} }
.agent-status { .agent-status {
font-size: 11px; font-size: 11px;
@ -99,14 +100,14 @@ export function getAgentCardStyles(): string {
/* 低调显示的工具调用样式 */ /* 低调显示的工具调用样式 */
.agent-step.low-profile { .agent-step.low-profile {
opacity: 0.85; opacity: 0.85;
font-size: 12px; font-size: 13px;
padding: 4px 8px; padding: 4px 8px;
background: transparent; background: transparent;
margin-bottom: 2px; margin-bottom: 2px;
} }
.agent-step.low-profile .step-icon { .agent-step.low-profile .step-icon {
opacity: 0.8; opacity: 0.8;
font-size: 12px; font-size: 13px;
} }
.agent-step.low-profile .step-name { .agent-step.low-profile .step-name {
font-weight: 400; font-weight: 400;
@ -115,7 +116,7 @@ export function getAgentCardStyles(): string {
} }
.agent-step.low-profile .step-result { .agent-step.low-profile .step-result {
opacity: 0.85; opacity: 0.85;
font-size: 11px; font-size: 12px;
} }
`; `;
} }

View File

@ -41,18 +41,18 @@ export function getContextButtonContent(): string {
<path d="M340.864 149.312l384 384-384 384-45.248-45.248L634.368 533.312 295.616 194.56z" fill="currentColor"/> <path d="M340.864 149.312l384 384-384 384-45.248-45.248L634.368 533.312 295.616 194.56z" fill="currentColor"/>
</svg> </svg>
</div> </div>
<div class="context-menu-item" onclick="handleAddImage()"> <!-- <div class="context-menu-item" onclick="handleAddImage()">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32z m-40 632H136V232h752v560z m-120-240c0 55.2-44.8 100-100 100s-100-44.8-100-100 44.8-100 100-100 100 44.8 100 100z m-476 0l164 164h476L696 480 536 640l-84-84-160 160z" fill="currentColor"/> <path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32z m-40 632H136V232h752v560z m-120-240c0 55.2-44.8 100-100 100s-100-44.8-100-100 44.8-100 100-100 100 44.8 100 100z m-476 0l164 164h476L696 480 536 640l-84-84-160 160z" fill="currentColor"/>
</svg> </svg>
<span>图片</span> <span>图片</span>
</div> </div> -->
<div class="context-menu-item" onclick="handleAddDocument()"> <!-- <div class="context-menu-item" onclick="handleAddDocument()">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M832 64H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32z m-40 824H232V136h560v752z m-120-568H352c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h320c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z m0 144H352c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h320c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z m0 144H352c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h320c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z" fill="currentColor"/> <path d="M832 64H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32z m-40 824H232V136h560v752z m-120-568H352c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h320c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z m0 144H352c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h320c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z m0 144H352c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h320c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z" fill="currentColor"/>
</svg> </svg>
<span>文档库</span> <span>文档库</span>
</div> </div> -->
</div> </div>
<!-- 文件/文件夹列表视图 --> <!-- 文件/文件夹列表视图 -->

View File

@ -380,7 +380,7 @@ export function getMessageAreaStyles(): string {
} }
/* 低调显示的工具调用 - 移除边距和背景 */ /* 低调显示的工具调用 - 移除边距和背景 */
.segment-tool.low-profile { .segment-tool.low-profile {
margin: 2px 0px; margin: 5px 0px;
padding: 0; padding: 0;
background: none; background: none;
} }
@ -545,7 +545,7 @@ export function getMessageAreaStyles(): string {
} }
.tool-segment-description { .tool-segment-description {
margin: 6px 0 0 0px; margin: 6px 0 0 0px;
font-size: 12px; font-size: 0.9rem;
color: #ccc; color: #ccc;
line-height: 1.4; line-height: 1.4;
} }
@ -564,7 +564,7 @@ export function getMessageAreaStyles(): string {
} }
.segment-tool.low-profile .tool-segment-result { .segment-tool.low-profile .tool-segment-result {
opacity: 0.7; opacity: 0.7;
font-size: 10px; font-size: 12px;
} }
.segment-question { .segment-question {
background: var(--vscode-textBlockQuote-background); background: var(--vscode-textBlockQuote-background);

View File

@ -304,6 +304,7 @@ export function getWebviewContent(
} }
.segment-text { .segment-text {
line-height: 1.6; line-height: 1.6;
font-size:0.9rem
} }
.segment-tool { .segment-tool {
background: var(--vscode-textBlockQuote-background); background: var(--vscode-textBlockQuote-background);
@ -325,7 +326,6 @@ export function getWebviewContent(
color: var(--vscode-foreground); color: var(--vscode-foreground);
} }
.tool-segment-result { .tool-segment-result {
margin-top: 6px;
font-size: 12px; font-size: 12px;
color: var(--vscode-descriptionForeground); color: var(--vscode-descriptionForeground);
padding-left: 22px; padding-left: 22px;