From 9344e4f3ef5d7be36815f37d67e475eddf30c970 Mon Sep 17 00:00:00 2001 From: Levi <9320732+posinega@user.noreply.gitee.com> Date: Mon, 23 Mar 2026 16:54:09 +0800 Subject: [PATCH] feat: enhance TerminalLayout with preview actions and overflow handling --- .../src/views/layouts/TerminalLayout.vue | 22 +++++++++++++ .../layouts/__tests__/TerminalLayout.test.ts | 32 +++++++++++++++++++ .../layouts/components/EditorActions.vue | 6 ++++ 3 files changed, 60 insertions(+) diff --git a/src/renderer/src/views/layouts/TerminalLayout.vue b/src/renderer/src/views/layouts/TerminalLayout.vue index 62b37b6a8..2927f2514 100644 --- a/src/renderer/src/views/layouts/TerminalLayout.vue +++ b/src/renderer/src/views/layouts/TerminalLayout.vue @@ -204,6 +204,7 @@ >
@@ -218,6 +219,7 @@ v-if="configLoaded" ref="dockviewRef" :class="currentTheme === 'light' ? 'dockview-theme-light' : 'dockview-theme-dark'" + :disable-tabs-overflow-list="true" :style="{ width: '100%', height: '100%', @@ -2251,6 +2253,14 @@ const panelCount = ref(0) const hasPanels = computed(() => panelCount.value > 0) let dockApi: DockviewApi | null = null const dockApiInstance = ref(null) +const isPreviewActionsVisible = ref(false) + +const computePreviewActionsVisible = (): boolean => { + const panel = dockApi?.activePanel + if (!panel) return false + // Keep in sync with `EditorActions.vue` showActions logic. + return panel.params?.content === 'KnowledgeCenterEditor' && panel.params?.mode !== 'preview' && panel.params?.isMarkdown +} const isFocusInTerminal = (event: KeyboardEvent): boolean => { const target = event.target as HTMLElement | null @@ -2377,6 +2387,7 @@ const handleActivePanelChange = async () => { const onDockReady = (event: DockviewReadyEvent) => { dockApi = event.api dockApiInstance.value = event.api + isPreviewActionsVisible.value = computePreviewActionsVisible() dockApi.onDidAddPanel(() => { panelCount.value = dockApi?.panels.length ?? 0 @@ -2392,6 +2403,7 @@ const onDockReady = (event: DockviewReadyEvent) => { }) dockApi.onDidActivePanelChange(() => { + isPreviewActionsVisible.value = computePreviewActionsVisible() handleActivePanelChange() }) @@ -2958,6 +2970,16 @@ defineExpose({ right: 0; z-index: 10; } + + // Reserve space for the preview actions overlay so it never covers + // Dockview header tabs when they overflow/clamp. + &.has-preview-actions { + .dockview-theme-light .dv-tabs-and-actions-container, + .dockview-theme-dark .dv-tabs-and-actions-container { + padding-right: 30px; + box-sizing: border-box; + } + } } .ant-input-group-wrapper { diff --git a/src/renderer/src/views/layouts/__tests__/TerminalLayout.test.ts b/src/renderer/src/views/layouts/__tests__/TerminalLayout.test.ts index f3a6c8505..76de03ba7 100644 --- a/src/renderer/src/views/layouts/__tests__/TerminalLayout.test.ts +++ b/src/renderer/src/views/layouts/__tests__/TerminalLayout.test.ts @@ -8,6 +8,8 @@ */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' import { ref } from 'vue' // Mocks (required by AI Sidebar tests) @@ -439,6 +441,36 @@ describe('TerminalLayout - Close Tab Keyboard Shortcut', () => { }) }) +describe('TerminalLayout - Dockview Tabs Overflow', () => { + it('should disable tabs overflow dropdown list', () => { + const sourcePath = join(process.cwd(), 'src/renderer/src/views/layouts/TerminalLayout.vue') + const source = readFileSync(sourcePath, 'utf8') + expect(source).toContain('disable-tabs-overflow-list') + }) +}) + +describe('TerminalLayout - Preview Actions Layout', () => { + it('should reserve right padding for preview actions overlay', () => { + const sourcePath = join(process.cwd(), 'src/renderer/src/views/layouts/TerminalLayout.vue') + const source = readFileSync(sourcePath, 'utf8') + expect(source).toContain('padding-right: 30px') + }) + + it('should set fixed width for preview actions button container', () => { + const sourcePath = join(process.cwd(), 'src/renderer/src/views/layouts/components/EditorActions.vue') + const source = readFileSync(sourcePath, 'utf8') + expect(source).toContain('width: 30px') + expect(source).toContain('min-width: 30px') + }) + + it('should only apply padding when preview actions are visible', () => { + const sourcePath = join(process.cwd(), 'src/renderer/src/views/layouts/TerminalLayout.vue') + const source = readFileSync(sourcePath, 'utf8') + expect(source).toContain('has-preview-actions') + expect(source).toContain('computePreviewActionsVisible') + }) +}) + // ========== Tab Context Menu ========== describe('TerminalLayout - Tab Context Menu', () => { let mockDockApi: any diff --git a/src/renderer/src/views/layouts/components/EditorActions.vue b/src/renderer/src/views/layouts/components/EditorActions.vue index c2efd0770..9b18e6eb3 100644 --- a/src/renderer/src/views/layouts/components/EditorActions.vue +++ b/src/renderer/src/views/layouts/components/EditorActions.vue @@ -90,6 +90,11 @@ const openPreview = () => { display: flex; align-items: center; padding: 0 8px; + width: 30px; + min-width: 30px; + flex: 0 0 30px; + flex-shrink: 0; + box-sizing: border-box; height: 35px; /* Match tab height */ background: var(--bg-color-secondary); border-bottom: 1px solid var(--border-color); @@ -102,6 +107,7 @@ const openPreview = () => { justify-content: center; width: 24px; height: 24px; + flex-shrink: 0; cursor: pointer; border-radius: 4px; color: var(--text-color-secondary);