mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
Merge branch 'main' of https://github.com/QwenLM/qwen-code into feat/jinjing/implement-ui-from-cc-vscode-extension
This commit is contained in:
@@ -1,315 +0,0 @@
|
||||
# 自动锁定编辑器组功能实现
|
||||
|
||||
## 概述
|
||||
|
||||
参考 Claude Code 的实现,Qwen Code VSCode 扩展现在支持自动锁定编辑器组功能,确保 AI 助手界面保持稳定,不会被其他编辑器替换或意外关闭。
|
||||
|
||||
## 实现原理
|
||||
|
||||
### 1. VSCode 锁定组机制
|
||||
|
||||
**VSCode 源码分析**(`src/vs/workbench/browser/parts/editor/editor.contribution.ts:558-566`):
|
||||
|
||||
```typescript
|
||||
// Lock Group: only on auxiliary window and when group is unlocked
|
||||
appendEditorToolItem(
|
||||
{
|
||||
id: LOCK_GROUP_COMMAND_ID,
|
||||
title: localize('lockEditorGroup', 'Lock Group'),
|
||||
icon: Codicon.unlock,
|
||||
},
|
||||
ContextKeyExpr.and(
|
||||
IsAuxiliaryEditorPartContext,
|
||||
ActiveEditorGroupLockedContext.toNegated(),
|
||||
),
|
||||
CLOSE_ORDER - 1, // immediately to the left of close action
|
||||
);
|
||||
```
|
||||
|
||||
**关键条件**:
|
||||
|
||||
- `IsAuxiliaryEditorPartContext`: 当前是辅助窗口的编辑器组
|
||||
- `ActiveEditorGroupLockedContext.toNegated()`: 当前组未锁定
|
||||
|
||||
### 2. Claude Code 的实现方式
|
||||
|
||||
Claude Code 在创建 webview panel 时会检测是否在新列中打开:
|
||||
|
||||
```typescript
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(
|
||||
'claude-vscode.editor.open',
|
||||
async (param1, param2) => {
|
||||
context.globalState.update('lastClaudeLocation', 1);
|
||||
let { startedInNewColumn } = webviewProvider.createPanel(param1, param2);
|
||||
|
||||
// 如果在新列中打开,则自动锁定编辑器组
|
||||
if (startedInNewColumn) {
|
||||
await vscode.commands.executeCommand(
|
||||
'workbench.action.lockEditorGroup',
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
### 3. Qwen Code 的实现
|
||||
|
||||
**文件位置**: `packages/vscode-ide-companion/src/WebViewProvider.ts:101-153`
|
||||
|
||||
```typescript
|
||||
async show(): Promise<void> {
|
||||
// Track if we're creating a new panel in a new column
|
||||
let startedInNewColumn = false;
|
||||
|
||||
if (this.panel) {
|
||||
// If panel already exists, just reveal it (no lock needed)
|
||||
this.revealPanelTab(true);
|
||||
this.capturePanelTab();
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark that we're creating a new panel
|
||||
startedInNewColumn = true;
|
||||
|
||||
this.panel = vscode.window.createWebviewPanel(
|
||||
'qwenCode.chat',
|
||||
'Qwen Code Chat',
|
||||
{
|
||||
viewColumn: vscode.ViewColumn.Beside, // Open on right side of active editor
|
||||
preserveFocus: true, // Don't steal focus from editor
|
||||
},
|
||||
{
|
||||
enableScripts: true,
|
||||
retainContextWhenHidden: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(this.extensionUri, 'dist')],
|
||||
},
|
||||
);
|
||||
|
||||
// Capture the Tab that corresponds to our WebviewPanel (Claude-style)
|
||||
this.capturePanelTab();
|
||||
|
||||
// Auto-lock editor group when opened in new column (Claude Code style)
|
||||
if (startedInNewColumn) {
|
||||
console.log('[WebViewProvider] Auto-locking editor group for Qwen Code chat');
|
||||
try {
|
||||
// Reveal panel without preserving focus to make it the active group
|
||||
// This ensures the lock command targets the correct editor group
|
||||
this.revealPanelTab(false);
|
||||
|
||||
await vscode.commands.executeCommand('workbench.action.lockEditorGroup');
|
||||
console.log('[WebViewProvider] Editor group locked successfully');
|
||||
} catch (error) {
|
||||
console.warn('[WebViewProvider] Failed to lock editor group:', error);
|
||||
// Non-fatal error, continue anyway
|
||||
}
|
||||
} else {
|
||||
// For existing panel, reveal with preserving focus
|
||||
this.revealPanelTab(true);
|
||||
}
|
||||
|
||||
// Continue with panel setup...
|
||||
}
|
||||
```
|
||||
|
||||
### 关键修复:preserveFocus 问题
|
||||
|
||||
**问题发现**:
|
||||
|
||||
- 最初实现中,`createWebviewPanel` 使用了 `preserveFocus: true`
|
||||
- 这导致焦点保留在左边的编辑器组,左边的组仍然是**活动组(activeGroup)**
|
||||
- 执行 `workbench.action.lockEditorGroup` 时,命令默认作用于活动组
|
||||
- 结果:**错误地锁定了左边的编辑器组**,而不是 webview 所在的组
|
||||
|
||||
**错误的执行流程**:
|
||||
|
||||
```
|
||||
1. createWebviewPanel() 创建新组
|
||||
└─> preserveFocus: true 保持焦点在左边
|
||||
└─> activeGroup 仍然是左边的编辑器组
|
||||
|
||||
2. executeCommand("workbench.action.lockEditorGroup")
|
||||
└─> resolveCommandsContext() 使用 activeGroup
|
||||
└─> activeGroup = 左边的编辑器组 ❌
|
||||
└─> 错误地锁定了左边的组
|
||||
```
|
||||
|
||||
**修复方案**:
|
||||
|
||||
1. 在执行锁定命令之前,调用 `this.revealPanelTab(false)`
|
||||
2. 这会让 webview panel 获得焦点并成为活动组
|
||||
3. 然后执行锁定命令就会锁定正确的组
|
||||
|
||||
**修复后的执行流程**:
|
||||
|
||||
```
|
||||
1. createWebviewPanel() 创建新组
|
||||
└─> preserveFocus: true 保持焦点在左边
|
||||
|
||||
2. revealPanelTab(false) 激活 webview 组
|
||||
└─> webview 组成为 activeGroup
|
||||
|
||||
3. executeCommand("workbench.action.lockEditorGroup")
|
||||
└─> resolveCommandsContext() 使用 activeGroup
|
||||
└─> activeGroup = webview 所在的组 ✓
|
||||
└─> 正确锁定 webview 所在的组
|
||||
```
|
||||
|
||||
## 执行流程
|
||||
|
||||
```
|
||||
1. 用户打开 Qwen Code chat
|
||||
↓
|
||||
2. 调用 WebViewProvider.show()
|
||||
↓
|
||||
3. 检查是否已有 panel
|
||||
- 有:直接 reveal,不执行锁定
|
||||
- 无:创建新 panel,设置 startedInNewColumn = true
|
||||
↓
|
||||
4. 创建 webview panel
|
||||
- viewColumn: ViewColumn.Beside
|
||||
- preserveFocus: true (不抢夺焦点,保持在编辑器)
|
||||
↓
|
||||
5. 捕获 Tab 引用
|
||||
- 调用 capturePanelTab() 保存 Tab 对象
|
||||
↓
|
||||
6. 执行自动锁定(startedInNewColumn === true)
|
||||
- 调用 revealPanelTab(false) 激活 webview 组
|
||||
- webview 所在的组成为活动组(activeGroup)
|
||||
- 执行命令: workbench.action.lockEditorGroup
|
||||
- 命令作用于活动组,正确锁定 webview 组
|
||||
↓
|
||||
7. 编辑器组被锁定
|
||||
- ActiveEditorGroupLockedContext 变为 true
|
||||
- 工具栏显示"解锁组"按钮(锁定图标)
|
||||
- webview 保持在固定位置
|
||||
```
|
||||
|
||||
## 功能效果
|
||||
|
||||
### 锁定前
|
||||
|
||||
- ❌ 用户可以拖拽 Qwen Code panel 到其他位置
|
||||
- ❌ 其他编辑器可能替换 Qwen Code panel
|
||||
- ❌ 容易意外关闭整个编辑器组
|
||||
|
||||
### 锁定后
|
||||
|
||||
- ✅ Qwen Code panel 保持在固定位置
|
||||
- ✅ 编辑器组不会被其他操作影响
|
||||
- ✅ 工具栏显示"锁定组"按钮,用户可以手动解锁
|
||||
- ✅ 类似侧边栏的稳定行为
|
||||
|
||||
## 设计优势
|
||||
|
||||
1. **防止意外操作**
|
||||
- 锁定后用户不能轻易拖拽或关闭 AI 助手界面
|
||||
- 减少误操作导致的工作流中断
|
||||
|
||||
2. **保持固定位置**
|
||||
- AI 助手界面始终在用户期望的位置
|
||||
- 符合"AI 助手作为辅助工具"的定位
|
||||
|
||||
3. **用户可控**
|
||||
- 自动锁定提供默认保护
|
||||
- 用户仍可以通过工具栏解锁按钮手动解锁
|
||||
- 平衡了便利性和灵活性
|
||||
|
||||
4. **一致的用户体验**
|
||||
- 与 Claude Code 保持一致的交互模式
|
||||
- 用户无需学习新的行为模式
|
||||
|
||||
## 错误处理
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await vscode.commands.executeCommand('workbench.action.lockEditorGroup');
|
||||
console.log('[WebViewProvider] Editor group locked successfully');
|
||||
} catch (error) {
|
||||
console.warn('[WebViewProvider] Failed to lock editor group:', error);
|
||||
// Non-fatal error, continue anyway
|
||||
}
|
||||
```
|
||||
|
||||
**设计考虑**:
|
||||
|
||||
- 锁定失败不影响 panel 的正常功能
|
||||
- 记录警告日志便于调试
|
||||
- 优雅降级,不中断用户工作流
|
||||
|
||||
## 配置选项(可选扩展)
|
||||
|
||||
如果需要让用户控制是否自动锁定,可以添加配置项:
|
||||
|
||||
```typescript
|
||||
// 在 package.json 中添加配置
|
||||
"qwenCode.autoLockEditorGroup": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Automatically lock the editor group when opening Qwen Code chat"
|
||||
}
|
||||
|
||||
// 在代码中检查配置
|
||||
const config = vscode.workspace.getConfiguration('qwenCode');
|
||||
const autoLock = config.get<boolean>('autoLockEditorGroup', true);
|
||||
|
||||
if (startedInNewColumn && autoLock) {
|
||||
await vscode.commands.executeCommand('workbench.action.lockEditorGroup');
|
||||
}
|
||||
```
|
||||
|
||||
## 测试场景
|
||||
|
||||
### 场景 1: 首次打开 Qwen Code
|
||||
|
||||
1. 打开 VSCode,没有 Qwen Code panel
|
||||
2. 执行命令打开 Qwen Code chat
|
||||
3. **预期**: Panel 在新列中打开,编辑器组自动锁定
|
||||
|
||||
### 场景 2: 已有 Qwen Code panel
|
||||
|
||||
1. Qwen Code panel 已打开
|
||||
2. 切换到其他编辑器
|
||||
3. 再次打开 Qwen Code chat
|
||||
4. **预期**: Panel 被 reveal,不重复锁定
|
||||
|
||||
### 场景 3: 手动解锁后
|
||||
|
||||
1. Qwen Code panel 已锁定
|
||||
2. 用户点击工具栏解锁按钮
|
||||
3. 编辑器组被解锁
|
||||
4. **预期**: 用户可以自由操作编辑器组
|
||||
|
||||
### 场景 4: 关闭并重新打开
|
||||
|
||||
1. Qwen Code panel 已打开并锁定
|
||||
2. 用户关闭 panel
|
||||
3. 再次打开 Qwen Code chat
|
||||
4. **预期**: 新 panel 在新列打开,自动锁定
|
||||
|
||||
## 兼容性
|
||||
|
||||
- ✅ VSCode 1.85+(支持 `workbench.action.lockEditorGroup` 命令)
|
||||
- ✅ 所有操作系统(Windows, macOS, Linux)
|
||||
- ✅ 不影响现有功能
|
||||
- ✅ 向后兼容旧版本 VSCode(锁定失败时优雅降级)
|
||||
|
||||
## 相关 VSCode 命令
|
||||
|
||||
| 命令 | 功能 |
|
||||
| ---------------------------------------- | -------------------- |
|
||||
| `workbench.action.lockEditorGroup` | 锁定当前编辑器组 |
|
||||
| `workbench.action.unlockEditorGroup` | 解锁当前编辑器组 |
|
||||
| `workbench.action.toggleEditorGroupLock` | 切换编辑器组锁定状态 |
|
||||
|
||||
## 总结
|
||||
|
||||
通过模仿 Claude Code 的实现,Qwen Code 现在提供了:
|
||||
|
||||
1. ✅ 自动锁定编辑器组功能
|
||||
2. ✅ 与 Claude Code 一致的用户体验
|
||||
3. ✅ 稳定的 AI 助手界面位置
|
||||
4. ✅ 优雅的错误处理
|
||||
|
||||
这个功能显著提升了用户体验,让 AI 助手界面更加稳定可靠!
|
||||
@@ -1,290 +0,0 @@
|
||||
# Claude Code 样式提取与应用
|
||||
|
||||
本文档记录了从 Claude Code 扩展 (v2.0.43) 编译产物中提取的样式,并应用到我们的 VSCode IDE Companion 项目中。
|
||||
|
||||
## 提取来源
|
||||
|
||||
- **路径**: `/Users/jinjing/Downloads/Anthropic.claude-code-2.0.43/extension/webview/index.css`
|
||||
- **版本**: 2.0.43
|
||||
- **文件类型**: 编译后的压缩 CSS
|
||||
|
||||
## 提取的核心样式类
|
||||
|
||||
### 1. Header 样式 (`.he`)
|
||||
|
||||
```css
|
||||
.he {
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--app-primary-border-color);
|
||||
padding: 6px 10px;
|
||||
gap: 4px;
|
||||
background-color: var(--app-header-background);
|
||||
justify-content: flex-start;
|
||||
user-select: none;
|
||||
}
|
||||
```
|
||||
|
||||
**应用到**: `.chat-header`
|
||||
|
||||
**改进点**:
|
||||
|
||||
- `gap: 4px` - 更紧凑的间距
|
||||
- `justify-content: flex-start` - 左对齐而非 space-between
|
||||
- `background-color: var(--app-header-background)` - 使用独立的 header 背景变量
|
||||
|
||||
### 2. Session Selector 按钮 (`.E`)
|
||||
|
||||
```css
|
||||
.E {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 2px 8px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
}
|
||||
|
||||
.E:focus,
|
||||
.E:hover {
|
||||
background: var(--app-ghost-button-hover-background);
|
||||
}
|
||||
```
|
||||
|
||||
**应用到**: `.session-selector-dropdown select`
|
||||
|
||||
**改进点**:
|
||||
|
||||
- `background: transparent` - 默认透明背景
|
||||
- `gap: 6px` - 内部元素间距
|
||||
- `min-width: 0; max-width: 300px` - 响应式宽度控制
|
||||
- `overflow: hidden` - 处理文本溢出
|
||||
|
||||
### 3. 图标按钮 (`.j`)
|
||||
|
||||
```css
|
||||
.j {
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
outline: none;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.j:focus,
|
||||
.j:hover {
|
||||
background: var(--app-ghost-button-hover-background);
|
||||
}
|
||||
```
|
||||
|
||||
**应用到**: `.new-session-header-button`
|
||||
|
||||
**改进点**:
|
||||
|
||||
- `flex: 0 0 auto` - 固定尺寸不伸缩
|
||||
- `border: 1px solid transparent` - 保留边框空间但透明
|
||||
- 精确的 `24px × 24px` 尺寸
|
||||
|
||||
### 4. Session Selector 弹窗 (`.Wt`)
|
||||
|
||||
```css
|
||||
.Wt {
|
||||
position: fixed;
|
||||
background: var(--app-menu-background);
|
||||
border: 1px solid var(--app-menu-border);
|
||||
border-radius: var(--corner-radius-small);
|
||||
width: min(400px, calc(100vw - 32px));
|
||||
max-height: min(500px, 50vh);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
outline: none;
|
||||
font-size: var(--vscode-chat-font-size, 13px);
|
||||
font-family: var(--vscode-chat-font-family);
|
||||
}
|
||||
```
|
||||
|
||||
**应用到**: `.session-selector`
|
||||
|
||||
**关键特性**:
|
||||
|
||||
- `width: min(400px, calc(100vw - 32px))` - 响应式宽度,小屏幕自适应
|
||||
- `max-height: min(500px, 50vh)` - 响应式高度
|
||||
- `box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1)` - 柔和阴影
|
||||
- 使用 menu 相关的 CSS 变量
|
||||
|
||||
### 5. Session List (`.It`, `.St`, `.s`)
|
||||
|
||||
```css
|
||||
/* Content area */
|
||||
.It {
|
||||
padding: 8px;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* List container */
|
||||
.St {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--app-list-padding);
|
||||
gap: var(--app-list-gap);
|
||||
}
|
||||
|
||||
/* List item */
|
||||
.s {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--app-list-item-padding);
|
||||
justify-content: space-between;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.s:hover {
|
||||
background: var(--app-list-hover-background);
|
||||
}
|
||||
|
||||
.s.U {
|
||||
background: var(--app-list-active-background);
|
||||
color: var(--app-list-active-foreground);
|
||||
}
|
||||
```
|
||||
|
||||
**应用到**: `.session-list`, `.session-item`
|
||||
|
||||
**改进点**:
|
||||
|
||||
- `border-radius: 6px` - 圆角列表项
|
||||
- `user-select: none` - 禁止选择文本
|
||||
- 使用统一的 list 变量系统
|
||||
|
||||
## 新增 CSS 变量
|
||||
|
||||
从 Claude Code 中提取并添加的 CSS 变量:
|
||||
|
||||
```css
|
||||
/* Header */
|
||||
--app-header-background: var(--vscode-sideBar-background);
|
||||
|
||||
/* List Styles */
|
||||
--app-list-padding: 0px;
|
||||
--app-list-item-padding: 4px 8px;
|
||||
--app-list-border-color: transparent;
|
||||
--app-list-border-radius: 4px;
|
||||
--app-list-hover-background: var(--vscode-list-hoverBackground);
|
||||
--app-list-active-background: var(--vscode-list-activeSelectionBackground);
|
||||
--app-list-active-foreground: var(--vscode-list-activeSelectionForeground);
|
||||
--app-list-gap: 2px;
|
||||
|
||||
/* Menu Colors */
|
||||
--app-menu-background: var(--vscode-menu-background);
|
||||
--app-menu-border: var(--vscode-menu-border);
|
||||
--app-menu-foreground: var(--vscode-menu-foreground);
|
||||
--app-menu-selection-background: var(--vscode-menu-selectionBackground);
|
||||
--app-menu-selection-foreground: var(--vscode-menu-selectionForeground);
|
||||
|
||||
/* Ghost Button */
|
||||
--app-ghost-button-hover-background: var(--vscode-toolbar-hoverBackground);
|
||||
```
|
||||
|
||||
## 设计理念总结
|
||||
|
||||
通过分析 Claude Code 的样式,我们发现以下设计理念:
|
||||
|
||||
### 1. **响应式优先**
|
||||
|
||||
- 使用 `min()` 函数实现响应式尺寸
|
||||
- 如: `width: min(400px, calc(100vw - 32px))`
|
||||
|
||||
### 2. **一致的间距系统**
|
||||
|
||||
- 小间距: 4px
|
||||
- 中间距: 8px
|
||||
- 大间距: 12px, 16px
|
||||
|
||||
### 3. **柔和的视觉效果**
|
||||
|
||||
- 透明背景 + hover 时显示背景色
|
||||
- 柔和的阴影: `0 4px 16px rgba(0, 0, 0, 0.1)`
|
||||
- 圆角统一使用变量: `var(--corner-radius-small)` = 4px
|
||||
|
||||
### 4. **完整的变量系统**
|
||||
|
||||
- 所有颜色都通过 CSS 变量定义
|
||||
- 支持 VSCode 主题自动适配
|
||||
- 有合理的 fallback 值
|
||||
|
||||
### 5. **交互反馈清晰**
|
||||
|
||||
- `:hover` 和 `:focus` 状态使用相同样式
|
||||
- 使用 `var(--app-ghost-button-hover-background)` 统一 hover 背景
|
||||
|
||||
## 文件变更
|
||||
|
||||
### 修改的文件
|
||||
|
||||
1. **`src/webview/App.css`**
|
||||
- 更新 Header 样式
|
||||
- 更新 Session Selector Modal 样式
|
||||
- 添加新的 CSS 变量
|
||||
|
||||
### 新增的文件
|
||||
|
||||
1. **`src/webview/ClaudeCodeStyles.css`**
|
||||
- 完整的 Claude Code 样式提取
|
||||
- 包含详细注释和类名映射
|
||||
|
||||
2. **`CLAUDE_CODE_STYLES.md`**
|
||||
- 本文档,记录样式提取和应用过程
|
||||
|
||||
## 效果对比
|
||||
|
||||
### 之前
|
||||
|
||||
- Header 使用 `justify-content: space-between`
|
||||
- Session selector 宽度固定 80%
|
||||
- 阴影较重: `rgba(0, 0, 0, 0.3)`
|
||||
- 间距不够紧凑
|
||||
|
||||
### 之后
|
||||
|
||||
- Header 使用 `justify-content: flex-start`,间距 4px
|
||||
- Session selector 响应式宽度 `min(400px, calc(100vw - 32px))`
|
||||
- 柔和阴影: `rgba(0, 0, 0, 0.1)`
|
||||
- 更紧凑的布局,更接近 Claude Code 的视觉风格
|
||||
|
||||
## 下一步优化建议
|
||||
|
||||
1. **添加选中状态图标** (`.ne` check icon)
|
||||
2. **实现 session list 的分组显示** (`.te` group header)
|
||||
3. **添加 session selector button 的图标和箭头** (`.xe`, `.fe`, `.ve` 等)
|
||||
4. **考虑添加 session 数量徽章**
|
||||
5. **优化移动端适配**
|
||||
|
||||
## 参考资料
|
||||
|
||||
- Claude Code Extension: https://marketplace.visualstudio.com/items?itemName=Anthropic.claude-code
|
||||
- 源文件位置: `/Users/jinjing/Downloads/Anthropic.claude-code-2.0.43/extension/webview/index.css`
|
||||
Reference in New Issue
Block a user