feat: 更新工作区选项卡逻辑,支持切换和状态管理
This commit is contained in:
1 parent
8cb4d88b39
commit
b8b2f63073
3 files changed
+30
-15
No files matched your search
+3
-2
@@ -293,8 +293,9 @@
|
||||
class="dock-tab"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="true"
|
||||
aria-selected="false"
|
||||
aria-controls="file-manager-panel"
|
||||
aria-expanded="false"
|
||||
tabindex="0"
|
||||
data-i18n-zh="文件管理"
|
||||
data-i18n-en="Files"
|
||||
@@ -314,7 +315,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="file-manager-panel" class="file-manager" role="tabpanel" aria-labelledby="file-manager-tab" tabindex="0">
|
||||
<section id="file-manager-panel" class="file-manager" role="tabpanel" aria-labelledby="file-manager-tab" tabindex="0" hidden>
|
||||
<div class="file-toolbar">
|
||||
<label class="file-path-field" for="file-manager-path">
|
||||
<span class="sr-only" data-i18n-zh="当前路径" data-i18n-en="Current path">当前路径</span>
|
||||
|
||||
+21
-12
@@ -1211,21 +1211,30 @@ function sendHostKeyDecision(accept: boolean): void {
|
||||
}
|
||||
|
||||
type WorkspaceTab = 'files' | 'log';
|
||||
let activeWorkspaceTab: WorkspaceTab | null = null;
|
||||
|
||||
function setWorkspaceTab(tab: WorkspaceTab, focus = false): void {
|
||||
function setWorkspaceTab(tab: WorkspaceTab | null, focus = false, rovingTab = tab ?? activeWorkspaceTab ?? 'files'): void {
|
||||
const filesActive = tab === 'files';
|
||||
const logActive = tab === 'log';
|
||||
activeWorkspaceTab = tab;
|
||||
ui.terminalCard.classList.toggle('workspace-panel-open', tab !== null);
|
||||
ui.fileManagerPanel.hidden = !filesActive;
|
||||
ui.eventLog.hidden = filesActive;
|
||||
ui.eventLog.hidden = !logActive;
|
||||
ui.fileManagerTab.setAttribute('aria-selected', String(filesActive));
|
||||
ui.eventToggle.setAttribute('aria-selected', String(!filesActive));
|
||||
ui.eventToggle.setAttribute('aria-expanded', String(!filesActive));
|
||||
ui.fileManagerTab.tabIndex = filesActive ? 0 : -1;
|
||||
ui.eventToggle.tabIndex = filesActive ? -1 : 0;
|
||||
if (!filesActive) requestAnimationFrame(() => { ui.eventLog.scrollTop = ui.eventLog.scrollHeight; });
|
||||
if (focus) (filesActive ? ui.fileManagerTab : ui.eventToggle).focus();
|
||||
ui.eventToggle.setAttribute('aria-selected', String(logActive));
|
||||
ui.fileManagerTab.setAttribute('aria-expanded', String(filesActive));
|
||||
ui.eventToggle.setAttribute('aria-expanded', String(logActive));
|
||||
ui.fileManagerTab.tabIndex = rovingTab === 'files' ? 0 : -1;
|
||||
ui.eventToggle.tabIndex = rovingTab === 'log' ? 0 : -1;
|
||||
if (logActive) requestAnimationFrame(() => { ui.eventLog.scrollTop = ui.eventLog.scrollHeight; });
|
||||
if (focus) (rovingTab === 'files' ? ui.fileManagerTab : ui.eventToggle).focus();
|
||||
requestAnimationFrame(() => fitTerminal(true));
|
||||
}
|
||||
|
||||
function toggleWorkspaceTab(tab: WorkspaceTab): void {
|
||||
setWorkspaceTab(activeWorkspaceTab === tab ? null : tab, false, tab);
|
||||
}
|
||||
|
||||
function handleWorkspaceTabKey(event: KeyboardEvent): void {
|
||||
if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return;
|
||||
event.preventDefault();
|
||||
@@ -1847,8 +1856,8 @@ ui.fullscreenTerminal.addEventListener('click', async () => {
|
||||
else await ui.terminalCard.requestFullscreen();
|
||||
});
|
||||
document.addEventListener('fullscreenchange', () => fitTerminal(true));
|
||||
ui.fileManagerTab.addEventListener('click', () => setWorkspaceTab('files'));
|
||||
ui.eventToggle.addEventListener('click', () => setWorkspaceTab('log'));
|
||||
ui.fileManagerTab.addEventListener('click', () => toggleWorkspaceTab('files'));
|
||||
ui.eventToggle.addEventListener('click', () => toggleWorkspaceTab('log'));
|
||||
ui.fileManagerTab.addEventListener('keydown', handleWorkspaceTabKey);
|
||||
ui.eventToggle.addEventListener('keydown', handleWorkspaceTabKey);
|
||||
ui.languageToggle.addEventListener('click', () => {
|
||||
@@ -1895,7 +1904,7 @@ async function initialize(): Promise<void> {
|
||||
setPanelOpen(panelOpen);
|
||||
setAuthMethod('password');
|
||||
setState('idle');
|
||||
setWorkspaceTab('files');
|
||||
setWorkspaceTab(null);
|
||||
ui.sessionTitle.textContent = bilingual('无活动会话', 'No active session');
|
||||
ui.sessionSubtitle.textContent = bilingual('选择目标并连接', 'Choose a target and connect');
|
||||
ui.eventMessage.textContent = bilingual('Worker 运行时待命', 'Worker runtime standing by');
|
||||
@@ -1916,6 +1925,6 @@ void initialize().catch(() => {
|
||||
setPanelOpen(panelOpen);
|
||||
setAuthMethod('password');
|
||||
setState('idle');
|
||||
setWorkspaceTab('files');
|
||||
setWorkspaceTab(null);
|
||||
initializeCompatibilityAPI();
|
||||
});
|
||||
@@ -953,12 +953,17 @@ button:disabled {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
grid-template-rows: minmax(0, 2fr) minmax(0, 1fr);
|
||||
grid-template-rows: minmax(0, 1fr) minmax(34px, 0fr);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: var(--terminal);
|
||||
box-shadow: var(--shadow);
|
||||
transition: grid-template-rows 220ms cubic-bezier(0.2, 0.75, 0.2, 1);
|
||||
}
|
||||
|
||||
.terminal-card.workspace-panel-open {
|
||||
grid-template-rows: minmax(0, 2fr) minmax(34px, 1fr);
|
||||
}
|
||||
|
||||
.terminal-pane {
|
||||
|
||||
Reference in new issue
Block a user