Merge branch 'feat/ningDeShiDai' of https://git.pengyejiatu.com/pengyejiatu/Ic-coder-plugin into feat/ningDeShiDai
251
media/USER_MANUAL.md
Normal file
@ -0,0 +1,251 @@
|
||||
# IC Coder 插件端用户手册
|
||||
|
||||
欢迎**宁德时代新能源科技股份有限公司**的各位专家使用 IC Coder 企业版!
|
||||
|
||||
本手册旨在为贵公司提供插件的安装、配置及使用指导,帮助您快速上手并充分发挥工具的功能。
|
||||
|
||||
在使用过程中,如遇任何功能异常、性能问题或操作疑问,欢迎随时联系我们,我们将在第一时间为您提供支持。
|
||||
|
||||
若贵司有特定的业务场景或个性化功能需求,也可直接与我们沟通,我们会为贵司进行定制化开发。
|
||||
|
||||
| 功能 | 说明 |
|
||||
| ----------------------- | ---------------------------------------------------- |
|
||||
| 自研微调模型 | IC Coder 自研顶尖 Max 微调模型,专为 FPGA 开发 |
|
||||
| 高质量 Verilog 代码生成 | 根据自然语言描述生成符合规范的 Verilog 代码 |
|
||||
| 自动语法检查 | 自动检测代码语法错误并自动修复 |
|
||||
| 自动仿真 | 内置编译器,自动编译和仿真 |
|
||||
| 波形检查工具 | 内置 VCD 波形查看器,自动波形解析 |
|
||||
| 自主检查迭代 | AI 自动检查代码问题并迭代优化 |
|
||||
| Diff 功能 | 快速比较代码差异,追踪 AI 修改,可一键确认和撤销修改 |
|
||||
| Code Action 快捷操作 | Ctrl+L 快捷键或右键菜单快速添加代码到对话 |
|
||||
| 支持上下文连续对话 | 多轮对话,AI 记住之前的交互内容 |
|
||||
| 会话历史管理 | 自动保存对话记录,随时恢复历史会话 |
|
||||
|
||||
## IC Coder 快速入门指南
|
||||
|
||||
### 系统要求
|
||||
|
||||
- **Visual Studio Code**: 版本 >= 1.60.0
|
||||
|
||||
各位专家也可以通过这个链接下载VSCode [下载链接](https://code.visualstudio.com/)
|
||||
|
||||
---
|
||||
|
||||
### 安装步骤
|
||||
|
||||
#### 步骤 1:通过 VSIX 文件安装(推荐)
|
||||
|
||||
1. **获取安装包**
|
||||
- 确保您已经获得 `iccoder-Trial-1.0.vsix` 文件
|
||||
|
||||
2. **打开 VS Code**
|
||||
- 启动 Visual Studio Code
|
||||
|
||||
3. **安装插件**
|
||||
|
||||
有以下三种安装方式:
|
||||
|
||||
**方式 A:通过命令面板**
|
||||
- 按 `Ctrl+Shift+P` (Windows/Linux) 或 `Cmd+Shift+P` (macOS) 打开命令面板
|
||||
- 输入 `Extensions: Install from VSIX...`
|
||||
- 选择 `iccoder-Trial-1.0.vsix` 文件
|
||||
- 等待安装完成
|
||||
|
||||

|
||||
|
||||
**方式 B:通过扩展视图**
|
||||
- 点击左侧活动栏的扩展图标(或按 `Ctrl+Shift+X`)
|
||||
- 点击扩展视图右上角的 `...` (更多操作)
|
||||
- 选择 `从 VSIX 安装...`
|
||||
- 选择 `iccoder-Trial-1.0.vsix` 文件
|
||||
|
||||

|
||||
|
||||
**方式 C:通过命令行**
|
||||
|
||||
```bash
|
||||
code --install-extension iccoder-Trial-1.0.vsix
|
||||
```
|
||||
|
||||
4. **重启 VS Code**
|
||||
- 安装完成后,建议重启 VS Code 以确保插件正常加载
|
||||
|
||||
#### 步骤 2:打开 IC Coder 界面
|
||||
|
||||
**登录后会自动打开**,手动打开也有以下几种方式:
|
||||
|
||||
**方式 1:通过侧边栏**
|
||||
|
||||
- 点击左侧活动栏的 IC Coder 图标
|
||||
- 侧边栏会显示 IC Coder 聊天界面
|
||||
|
||||

|
||||
|
||||
**方式 2:通过命令面板**
|
||||
|
||||
- 按 `Ctrl+Shift+P` (Windows/Linux) 或 `Cmd+Shift+P` (macOS)
|
||||
- 输入以下命令之一:
|
||||
- `IC Coder: 打开聊天` - 打开聊天界面
|
||||
- `打开 IC Coder 助手` - 打开助手面板
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
#### 步骤 3:开始使用
|
||||
|
||||
插件已预配置好后端服务,安装后即可直接使用,无需手动配置。
|
||||
|
||||

|
||||
|
||||
### 故障排除
|
||||
|
||||
#### 问题 :插件无法安装
|
||||
|
||||
**症状**:安装 VSIX 文件时报错
|
||||
|
||||
#### 解决方案:
|
||||
|
||||
- 确认 VS Code 版本 >= 1.60.0
|
||||
|
||||
- 检查 VSIX 文件是否完整(未损坏)
|
||||
|
||||
- 尝试以管理员权限运行 VS Code
|
||||
|
||||
- 清除 VS Code 缓存后重试
|
||||
|
||||
### 完整使用流程示例
|
||||
|
||||
下面通过一个完整的案例,展示如何使用 IC Coder 从需求到代码生成的全过程。
|
||||
|
||||
#### 步骤 1:输入设计需求
|
||||
|
||||
在对话框中输入设计需求,例如:
|
||||
|
||||
```
|
||||
我需要设计一个 8 位加法器,要求有进位输入和进位输出
|
||||
```
|
||||
|
||||
点击**发送**按钮。
|
||||
|
||||

|
||||
|
||||
#### 步骤 2:AI 询问补充信息
|
||||
|
||||
AI 会根据需求,询问一些关键的设计细节。例如:
|
||||
|
||||
- 是否需要溢出检测?
|
||||
- 时钟频率要求是多少?
|
||||
- 是否需要流水线设计?
|
||||
|
||||
您只需要根据实际需求**选择相应的选项或者直接输入需求**即可,AI 会根据您的选择生成最合适的设计方案。
|
||||
|
||||
#### 步骤 3:确认 AI 生成的任务列表
|
||||
|
||||
AI 会根据您的需求和补充信息,生成一个详细的任务列表(Todo List)
|
||||
|
||||

|
||||
|
||||
仔细查看任务列表,确认无误后点击**确认**按钮,AI 将开始执行。
|
||||
|
||||
#### 步骤 4:观察 AI 执行过程
|
||||
|
||||
AI 开始工作后,您可以在对话框中实时看到所有执行步骤:
|
||||
|
||||

|
||||
|
||||
每个步骤完成后,任务列表中对应的项目会被标记为完成状态。
|
||||
|
||||
#### 步骤 5:仿真运行与结果查看
|
||||
|
||||
当 AI 完成代码生成后,会自动运行仿真验证:
|
||||
|
||||

|
||||
|
||||
#### 步骤 6:查看生成的文件
|
||||
|
||||
所有生成的文件会自动保存到您的工作目录中:
|
||||
|
||||
```
|
||||
project/
|
||||
├── src/
|
||||
│ └── tb_adder_8bit.v # RTL 设计文件
|
||||
├── sim/
|
||||
│ └── tb_adder_8bit # 测试平台文件
|
||||
└── tb_adder_8bit.vcd # 波形文件
|
||||
```
|
||||
|
||||
您可以在 VS Code 的文件资源管理器中直接打开这些文件进行查看或修改。
|
||||
|
||||
#### 步骤8:继续对话
|
||||
|
||||
如果您对给出的结果不太满意,您可以告诉IC Coder您想具体修改的地方或者文件
|
||||
|
||||
#### 使用流程总结
|
||||
|
||||
整个使用流程可以概括为:
|
||||
|
||||
- **输入需求** → 在对话框中描述您的设计需求
|
||||
- **回答问题** → 根据 AI 的询问选择合适的选项
|
||||
- **确认任务** → 查看并确认 AI 生成的任务列表
|
||||
- **观察执行** → 实时查看 AI 的所有执行步骤
|
||||
- **查看结果** → 仿真成功后查看生成的文件
|
||||
|
||||
#### 使用提示
|
||||
|
||||
**如何描述需求更准确?**
|
||||
|
||||
- **明确功能**:清楚说明模块要实现什么功能
|
||||
- **指定参数**:说明位宽、时钟频率等关键参数
|
||||
- **特殊要求**:如果有特殊的时序要求或接口规范,请明确说明
|
||||
|
||||
**示例:**
|
||||
|
||||
```
|
||||
好的描述:设计一个 16 位的 FIFO,深度为 256,支持异步读写
|
||||
不够清晰:帮我写一个 FIFO
|
||||
```
|
||||
|
||||
#### 常见问题
|
||||
|
||||
**Q: 仿真失败了怎么办?**
|
||||
A: AI 会根据错误自动修复代码并重新仿真。
|
||||
|
||||
**Q: 可以修改生成的代码吗?**
|
||||
A: 可以,可以直接编辑文件,然后告诉 AI 重新运行仿真。
|
||||
|
||||
**Q: 可以导入已有的代码吗?**
|
||||
A: 可以,在工作区中打开对应的代码文件夹,然后直接在对话中告诉 AI 您要修改或优化哪个文件,AI 会读取并进行修改。
|
||||
|
||||
**Q: 如何查看 AI 的思考过程?**
|
||||
A: 在执行过程中,AI 会实时显示每一步的操作和决策依据。
|
||||
|
||||
**Q: 如何保存对话历史?**
|
||||
A: 对话历史会自动保存在本地,可以点击历史对话查看历史会话记录。
|
||||
|
||||
---
|
||||
|
||||
### 卸载插件
|
||||
|
||||
如需卸载插件:
|
||||
|
||||
1. 打开扩展视图
|
||||
2. 找到 "IC Coder" 插件
|
||||
3. 点击卸载按钮
|
||||
4. 重启 VS Code
|
||||
|
||||
---
|
||||
|
||||
### 注意事项
|
||||
|
||||
1. **需提前打开一个文件夹作为工作区**,否则会准确的为您服务
|
||||
|
||||

|
||||
|
||||
2. **开箱即用**
|
||||
- 插件已预配置后端服务,无需手动设置
|
||||
- 安装后即可直接使用所有功能
|
||||
|
||||
---
|
||||
|
||||
**祝您使用愉快!如有问题欢迎反馈。**
|
||||
BIN
media/manual/仿真运行结果.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
media/manual/侧边栏打开.png
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
media/manual/命令面板打开.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
media/manual/安装方式1.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
media/manual/安装方式2.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
media/manual/打开文件夹.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
media/manual/确认任务.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
media/manual/聊天界面.png
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
media/manual/观察执行过程.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
media/manual/输入需求.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
@ -2,6 +2,7 @@ import * as vscode from "vscode";
|
||||
import { ICViewProvider } from "./views/ICViewProvider";
|
||||
import { showICHelperPanel } from "./panels/ICHelperPanel";
|
||||
import { VCDViewerPanel, VCDViewerEditorProvider } from "./panels/VCDViewerPanel";
|
||||
import { UserManualPanel } from "./panels/UserManualPanel";
|
||||
import { ChatHistoryManager } from "./utils/chatHistoryManager";
|
||||
import { ICCoderAuthenticationProvider } from "./services/icCoderAuthProvider";
|
||||
import { VCDFileServer } from "./services/vcdFileServer";
|
||||
@ -181,6 +182,14 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
);
|
||||
|
||||
// 注册命令:打开用户手册
|
||||
const openUserManualCommand = vscode.commands.registerCommand(
|
||||
"ic-coder.openUserManual",
|
||||
() => {
|
||||
UserManualPanel.render(context.extensionUri);
|
||||
}
|
||||
);
|
||||
|
||||
// 注册命令:用户登录
|
||||
const loginCommand = vscode.commands.registerCommand(
|
||||
"ic-coder.login",
|
||||
@ -425,6 +434,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
openChatCommand,
|
||||
openVCDViewerCommand,
|
||||
openVCDViewerInBrowserCommand,
|
||||
openUserManualCommand,
|
||||
loginCommand,
|
||||
logoutCommand,
|
||||
changeInvitationCodeCommand,
|
||||
|
||||
@ -492,7 +492,7 @@ export async function showICHelperPanel(
|
||||
break;
|
||||
case "openUserManual":
|
||||
// 打开用户手册
|
||||
vscode.env.openExternal(vscode.Uri.parse("https://www.iccoder.com"));
|
||||
vscode.commands.executeCommand("ic-coder.openUserManual");
|
||||
break;
|
||||
case "openUserFeedback":
|
||||
// 打开用户反馈二维码弹窗
|
||||
|
||||
181
src/panels/UserManualPanel.ts
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* 用户手册只读预览面板
|
||||
*/
|
||||
|
||||
import * as vscode from "vscode";
|
||||
|
||||
export class UserManualPanel {
|
||||
public static currentPanel: UserManualPanel | undefined;
|
||||
private readonly _panel: vscode.WebviewPanel;
|
||||
private _disposables: vscode.Disposable[] = [];
|
||||
|
||||
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
|
||||
this._panel = panel;
|
||||
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
|
||||
this._update(extensionUri);
|
||||
}
|
||||
|
||||
public static render(extensionUri: vscode.Uri) {
|
||||
if (UserManualPanel.currentPanel) {
|
||||
UserManualPanel.currentPanel._panel.reveal(vscode.ViewColumn.One);
|
||||
} else {
|
||||
const panel = vscode.window.createWebviewPanel(
|
||||
"userManual",
|
||||
"IC Coder 用户手册",
|
||||
vscode.ViewColumn.One,
|
||||
{
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, "media")],
|
||||
},
|
||||
);
|
||||
UserManualPanel.currentPanel = new UserManualPanel(panel, extensionUri);
|
||||
}
|
||||
}
|
||||
|
||||
private async _update(extensionUri: vscode.Uri) {
|
||||
const manualPath = vscode.Uri.joinPath(
|
||||
extensionUri,
|
||||
"media",
|
||||
"USER_MANUAL.md",
|
||||
);
|
||||
const markdown = await vscode.workspace.fs.readFile(manualPath);
|
||||
const content = Buffer.from(markdown).toString("utf-8");
|
||||
this._panel.webview.html = await this._getHtmlContent(
|
||||
content,
|
||||
extensionUri,
|
||||
);
|
||||
}
|
||||
|
||||
private async _getHtmlContent(
|
||||
markdown: string,
|
||||
extensionUri: vscode.Uri,
|
||||
): Promise<string> {
|
||||
let inCodeBlock = false;
|
||||
let inTable = false;
|
||||
let tableRows: string[] = [];
|
||||
const lines: string[] = [];
|
||||
|
||||
// 先处理图片
|
||||
markdown = markdown.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, src) => {
|
||||
const imgUri = this._panel.webview.asWebviewUri(
|
||||
vscode.Uri.joinPath(extensionUri, "media", src),
|
||||
);
|
||||
return `<img src="${imgUri}" alt="${alt}">`;
|
||||
});
|
||||
|
||||
markdown.split("\n").forEach((line) => {
|
||||
// 代码块
|
||||
if (line.startsWith("```")) {
|
||||
if (inCodeBlock) {
|
||||
lines.push("</code></pre>");
|
||||
inCodeBlock = false;
|
||||
} else {
|
||||
lines.push("<pre><code>");
|
||||
inCodeBlock = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (inCodeBlock) {
|
||||
lines.push(line);
|
||||
return;
|
||||
}
|
||||
|
||||
// 表格
|
||||
if (line.startsWith("|")) {
|
||||
if (!inTable) inTable = true;
|
||||
tableRows.push(line);
|
||||
return;
|
||||
} else if (inTable) {
|
||||
// 表格结束
|
||||
const headers = tableRows[0]
|
||||
.split("|")
|
||||
.filter((c) => c.trim())
|
||||
.map((h) => `<th>${h.trim()}</th>`)
|
||||
.join("");
|
||||
const body = tableRows
|
||||
.slice(2)
|
||||
.map(
|
||||
(r) =>
|
||||
"<tr>" +
|
||||
r
|
||||
.split("|")
|
||||
.filter((c) => c.trim())
|
||||
.map((c) => `<td>${c.trim()}</td>`)
|
||||
.join("") +
|
||||
"</tr>",
|
||||
)
|
||||
.join("");
|
||||
lines.push(
|
||||
`<table><thead><tr>${headers}</tr></thead><tbody>${body}</tbody></table>`,
|
||||
);
|
||||
tableRows = [];
|
||||
inTable = false;
|
||||
}
|
||||
|
||||
// 其他行
|
||||
if (line === "---") lines.push("<hr>");
|
||||
else if (line.startsWith("#### "))
|
||||
lines.push(`<h4>${line.slice(5)}</h4>`);
|
||||
else if (line.startsWith("### ")) lines.push(`<h3>${line.slice(4)}</h3>`);
|
||||
else if (line.startsWith("## ")) lines.push(`<h2>${line.slice(3)}</h2>`);
|
||||
else if (line.startsWith("# ")) lines.push(`<h1>${line.slice(2)}</h1>`);
|
||||
else if (line.startsWith("- "))
|
||||
lines.push(
|
||||
`<li>${line.slice(2).replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>")}</li>`,
|
||||
);
|
||||
else if (line.trim() === "") lines.push("<p></p>");
|
||||
else
|
||||
lines.push(
|
||||
`<p>${line.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2">$1</a>')}</p>`,
|
||||
);
|
||||
});
|
||||
|
||||
const html = lines
|
||||
.join("\n")
|
||||
.replace(/((?:<li>.*<\/li>\n?)+)/g, "<ul>$1</ul>");
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
padding: 40px;
|
||||
line-height: 1.8;
|
||||
font-size: 16px;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h1 { font-size: 2em; border-bottom: 3px solid #ddd; padding-bottom: 15px; margin: 30px 0 20px; }
|
||||
h2 { font-size: 1.6em; margin-top: 40px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
|
||||
h3 { font-size: 1.3em; margin-top: 30px; }
|
||||
h4 { font-size: 1.1em; margin-top: 20px; font-weight: 600; }
|
||||
p { margin: 15px 0; }
|
||||
img { display: block; margin: 30px auto; max-width: 100%; border: 1px solid #ddd; border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
|
||||
table { border-collapse: collapse; width: 100%; margin: 25px 0; font-size: 15px; }
|
||||
th, td { border: 1px solid #ddd; padding: 12px 16px; text-align: left; }
|
||||
th { background: #636363; font-weight: 600; }
|
||||
tr:hover { background: #636363; }
|
||||
ul { margin: 15px 0; padding-left: 30px; }
|
||||
li { margin: 8px 0; margin-left: 40px;}
|
||||
pre { background: #2f2f2f; padding: 20px; border-radius: 6px; overflow-x: auto; margin: 20px 0; border: 1px solid #e0e0e0; }
|
||||
code { font-family: 'Consolas', 'Monaco', monospace; font-size: 14px; line-height: 1.6; }
|
||||
hr { border: none; border-top: 2px solid #e0e0e0; margin: 30px 0; }
|
||||
a { color: #0066cc; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
strong { font-weight: 600; color: #e5e5e5; }
|
||||
</style>
|
||||
</head>
|
||||
<body>${html}</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
UserManualPanel.currentPanel = undefined;
|
||||
this._panel.dispose();
|
||||
while (this._disposables.length) {
|
||||
this._disposables.pop()?.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -286,10 +286,18 @@ async function handleUserMessageWithBackend(
|
||||
},
|
||||
|
||||
onSegmentUpdate: (segments) => {
|
||||
// 过滤掉包含 [调用工具:xxx] 的段落
|
||||
const filteredSegments = segments.filter(seg => {
|
||||
if (seg.type === 'text' && typeof seg.content === 'string') {
|
||||
return !/\[调用工具:.+?\]/.test(seg.content);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// 实时发送段落更新,按后端返回顺序展示
|
||||
panel.webview.postMessage({
|
||||
command: "updateSegments",
|
||||
segments: segments,
|
||||
segments: filteredSegments,
|
||||
});
|
||||
|
||||
// 【离线部署模式】检测代码生成完成消息,模拟仿真流程
|
||||
|
||||
@ -125,6 +125,10 @@ export function showICHelperPanel(context: vscode.ExtensionContext) {
|
||||
case "showWarning":
|
||||
vscode.window.showWarningMessage(message.message);
|
||||
break;
|
||||
// 新增:打开用户手册
|
||||
case "openUserManual":
|
||||
vscode.commands.executeCommand("ic-coder.openUserManual");
|
||||
break;
|
||||
// 新增:处理用户回答
|
||||
case "submitAnswer":
|
||||
handleUserAnswer(
|
||||
@ -224,6 +228,9 @@ export class ICViewProvider implements vscode.WebviewViewProvider {
|
||||
} else if (message.command === "openICCoder") {
|
||||
// 打开 IC Coder 官网
|
||||
vscode.env.openExternal(vscode.Uri.parse('https://www.iccoder.com'));
|
||||
} else if (message.command === "openUserManual") {
|
||||
// 打开用户手册
|
||||
vscode.commands.executeCommand("ic-coder.openUserManual");
|
||||
} else if (message.command === "openExternalUrl") {
|
||||
// 打开外部链接
|
||||
if (message.url) {
|
||||
|
||||
@ -34,14 +34,6 @@ export function getExampleShowcaseContent(): string {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="web-link">
|
||||
<a href="https://iccoder.com" target="_blank" class="web-link-button">
|
||||
<span class="link-icon">🌐</span>
|
||||
<span>IC Coder Web端</span>
|
||||
<span class="link-arrow">→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -165,41 +157,6 @@ export function getExampleShowcaseStyles(): string {
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.web-link {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--vscode-panel-border);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.web-link-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 20px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 50%, #a855f7 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.web-link-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.web-link-button:hover {
|
||||
transform: translateY(-1px);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.link-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
@ -208,10 +165,6 @@ export function getExampleShowcaseStyles(): string {
|
||||
font-size: 16px;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.web-link-button:hover .link-arrow {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@ -382,7 +382,7 @@ export function getMessageAreaStyles(): string {
|
||||
}
|
||||
/* 低调显示的工具调用 - 移除边距和背景 */
|
||||
.segment-tool.low-profile {
|
||||
margin: 5px 0px;
|
||||
margin: 25px 0px;
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
@ -549,7 +549,7 @@ export function getMessageAreaStyles(): string {
|
||||
max-height: 0;
|
||||
}
|
||||
.tool-segment-description {
|
||||
margin: 6px 0 0 0px;
|
||||
margin: 25px 0 0 0px;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
line-height: 1.4;
|
||||
@ -590,9 +590,9 @@ export function getMessageAreaStyles(): string {
|
||||
}
|
||||
.segment-question .question-option {
|
||||
padding: 8px 16px;
|
||||
background: #007ACC;
|
||||
background: #3d3f41;
|
||||
color: #ffffff;
|
||||
border: 1px solid #007ACC;
|
||||
border: 1px solid #474747;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
@ -1211,7 +1211,7 @@ export function getMessageAreaScript(): string {
|
||||
|
||||
const optionsHtml = q.options.map(opt => {
|
||||
const isSelected = selectedAnswers.includes(opt);
|
||||
return \`<label class="question-option\${isSelected ? ' selected' : ''}" style="display:flex;align-items:center;gap:6px;cursor:pointer;padding:4px 0;">
|
||||
return \`<label class="question-option\${isSelected ? ' selected' : ''}" style="display:flex;align-items:center;gap:6px;cursor:pointer;padding:5px 5px 5px 0;">
|
||||
<input type="\${inputType}" name="\${inputName}" value="\${opt}" \${isSelected ? 'checked' : ''} \${isAnswered ? 'disabled' : ''}>
|
||||
<span>\${opt}</span>
|
||||
</label>\`;
|
||||
|
||||
@ -9,66 +9,16 @@ export function getModelSelectorContent(
|
||||
autoIcon: string = "",
|
||||
liteIcon: string = "",
|
||||
syIcon: string = "",
|
||||
maxIcon: string = ""
|
||||
maxIcon: string = "",
|
||||
): string {
|
||||
return `
|
||||
<!-- 模型选择 -->
|
||||
<div class="tooltip">
|
||||
<div class="custom-select" id="modelSelect">
|
||||
<div class="select-trigger" onclick="toggleModelDropdown()">
|
||||
<span class="select-value" id="modelValue">Auto</span>
|
||||
<svg class="select-arrow" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M507.8 727.728a30.016 30.016 0 0 1-21.288-8.824L231.104 463.496a30.088 30.088 0 0 1 0-42.568 30.088 30.088 0 0 1 42.568 0l234.128 234.128 234.16-234.128a30.088 30.088 0 0 1 42.568 0 30.088 30.088 0 0 1 0 42.568L529.08 718.904a30 30 0 0 1-21.28 8.824z" fill="#8a8a8a"/>
|
||||
</svg>
|
||||
<div class="model-display">
|
||||
<img src="${maxIcon || ""}" class="model-icon" alt="Max" style="display: ${maxIcon ? "block" : "none"};">
|
||||
<span class="model-label">Max</span>
|
||||
</div>
|
||||
<div class="select-dropdown" id="modelDropdown">
|
||||
<div class="select-option selected" data-value="auto" onclick="selectModel('auto', 'Auto')">
|
||||
${
|
||||
autoIcon
|
||||
? `<img src="${autoIcon}" class="model-icon" alt="Auto">`
|
||||
: ""
|
||||
}
|
||||
<div class="option-content">
|
||||
<span class="option-label">Auto</span>
|
||||
<span class="option-desc">智能匹配最优模型</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="select-option" data-value="lite" onclick="selectModel('lite', 'Lite')">
|
||||
${
|
||||
liteIcon
|
||||
? `<img src="${liteIcon}" class="model-icon" alt="Lite">`
|
||||
: ""
|
||||
}
|
||||
<div class="option-content">
|
||||
<span class="option-label">Lite</span>
|
||||
<span class="option-desc">基础模型,快速相应,适合简单任务</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="select-option" data-value="syntaxic" onclick="selectModel('syntaxic', 'Syntaxic')">
|
||||
${
|
||||
syIcon
|
||||
? `<img src="${syIcon}" class="model-icon" alt="Syntaxic">`
|
||||
: ""
|
||||
}
|
||||
<div class="option-content">
|
||||
<span class="option-label">Syntaxic</span>
|
||||
<span class="option-desc">均衡成本和性能,节省credits同时保持可靠输出</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="select-option" data-value="max" onclick="selectModel('max', 'Max')">
|
||||
${
|
||||
maxIcon
|
||||
? `<img src="${maxIcon}" class="model-icon" alt="Max">`
|
||||
: ""
|
||||
}
|
||||
<div class="option-content">
|
||||
<span class="option-label">Max</span>
|
||||
<span class="option-desc">最强性能,质量优先,适合复杂任务</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="tooltiptext">选择模型</span>
|
||||
<span class="tooltiptext">IC Coder自研FPGA专属微调模型</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -78,72 +28,16 @@ export function getModelSelectorContent(
|
||||
*/
|
||||
export function getModelSelectorStyles(): string {
|
||||
return `
|
||||
/* 自定义下拉框样式 */
|
||||
.custom-select {
|
||||
position: relative;
|
||||
user-select: none;
|
||||
}
|
||||
.select-trigger {
|
||||
.model-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 8px;
|
||||
background: var(--vscode-input-background);
|
||||
color: var(--vscode-foreground);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
.select-trigger:hover {
|
||||
background: var(--vscode-list-hoverBackground);
|
||||
}
|
||||
.select-value {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.select-arrow {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.custom-select.active .select-arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.select-dropdown {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 2px);
|
||||
left: 0;
|
||||
min-width: 100%;
|
||||
background: var(--vscode-dropdown-background);
|
||||
border: 1px solid var(--vscode-dropdown-border);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
z-index: 1100;
|
||||
display: none;
|
||||
overflow: visible;
|
||||
}
|
||||
.custom-select.active .select-dropdown {
|
||||
display: block;
|
||||
}
|
||||
/* 模型选择器的选项样式 */
|
||||
#modelDropdown .select-option {
|
||||
position: relative;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
#modelDropdown .select-option:hover {
|
||||
background: rgba(128, 128, 128, 0.3);
|
||||
}
|
||||
#modelDropdown .select-option.selected {
|
||||
background: rgba(128, 128, 128, 0.5);
|
||||
color: var(--vscode-foreground);
|
||||
cursor: default;
|
||||
}
|
||||
.model-icon {
|
||||
width: 16px;
|
||||
@ -151,21 +45,7 @@ export function getModelSelectorStyles(): string {
|
||||
flex-shrink: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
.option-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
flex: 1;
|
||||
}
|
||||
.option-label {
|
||||
font-size: 13px;
|
||||
color: var(--vscode-foreground);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.option-desc {
|
||||
font-size: 11px;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
.model-label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
`;
|
||||
@ -176,58 +56,9 @@ export function getModelSelectorStyles(): string {
|
||||
*/
|
||||
export function getModelSelectorScript(): string {
|
||||
return `
|
||||
// 模型选择相关变量
|
||||
let currentModel = 'auto';
|
||||
|
||||
// 切换模型下拉框显示/隐藏
|
||||
function toggleModelDropdown() {
|
||||
const modelSelect = document.getElementById('modelSelect');
|
||||
const customSelect = document.getElementById('customSelect');
|
||||
if (modelSelect) {
|
||||
modelSelect.classList.toggle('active');
|
||||
// 关闭模式下拉框
|
||||
if (customSelect) {
|
||||
customSelect.classList.remove('active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 选择模型
|
||||
function selectModel(value, label) {
|
||||
currentModel = value;
|
||||
const modelValue = document.getElementById('modelValue');
|
||||
if (modelValue) {
|
||||
modelValue.textContent = label;
|
||||
}
|
||||
|
||||
// 更新选中状态
|
||||
const options = document.querySelectorAll('#modelDropdown .select-option');
|
||||
options.forEach(option => {
|
||||
if (option.getAttribute('data-value') === value) {
|
||||
option.classList.add('selected');
|
||||
} else {
|
||||
option.classList.remove('selected');
|
||||
}
|
||||
});
|
||||
|
||||
// 关闭下拉框
|
||||
const modelSelect = document.getElementById('modelSelect');
|
||||
if (modelSelect) {
|
||||
modelSelect.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
// 点击外部关闭模型下拉框
|
||||
document.addEventListener('click', (event) => {
|
||||
const modelSelect = document.getElementById('modelSelect');
|
||||
if (modelSelect && !modelSelect.contains(event.target)) {
|
||||
modelSelect.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// 获取当前选中的模型
|
||||
// 获取当前选中的模型(固定为 max)
|
||||
function getCurrentModel() {
|
||||
return currentModel;
|
||||
return 'max';
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 更多选项组件
|
||||
* 包含用户手册和用户反馈入口
|
||||
* 包含用户手册入口
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -28,40 +28,10 @@ export function getMoreOptionsComponentContent(): string {
|
||||
<div class="option-desc">查看使用文档和帮助</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="more-option-item" id="userFeedbackOption">
|
||||
<div class="option-icon">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z" fill="currentColor"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="option-text">
|
||||
<div class="option-label">用户反馈</div>
|
||||
<div class="option-desc">提交问题和建议</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户反馈二维码弹窗 -->
|
||||
<div class="feedback-qrcode-modal" id="feedbackQRCodeModal">
|
||||
<div class="feedback-qrcode-overlay" onclick="closeFeedbackQRCode()"></div>
|
||||
<div class="feedback-qrcode-content">
|
||||
<div class="feedback-qrcode-header">
|
||||
<span class="feedback-qrcode-title">用户反馈</span>
|
||||
<button class="feedback-qrcode-close" onclick="closeFeedbackQRCode()">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" fill="currentColor"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="feedback-qrcode-body">
|
||||
<img class="feedback-qrcode-image" id="feedbackQRCodeImage" alt="微信二维码" />
|
||||
<p class="feedback-qrcode-text">扫描二维码添加微信反馈</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -163,125 +133,6 @@ export function getMoreOptionsComponentStyles(): string {
|
||||
.option-desc {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 用户反馈二维码弹窗 */
|
||||
.feedback-qrcode-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 20000;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.feedback-qrcode-modal.active {
|
||||
display: flex;
|
||||
animation: fadeIn 0.2s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-qrcode-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.feedback-qrcode-content {
|
||||
position: relative;
|
||||
background: var(--vscode-editor-background);
|
||||
border: 1px solid var(--vscode-widget-border);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
animation: slideUp 0.2s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-qrcode-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid var(--vscode-widget-border);
|
||||
}
|
||||
|
||||
.feedback-qrcode-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vscode-foreground);
|
||||
}
|
||||
|
||||
.feedback-qrcode-close {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.feedback-qrcode-close:hover {
|
||||
background: var(--vscode-toolbar-hoverBackground);
|
||||
}
|
||||
|
||||
.feedback-qrcode-close svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--vscode-foreground);
|
||||
}
|
||||
|
||||
.feedback-qrcode-body {
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.feedback-qrcode-image {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid var(--vscode-widget-border);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.feedback-qrcode-text {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
text-align: center;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@ -331,29 +182,6 @@ export function getMoreOptionsComponentScript(): string {
|
||||
closeMoreOptionsDropdown();
|
||||
}
|
||||
|
||||
// 打开用户反馈
|
||||
function openUserFeedback() {
|
||||
console.log('打开用户反馈');
|
||||
vscode.postMessage({ command: 'openUserFeedback' });
|
||||
closeMoreOptionsDropdown();
|
||||
}
|
||||
|
||||
// 显示用户反馈二维码弹窗
|
||||
function showFeedbackQRCode() {
|
||||
const modal = document.getElementById('feedbackQRCodeModal');
|
||||
if (modal) {
|
||||
modal.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭用户反馈二维码弹窗
|
||||
function closeFeedbackQRCode() {
|
||||
const modal = document.getElementById('feedbackQRCodeModal');
|
||||
if (modal) {
|
||||
modal.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定更多选项事件
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// 绑定用户手册选项
|
||||
@ -362,12 +190,6 @@ export function getMoreOptionsComponentScript(): string {
|
||||
userManualOption.addEventListener('click', openUserManual);
|
||||
}
|
||||
|
||||
// 绑定用户反馈选项
|
||||
const userFeedbackOption = document.getElementById('userFeedbackOption');
|
||||
if (userFeedbackOption) {
|
||||
userFeedbackOption.addEventListener('click', openUserFeedback);
|
||||
}
|
||||
|
||||
// 点击页面其他地方关闭下拉面板
|
||||
document.addEventListener('click', (e) => {
|
||||
const dropdown = document.getElementById('moreOptionsDropdown');
|
||||
|
||||
@ -25,7 +25,7 @@ export function getProgressBarContent(): string {
|
||||
<span class="step-number">1</span>
|
||||
<span class="step-check">✓</span>
|
||||
</div>
|
||||
<div class="step-label">Spec</div>
|
||||
<div class="step-label">Specification</div>
|
||||
</div>
|
||||
|
||||
<div class="progress-line"></div>
|
||||
|
||||
@ -3,11 +3,6 @@ import {
|
||||
getGeneralSettingsComponentStyles,
|
||||
getGeneralSettingsComponentScript,
|
||||
} from "./generalSettingsComponent";
|
||||
import {
|
||||
getRulesSettingsComponentContent,
|
||||
getRulesSettingsComponentStyles,
|
||||
getRulesSettingsComponentScript,
|
||||
} from "./rulesSettingsComponent";
|
||||
|
||||
/**
|
||||
* 获取设置面板的 HTML 内容
|
||||
@ -31,18 +26,13 @@ export function getSettingsComponentContent(): string {
|
||||
<button class="settings-nav-item active" data-tab="general" onclick="switchSettingsTab('general')">
|
||||
通用
|
||||
</button>
|
||||
<button class="settings-nav-item" data-tab="rules" onclick="switchSettingsTab('rules')">
|
||||
规则
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-content">
|
||||
<div class="settings-tab-content active" id="generalSettings">
|
||||
${getGeneralSettingsComponentContent()}
|
||||
</div>
|
||||
<div class="settings-tab-content" id="rulesSettings">
|
||||
${getRulesSettingsComponentContent()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -186,7 +176,6 @@ export function getSettingsComponentStyles(): string {
|
||||
}
|
||||
|
||||
${getGeneralSettingsComponentStyles()}
|
||||
${getRulesSettingsComponentStyles()}
|
||||
`;
|
||||
}
|
||||
|
||||
@ -196,7 +185,6 @@ export function getSettingsComponentStyles(): string {
|
||||
export function getSettingsComponentScript(): string {
|
||||
return `
|
||||
${getGeneralSettingsComponentScript()}
|
||||
${getRulesSettingsComponentScript()}
|
||||
|
||||
// 打开设置面板
|
||||
function openSettingsModal() {
|
||||
|
||||
@ -18,6 +18,11 @@ import {
|
||||
getMessageAreaScript,
|
||||
} from "./messageArea";
|
||||
import { getAgentCardStyles, getAgentCardScript } from "./agentCard";
|
||||
import {
|
||||
getMoreOptionsComponentContent,
|
||||
getMoreOptionsComponentStyles,
|
||||
getMoreOptionsComponentScript,
|
||||
} from "./moreOptionsComponent";
|
||||
import {
|
||||
getProgressBarContent,
|
||||
getProgressBarStyles,
|
||||
@ -110,6 +115,7 @@ export function getWebviewContent(
|
||||
}
|
||||
${getMessageAreaStyles()}
|
||||
${getAgentCardStyles()}
|
||||
${getMoreOptionsComponentStyles()}
|
||||
${getWaveformPreviewContent()}
|
||||
${getConversationHistoryBarStyles()}
|
||||
${getProgressBarStyles()}
|
||||
@ -375,16 +381,32 @@ export function getWebviewContent(
|
||||
font-size: 13px;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
}
|
||||
.status-bar #statusText {
|
||||
background: linear-gradient(90deg,
|
||||
var(--vscode-descriptionForeground) 0%,
|
||||
var(--vscode-foreground) 50%,
|
||||
var(--vscode-descriptionForeground) 100%);
|
||||
background-size: 200% 100%;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
animation: textShimmer 2s linear infinite;
|
||||
}
|
||||
@keyframes textShimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
.status-indicator {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--vscode-charts-blue);
|
||||
animation: statusPulse 1.5s ease-in-out infinite;
|
||||
box-shadow: 0 0 8px currentColor;
|
||||
}
|
||||
@keyframes statusPulse {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.5; transform: scale(0.8); }
|
||||
0%, 100% { opacity: 1; transform: scale(1.2); }
|
||||
50% { opacity: 0.3; transform: scale(0.6); }
|
||||
}
|
||||
.status-bar.working .status-indicator {
|
||||
background: var(--vscode-charts-orange);
|
||||
@ -488,13 +510,17 @@ export function getWebviewContent(
|
||||
${getNdtWelcomeModalContent(logoUri)}
|
||||
${getExpiredModalContent(logoUri)}
|
||||
<div class="header">
|
||||
<div style="display: flex; align-items: center; justify-content: center;">
|
||||
<div style="display: flex; align-items: flex-end; justify-content: center">
|
||||
<img src="${logoUri}" alt="IC Coder" style="max-width: 100%; height: auto; max-height: 80px;" />
|
||||
<span style="font-size: 23px; font-weight: bold; background: linear-gradient(to bottom, #b2e4ff, #42bcff); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin: 0 0 14px -16px;">企业版</span>
|
||||
</div>
|
||||
<p style="font-size: 16px; margin-top: 12px; line-height: 1.5;">
|
||||
The <span style="background: linear-gradient(to right, #42bcff, #4A9EFF); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: bold;">Agentic AI</span> Verilog Coding Platform,
|
||||
<span style="display: block; margin-top: 8px;">将芯片设计与验证的效率提升至少20倍!</span>
|
||||
<p style="font-size: 16px; margin-top: 8px; line-height: 1.5;">
|
||||
The <span style="background: linear-gradient(to right, #42bcff, #4A9EFF); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: bold;">Agentic AI</span> Verilog Coding Platform
|
||||
<span style="display: block; margin-top: 8px;">将FPGA研发效率提升至少20倍!</span>
|
||||
</p>
|
||||
<div style="margin-top: 16px; padding: 8px 20px; background: linear-gradient(135deg, rgba(255, 215, 0, 0.15), rgba(255, 165, 0, 0.15)); border: 1px solid rgba(255, 215, 0, 0.3); border-radius: 6px;">
|
||||
<p style="font-size: 13px; margin: 0; background: linear-gradient(135deg, #FFD700, #FFA500); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600; letter-spacing: 1px;">宁德时代专属定制版</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-container">
|
||||
@ -917,6 +943,7 @@ export function getWebviewContent(
|
||||
|
||||
${getMessageAreaScript()}
|
||||
${getAgentCardScript()}
|
||||
${getMoreOptionsComponentScript()}
|
||||
${getWaveformPreviewScript()}
|
||||
${getConversationHistoryBarScript()}
|
||||
${getProgressBarScript()}
|
||||
|
||||