v3.2.3: 工作空间面板改为常驻显示,固定宽度480px,不可关闭不可拖拽
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "metona-ollama-desktop",
|
"name": "metona-ollama-desktop",
|
||||||
"version": "3.2.2",
|
"version": "3.2.3",
|
||||||
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
|
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
|
||||||
"main": "dist/main/main.js",
|
"main": "dist/main/main.js",
|
||||||
"author": "thzxx",
|
"author": "thzxx",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ interface FileNode {
|
|||||||
loaded?: boolean;
|
loaded?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let panelVisible = false;
|
let panelVisible = true; // 常驻显示,不可关闭
|
||||||
let activeTab: 'terminal' | 'files' = 'terminal';
|
let activeTab: 'terminal' | 'files' = 'terminal';
|
||||||
let terminalSessions: TerminalSession[] = [];
|
let terminalSessions: TerminalSession[] = [];
|
||||||
let activeTerminalId = '';
|
let activeTerminalId = '';
|
||||||
@@ -181,12 +181,6 @@ export async function initWorkspacePanel(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bindEvents(): void {
|
function bindEvents(): void {
|
||||||
// 切换面板显示
|
|
||||||
document.querySelector('#btnWorkspace')?.addEventListener('click', togglePanel);
|
|
||||||
document.querySelector('#btnWorkspaceClose')?.addEventListener('click', () => {
|
|
||||||
if (panelVisible) togglePanel();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Tab 切换
|
// Tab 切换
|
||||||
document.querySelector('#wsTabTerminal')?.addEventListener('click', () => switchTab('terminal'));
|
document.querySelector('#wsTabTerminal')?.addEventListener('click', () => switchTab('terminal'));
|
||||||
document.querySelector('#wsTabFiles')?.addEventListener('click', () => switchTab('files'));
|
document.querySelector('#wsTabFiles')?.addEventListener('click', () => switchTab('files'));
|
||||||
@@ -243,58 +237,9 @@ function bindEvents(): void {
|
|||||||
previewFile = null;
|
previewFile = null;
|
||||||
renderPanel();
|
renderPanel();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 拖拽调整宽度
|
|
||||||
setupResizer();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupResizer(): void {
|
|
||||||
const resizer = document.querySelector('#wsResizer') as HTMLElement;
|
|
||||||
const panel = document.querySelector('#workspacePanel') as HTMLElement;
|
|
||||||
if (!resizer || !panel) return;
|
|
||||||
|
|
||||||
let startX = 0;
|
|
||||||
let startWidth = 0;
|
|
||||||
|
|
||||||
resizer.addEventListener('mousedown', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
startX = e.clientX;
|
|
||||||
startWidth = panel.offsetWidth;
|
|
||||||
|
|
||||||
const onMouseMove = (e: MouseEvent) => {
|
|
||||||
const delta = startX - e.clientX; // 向左拖拽增大宽度
|
|
||||||
const newWidth = Math.min(700, Math.max(300, startWidth + delta));
|
|
||||||
panel.style.width = newWidth + 'px';
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseUp = () => {
|
|
||||||
document.removeEventListener('mousemove', onMouseMove);
|
|
||||||
document.removeEventListener('mouseup', onMouseUp);
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('mousemove', onMouseMove);
|
|
||||||
document.addEventListener('mouseup', onMouseUp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 面板控制 ──
|
|
||||||
export function togglePanel(): void {
|
|
||||||
panelVisible = !panelVisible;
|
|
||||||
const panel = document.querySelector('#workspacePanel') as HTMLElement;
|
|
||||||
const btn = document.querySelector('#btnWorkspace') as HTMLElement;
|
|
||||||
const mainWrap = document.querySelector('#mainWrap') as HTMLElement;
|
|
||||||
|
|
||||||
if (panel) panel.style.display = panelVisible ? '' : 'none';
|
|
||||||
if (btn) btn.classList.toggle('active', panelVisible);
|
|
||||||
if (mainWrap) mainWrap.classList.toggle('with-workspace', panelVisible);
|
|
||||||
|
|
||||||
if (panelVisible) {
|
|
||||||
if (activeTab === 'files') loadFiles(currentFileDir || workspaceDir);
|
|
||||||
const termInput = document.querySelector('#wsTermInput') as HTMLElement;
|
|
||||||
termInput?.focus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 面板控制 ──(常驻显示,无需切换)
|
||||||
function switchTab(tab: 'terminal' | 'files'): void {
|
function switchTab(tab: 'terminal' | 'files'): void {
|
||||||
activeTab = tab;
|
activeTab = tab;
|
||||||
renderPanel();
|
renderPanel();
|
||||||
@@ -693,9 +638,6 @@ function formatSize(bytes: number): string {
|
|||||||
|
|
||||||
/** 从聊天区域调用:在工作空间执行命令 */
|
/** 从聊天区域调用:在工作空间执行命令 */
|
||||||
export function execInWorkspace(command: string): void {
|
export function execInWorkspace(command: string): void {
|
||||||
// 确保面板可见
|
|
||||||
if (!panelVisible) togglePanel();
|
|
||||||
|
|
||||||
// 切换到终端 tab
|
// 切换到终端 tab
|
||||||
activeTab = 'terminal';
|
activeTab = 'terminal';
|
||||||
|
|
||||||
|
|||||||
+3
-15
@@ -20,7 +20,7 @@
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- ═══════════════ 主内容区 ═══════════════ -->
|
<!-- ═══════════════ 主内容区 ═══════════════ -->
|
||||||
<div class="main-wrap" id="mainWrap">
|
<div class="main-wrap with-workspace" id="mainWrap">
|
||||||
|
|
||||||
<!-- ═══════════════ 顶部导航 ═══════════════ -->
|
<!-- ═══════════════ 顶部导航 ═══════════════ -->
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
@@ -65,12 +65,6 @@
|
|||||||
<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
|
<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="icon-btn" id="btnWorkspace" title="工作空间">
|
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
||||||
<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/>
|
|
||||||
<rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<button class="icon-btn" id="btnSettings" title="设置">
|
<button class="icon-btn" id="btnSettings" title="设置">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<circle cx="12" cy="12" r="3"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
<circle cx="12" cy="12" r="3"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||||
@@ -173,20 +167,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div><!-- /.main-wrap -->
|
</div><!-- /.main-wrap -->
|
||||||
|
|
||||||
<!-- ═══════════════ 工作空间面板(右侧)═══════════════ -->
|
<!-- ═══════════════ 工作空间面板(右侧,常驻显示)═══════════════ -->
|
||||||
<aside class="workspace-panel" id="workspacePanel" style="display:none;">
|
<aside class="workspace-panel" id="workspacePanel">
|
||||||
<div class="ws-resizer" id="wsResizer" title="拖拽调整宽度"></div>
|
|
||||||
<div class="ws-header">
|
<div class="ws-header">
|
||||||
<span class="ws-title">🖥️ 工作空间</span>
|
<span class="ws-title">🖥️ 工作空间</span>
|
||||||
<div class="ws-tabs">
|
<div class="ws-tabs">
|
||||||
<button class="ws-header-tab active" id="wsTabTerminal">💻 命令行</button>
|
<button class="ws-header-tab active" id="wsTabTerminal">💻 命令行</button>
|
||||||
<button class="ws-header-tab" id="wsTabFiles">📁 文件</button>
|
<button class="ws-header-tab" id="wsTabFiles">📁 文件</button>
|
||||||
</div>
|
</div>
|
||||||
<button class="icon-btn ws-toggle-btn" id="btnWorkspaceClose" title="收起面板">
|
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
||||||
<polyline points="9 18 15 12 9 6"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 终端 Tab -->
|
<!-- 终端 Tab -->
|
||||||
|
|||||||
@@ -2670,7 +2670,7 @@ html, body {
|
|||||||
top: 90px; /* header(44px) + model-bar(46px) */
|
top: 90px; /* header(44px) + model-bar(46px) */
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 420px;
|
width: 480px;
|
||||||
background: var(--bg-solid, #202020);
|
background: var(--bg-solid, #202020);
|
||||||
border-left: 1px solid var(--border-default, rgba(255,255,255,0.08));
|
border-left: 1px solid var(--border-default, rgba(255,255,255,0.08));
|
||||||
border-top: 1px solid var(--border-default, rgba(255,255,255,0.08));
|
border-top: 1px solid var(--border-default, rgba(255,255,255,0.08));
|
||||||
@@ -2680,21 +2680,6 @@ html, body {
|
|||||||
font-family: 'Cascadia Code', 'Consolas', 'Courier New', monospace;
|
font-family: 'Cascadia Code', 'Consolas', 'Courier New', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ws-resizer {
|
|
||||||
position: absolute;
|
|
||||||
left: -3px;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 6px;
|
|
||||||
cursor: col-resize;
|
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ws-resizer:hover {
|
|
||||||
background: var(--accent, #60CDFF);
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ws-header {
|
.ws-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -2742,11 +2727,6 @@ html, body {
|
|||||||
border-color: var(--border-strong, rgba(255,255,255,0.12));
|
border-color: var(--border-strong, rgba(255,255,255,0.12));
|
||||||
}
|
}
|
||||||
|
|
||||||
.ws-toggle-btn {
|
|
||||||
margin-left: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── 终端内容区 ── */
|
/* ── 终端内容区 ── */
|
||||||
|
|
||||||
.ws-content {
|
.ws-content {
|
||||||
@@ -3086,13 +3066,8 @@ html, body {
|
|||||||
|
|
||||||
/* ── Header 按钮高亮 ── */
|
/* ── Header 按钮高亮 ── */
|
||||||
|
|
||||||
#btnWorkspace.active {
|
|
||||||
color: var(--accent, #60CDFF);
|
|
||||||
background: var(--accent-subtle, rgba(96,205,255,0.06));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── 主内容区自适应 ── */
|
/* ── 主内容区自适应 ── */
|
||||||
|
|
||||||
.main-wrap.with-workspace {
|
.main-wrap.with-workspace {
|
||||||
margin-right: 420px;
|
margin-right: 480px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user