feat(workspace): add workspace bottom bar, terminal tab manager, and run-process integration
This commit is contained in:
@@ -17,7 +17,10 @@ import '../dees-workspace-monaco/dees-workspace-monaco.js';
|
||||
import '../dees-workspace-filetree/dees-workspace-filetree.js';
|
||||
import { DeesWorkspaceFiletree } from '../dees-workspace-filetree/dees-workspace-filetree.js';
|
||||
import '../dees-workspace-terminal/dees-workspace-terminal.js';
|
||||
import { DeesWorkspaceTerminal } from '../dees-workspace-terminal/dees-workspace-terminal.js';
|
||||
import type { IRunProcessEventDetail } from '../dees-workspace-terminal/interfaces.js';
|
||||
import '../dees-workspace-terminal-preview/dees-workspace-terminal-preview.js';
|
||||
import '../dees-workspace-bottombar/dees-workspace-bottombar.js';
|
||||
import '../../dees-icon/dees-icon.js';
|
||||
import { DeesWorkspaceMonaco } from '../dees-workspace-monaco/dees-workspace-monaco.js';
|
||||
import { TypeScriptIntelliSenseManager } from './typescript-intellisense.js';
|
||||
@@ -370,10 +373,18 @@ testSmartPromise();
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
.workspace-outer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.workspace-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -857,121 +868,129 @@ testSmartPromise();
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="${containerClasses}">
|
||||
<!-- Filetree panel (full height) -->
|
||||
${this.showFileTree ? html`
|
||||
<div
|
||||
class="filetree-panel ${this.isFileTreeCollapsed ? 'collapsed' : ''}"
|
||||
style="width: ${this.isFileTreeCollapsed ? 0 : this.currentFileTreeWidth}px"
|
||||
>
|
||||
<dees-workspace-filetree
|
||||
.executionEnvironment=${this.executionEnvironment}
|
||||
.selectedPath=${this.activeFilePath}
|
||||
@file-select=${this.handleFileSelect}
|
||||
></dees-workspace-filetree>
|
||||
</div>
|
||||
${!this.isFileTreeCollapsed ? html`
|
||||
<div class="workspace-outer">
|
||||
<div class="${containerClasses}">
|
||||
<!-- Filetree panel (full height) -->
|
||||
${this.showFileTree ? html`
|
||||
<div
|
||||
class="resize-handle-vertical ${this.isDraggingFileTree ? 'dragging' : ''}"
|
||||
@mousedown=${this.handleFileTreeMouseDown}
|
||||
></div>
|
||||
` : ''}
|
||||
` : ''}
|
||||
|
||||
<!-- Editor + Terminal area -->
|
||||
<div class="editor-area">
|
||||
<div class="editor-panel">
|
||||
<div class="tabs-bar">
|
||||
<div class="tabs-container">
|
||||
${this.openFiles.map(file => html`
|
||||
<div
|
||||
class="tab ${file.path === this.activeFilePath ? 'active' : ''}"
|
||||
@click=${() => this.activateFile(file.path)}
|
||||
>
|
||||
${file.modified ? html`<span class="tab-modified"></span>` : ''}
|
||||
<span class="tab-name">${file.name}</span>
|
||||
<span class="tab-close" @click=${(e: Event) => this.closeFile(e, file.path)}>
|
||||
<dees-icon .icon=${'lucide:x'} iconSize="12"></dees-icon>
|
||||
</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
<div class="editor-menu-button" @click=${this.showEditorMenu} title="Editor options">
|
||||
<dees-icon .icon=${'lucide:moreVertical'} iconSize="16"></dees-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-content">
|
||||
${this.openFiles.length === 0 ? html`
|
||||
<div class="empty-state">
|
||||
<dees-icon .icon=${'lucide:fileCode'} iconSize="48"></dees-icon>
|
||||
<span>Select a file to edit</span>
|
||||
</div>
|
||||
` : html`
|
||||
<dees-workspace-monaco
|
||||
.filePath=${this.activeFilePath}
|
||||
.content=${this.getActiveFileContent()}
|
||||
.language=${this.getLanguageFromPath(this.activeFilePath)}
|
||||
@content-change=${this.handleContentChange}
|
||||
></dees-workspace-monaco>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Horizontal resize handle for terminal -->
|
||||
${this.showTerminal && !this.isTerminalCollapsed ? html`
|
||||
<div
|
||||
class="resize-handle-horizontal ${this.isDraggingTerminal ? 'dragging' : ''}"
|
||||
@mousedown=${this.handleTerminalMouseDown}
|
||||
></div>
|
||||
` : ''}
|
||||
|
||||
<!-- Terminal panel -->
|
||||
${this.showTerminal ? html`
|
||||
<div
|
||||
class="terminal-panel ${this.isTerminalCollapsed ? 'collapsed' : ''}"
|
||||
style="height: ${this.isTerminalCollapsed ? 32 : this.currentTerminalHeight}px"
|
||||
class="filetree-panel ${this.isFileTreeCollapsed ? 'collapsed' : ''}"
|
||||
style="width: ${this.isFileTreeCollapsed ? 0 : this.currentFileTreeWidth}px"
|
||||
>
|
||||
<div class="panel-header">
|
||||
<div class="panel-tabs">
|
||||
<div
|
||||
class="panel-tab ${this.activeBottomPanel === 'terminal' ? 'active' : ''}"
|
||||
@click=${() => this.activeBottomPanel = 'terminal'}
|
||||
>
|
||||
<dees-icon .icon=${'lucide:terminal'} iconSize="14"></dees-icon>
|
||||
Terminal
|
||||
</div>
|
||||
<div
|
||||
class="panel-tab ${this.activeBottomPanel === 'problems' ? 'active' : ''}"
|
||||
@click=${() => this.activeBottomPanel = 'problems'}
|
||||
>
|
||||
<dees-icon .icon=${'lucide:circleAlert'} iconSize="14"></dees-icon>
|
||||
Problems
|
||||
${this.diagnosticMarkers.length > 0 ? html`
|
||||
<span class="panel-tab-badge ${this.getErrorCount() === 0 ? 'warning' : ''}">${this.diagnosticMarkers.length}</span>
|
||||
` : ''}
|
||||
</div>
|
||||
<dees-workspace-filetree
|
||||
.executionEnvironment=${this.executionEnvironment}
|
||||
.selectedPath=${this.activeFilePath}
|
||||
@file-select=${this.handleFileSelect}
|
||||
></dees-workspace-filetree>
|
||||
</div>
|
||||
${!this.isFileTreeCollapsed ? html`
|
||||
<div
|
||||
class="resize-handle-vertical ${this.isDraggingFileTree ? 'dragging' : ''}"
|
||||
@mousedown=${this.handleFileTreeMouseDown}
|
||||
></div>
|
||||
` : ''}
|
||||
` : ''}
|
||||
|
||||
<!-- Editor + Terminal area -->
|
||||
<div class="editor-area">
|
||||
<div class="editor-panel">
|
||||
<div class="tabs-bar">
|
||||
<div class="tabs-container">
|
||||
${this.openFiles.map(file => html`
|
||||
<div
|
||||
class="tab ${file.path === this.activeFilePath ? 'active' : ''}"
|
||||
@click=${() => this.activateFile(file.path)}
|
||||
>
|
||||
${file.modified ? html`<span class="tab-modified"></span>` : ''}
|
||||
<span class="tab-name">${file.name}</span>
|
||||
<span class="tab-close" @click=${(e: Event) => this.closeFile(e, file.path)}>
|
||||
<dees-icon .icon=${'lucide:x'} iconSize="12"></dees-icon>
|
||||
</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
<div class="panel-header-actions">
|
||||
<div class="panel-action" @click=${this.toggleTerminal}>
|
||||
<dees-icon
|
||||
.icon=${this.isTerminalCollapsed ? 'lucide:chevronUp' : 'lucide:chevronDown'}
|
||||
iconSize="14"
|
||||
></dees-icon>
|
||||
</div>
|
||||
<div class="editor-menu-button" @click=${this.showEditorMenu} title="Editor options">
|
||||
<dees-icon .icon=${'lucide:moreVertical'} iconSize="16"></dees-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="terminal-content" style="display: ${this.activeBottomPanel === 'terminal' ? 'block' : 'none'}">
|
||||
<dees-workspace-terminal
|
||||
.executionEnvironment=${this.executionEnvironment}
|
||||
.setupCommand=${''}
|
||||
></dees-workspace-terminal>
|
||||
</div>
|
||||
<div class="problems-content" style="display: ${this.activeBottomPanel === 'problems' ? 'block' : 'none'}">
|
||||
${this.renderProblemsPanel()}
|
||||
<div class="editor-content">
|
||||
${this.openFiles.length === 0 ? html`
|
||||
<div class="empty-state">
|
||||
<dees-icon .icon=${'lucide:fileCode'} iconSize="48"></dees-icon>
|
||||
<span>Select a file to edit</span>
|
||||
</div>
|
||||
` : html`
|
||||
<dees-workspace-monaco
|
||||
.filePath=${this.activeFilePath}
|
||||
.content=${this.getActiveFileContent()}
|
||||
.language=${this.getLanguageFromPath(this.activeFilePath)}
|
||||
@content-change=${this.handleContentChange}
|
||||
></dees-workspace-monaco>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<!-- Horizontal resize handle for terminal -->
|
||||
${this.showTerminal && !this.isTerminalCollapsed ? html`
|
||||
<div
|
||||
class="resize-handle-horizontal ${this.isDraggingTerminal ? 'dragging' : ''}"
|
||||
@mousedown=${this.handleTerminalMouseDown}
|
||||
></div>
|
||||
` : ''}
|
||||
|
||||
<!-- Terminal panel -->
|
||||
${this.showTerminal ? html`
|
||||
<div
|
||||
class="terminal-panel ${this.isTerminalCollapsed ? 'collapsed' : ''}"
|
||||
style="height: ${this.isTerminalCollapsed ? 32 : this.currentTerminalHeight}px"
|
||||
>
|
||||
<div class="panel-header">
|
||||
<div class="panel-tabs">
|
||||
<div
|
||||
class="panel-tab ${this.activeBottomPanel === 'terminal' ? 'active' : ''}"
|
||||
@click=${() => this.activeBottomPanel = 'terminal'}
|
||||
>
|
||||
<dees-icon .icon=${'lucide:terminal'} iconSize="14"></dees-icon>
|
||||
Terminal
|
||||
</div>
|
||||
<div
|
||||
class="panel-tab ${this.activeBottomPanel === 'problems' ? 'active' : ''}"
|
||||
@click=${() => this.activeBottomPanel = 'problems'}
|
||||
>
|
||||
<dees-icon .icon=${'lucide:circleAlert'} iconSize="14"></dees-icon>
|
||||
Problems
|
||||
${this.diagnosticMarkers.length > 0 ? html`
|
||||
<span class="panel-tab-badge ${this.getErrorCount() === 0 ? 'warning' : ''}">${this.diagnosticMarkers.length}</span>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-header-actions">
|
||||
<div class="panel-action" @click=${this.toggleTerminal}>
|
||||
<dees-icon
|
||||
.icon=${this.isTerminalCollapsed ? 'lucide:chevronUp' : 'lucide:chevronDown'}
|
||||
iconSize="14"
|
||||
></dees-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="terminal-content" style="display: ${this.activeBottomPanel === 'terminal' ? 'block' : 'none'}">
|
||||
<dees-workspace-terminal
|
||||
.executionEnvironment=${this.executionEnvironment}
|
||||
.setupCommand=${''}
|
||||
></dees-workspace-terminal>
|
||||
</div>
|
||||
<div class="problems-content" style="display: ${this.activeBottomPanel === 'problems' ? 'block' : 'none'}">
|
||||
${this.renderProblemsPanel()}
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Bar (full width) -->
|
||||
<dees-workspace-bottombar
|
||||
.executionEnvironment=${this.executionEnvironment}
|
||||
@run-process=${this.handleRunProcess}
|
||||
></dees-workspace-bottombar>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -1484,6 +1503,44 @@ testSmartPromise();
|
||||
}));
|
||||
}
|
||||
|
||||
// ========== Bottom Bar Event Handlers ==========
|
||||
|
||||
/**
|
||||
* Handle run-process events from bottom bar widgets
|
||||
* Creates a new terminal tab for the process
|
||||
*/
|
||||
private async handleRunProcess(e: CustomEvent<IRunProcessEventDetail>): Promise<void> {
|
||||
const detail = e.detail;
|
||||
|
||||
// Find the terminal component
|
||||
const terminal = this.shadowRoot?.querySelector('dees-workspace-terminal') as DeesWorkspaceTerminal;
|
||||
if (!terminal) {
|
||||
console.warn('Terminal component not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand terminal if collapsed
|
||||
if (this.isTerminalCollapsed) {
|
||||
this.isTerminalCollapsed = false;
|
||||
}
|
||||
|
||||
// Switch to terminal panel
|
||||
this.activeBottomPanel = 'terminal';
|
||||
|
||||
// Wait for UI update
|
||||
await this.updateComplete;
|
||||
|
||||
// Create a new terminal tab for the process
|
||||
await terminal.createProcessTab({
|
||||
type: detail.type,
|
||||
label: detail.label,
|
||||
command: detail.command,
|
||||
args: detail.args,
|
||||
metadata: detail.metadata,
|
||||
switchToTab: true,
|
||||
});
|
||||
}
|
||||
|
||||
// ========== Public Layout Methods ==========
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user