Skip to content

Commit 7bf8059

Browse files
committed
fix(ui): 修复全屏对话框内容溢出问题
采用多层滚动容器设计解决全屏显示时超长内容溢出父容器边界的问题: **核心改进:** - 使用 Naive UI 的 NFlex 组件替代原生 div/NSpace,实现更规范的 flexbox 布局 - 建立正确的高度约束链:每层容器都设置 min-height: 0 和 overflow 控制 - 实现分层滚动策略:内层主滚动 + 外层兜底滚动 **滚动容器设计:** 1. 渲染/对比模式:MarkdownRenderer/TextDiffUI 自身提供滚动(overflow: auto) 2. 原文编辑模式:NInput textarea 会撑开容器,由 FullscreenDialog 提供兜底滚动 3. 外层约束容器:OutputDisplayFullscreen/Core 使用 overflow: hidden 防止意外滚动 **修改文件:** - FullscreenDialog.vue: 使用 NFlex + overflow: auto 提供兜底滚动 - OutputDisplayFullscreen.vue: 使用 NFlex 包裹,修复 content 绑定为 internalContent - OutputDisplayCore.vue: 主内容区从 NSpace 改为 NFlex,优化布局约束 - MarkdownRenderer.vue: 优化 NScrollbar 实现,移除冗余的高度和滚动样式
1 parent c1bf0f2 commit 7bf8059

File tree

4 files changed

+47
-43
lines changed

4 files changed

+47
-43
lines changed

packages/ui/src/components/FullscreenDialog.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<NModal
2+
<NModal
33
v-model:show="localVisible"
44
preset="card"
55
:title="title"
@@ -10,15 +10,15 @@
1010
transform-origin="center"
1111
content-style="height: 100%; display: flex; flex-direction: column; min-height: 0;"
1212
>
13-
<div class="fullscreen-content">
13+
<NFlex vertical style="height: 100%; min-height: 0; overflow: auto;">
1414
<slot></slot>
15-
</div>
15+
</NFlex>
1616
</NModal>
1717
</template>
1818

1919
<script setup lang="ts">
2020
import { computed } from 'vue'
21-
import { NModal } from 'naive-ui'
21+
import { NModal, NFlex } from 'naive-ui'
2222
2323
const props = defineProps({
2424
modelValue: {
@@ -41,4 +41,4 @@ const localVisible = computed({
4141
</script>
4242
<style scoped>
4343
/* Pure Naive UI implementation - no custom theme CSS needed */
44-
</style>
44+
</style>

packages/ui/src/components/MarkdownRenderer.vue

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
2-
<NScrollbar v-if="!disableInternalScroll" :style="{ height: '100%' }" :bordered="false" content-style="padding: 0; height: 100%; display: flex; flex-direction: column;">
3-
<div ref="markdownContainer" class="markdown-content" :style="{ height: '100%',maxHeight: '100%' }">
2+
<NScrollbar v-if="!disableInternalScroll" style="height: 100%; max-height: 100%;" :bordered="false">
3+
<div ref="markdownContainer" class="markdown-content markdown-content--scrollable">
44
</div>
55
</NScrollbar>
6-
<div v-else ref="markdownContainer" class="markdown-content" :style="{ height: '100%',maxHeight: '100%' }">
6+
<div v-else ref="markdownContainer" class="markdown-content" style="height: 100%; max-height: 100%; overflow-y: auto;">
77
</div>
88
</template>
99

@@ -287,10 +287,11 @@ onMounted(renderMarkdown);
287287
overflow-wrap: break-word;
288288
hyphens: auto;
289289
/* Pure Naive UI theme - remove custom CSS variables */
290-
/* 填满容器并处理滚动 */
291-
height: 100%;
292-
overflow-y: auto;
293290
padding: 0.75rem; /* 提供合适的内边距,与其他组件保持一致 */
291+
}
292+
293+
/* 当使用 NScrollbar 时,不需要自己的滚动条 */
294+
.markdown-content--scrollable {
294295
/* 隐藏滚动条但保持可滚动 */
295296
scrollbar-width: none; /* Firefox */
296297
-ms-overflow-style: none; /* IE and Edge */

packages/ui/src/components/OutputDisplayCore.vue

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<template>
2-
<NCard
2+
<NCard
33
:bordered="false"
44
class="output-display-core h-full max-height: 100% "
5-
content-style="padding: 0; height: 100%; max-height: 100%;"
5+
content-style="padding: 0; height: 100%; max-height: 100%; display: flex; flex-direction: column; overflow: hidden;"
66
>
7-
<NFlex vertical style="height: 100%;">
7+
<NFlex vertical style="height: 100%; min-height: 0; overflow: hidden;">
88
<!-- 统一顶层工具栏 -->
9-
<NFlex v-if="hasToolbar" justify="space-between" align="center">
9+
<NFlex v-if="hasToolbar" justify="space-between" align="center" style="flex: 0 0 auto;">
1010
<!-- 左侧:视图控制按钮组 -->
1111
<NButtonGroup>
1212
<NButton
@@ -103,14 +103,14 @@
103103
</NCollapse>
104104
</NFlex>
105105
<!-- 主要内容区域 -->
106-
<NFlex vertical style="flex: 1; min-height: 0; max-height: 100%;">
106+
<NFlex vertical style="flex: 1; min-height: 0; max-height: 100%; overflow: hidden;">
107107
<!-- 对比模式 -->
108-
<TextDiffUI v-if="internalViewMode === 'diff' && content && originalContent"
108+
<TextDiffUI v-if="internalViewMode === 'diff' && content && originalContent"
109109
:originalText="originalContent"
110110
:optimizedText="content"
111111
:compareResult="compareResult"
112112
class="w-full"
113-
style="height: 100%;"
113+
style="height: 100%; min-height: 0; overflow: auto;"
114114
/>
115115

116116
<!-- 原文模式 -->
@@ -121,21 +121,21 @@
121121
type="textarea"
122122
:placeholder="placeholder"
123123
:autosize="{ minRows: 10 }"
124-
style="height: 100%;"
124+
style="height: 100%; min-height: 0;"
125125
/>
126126

127127
<!-- 渲染模式(默认) -->
128-
<NSpace v-else
129-
style="height: 100%;max-height: 100%;"
130-
item-style="height: 100%;max-height: 100%;"
131-
:align="displayContent ? 'start' : 'center'"
132-
:justify="displayContent ? 'start' : 'center'"
128+
<NFlex v-else
129+
vertical
130+
:align="displayContent ? 'stretch' : 'center'"
131+
:justify="displayContent ? 'start' : 'center'"
132+
style="flex: 1; min-height: 0; overflow: hidden;"
133133
>
134134
<MarkdownRenderer
135135
v-if="displayContent"
136136
:content="displayContent"
137137
:streaming="streaming"
138-
style="height: 100%;max-height: 100%;"
138+
style="flex: 1; min-height: 0; overflow: auto;"
139139
/>
140140
<NEmpty
141141
v-else-if="!loading && !streaming"
@@ -144,7 +144,7 @@
144144
style="height: 100%;"
145145
/>
146146
<NText v-else class="ml-2">{{ placeholder || t('common.loading') }}</NText>
147-
</NSpace>
147+
</NFlex>
148148
</NFlex>
149149

150150
</NFlex>

packages/ui/src/components/OutputDisplayFullscreen.vue

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
11
<template>
22
<FullscreenDialog v-model="internalVisible" :title="title || t('common.content')">
3-
<OutputDisplayCore
4-
ref="coreDisplayRef"
5-
:content="content"
6-
:originalContent="originalContent"
7-
:reasoning="reasoning"
8-
:mode="mode"
9-
:reasoningMode="reasoningMode"
10-
:enabledActions="coreEnabledActions"
11-
height="100%"
12-
:placeholder="placeholder"
13-
:loading="loading"
14-
:streaming="streaming"
15-
:compareService="compareService"
16-
@update:content="handleContentUpdate"
17-
@copy="handleCopy"
18-
/>
3+
<NFlex vertical style="flex: 1; min-height: 0; overflow: hidden;">
4+
<OutputDisplayCore
5+
ref="coreDisplayRef"
6+
:content="internalContent"
7+
:originalContent="originalContent"
8+
:reasoning="reasoning"
9+
:mode="mode"
10+
:reasoningMode="reasoningMode"
11+
:enabledActions="coreEnabledActions"
12+
height="100%"
13+
:placeholder="placeholder"
14+
:loading="loading"
15+
:streaming="streaming"
16+
:compareService="compareService"
17+
@update:content="handleContentUpdate"
18+
@copy="handleCopy"
19+
/>
20+
</NFlex>
1921
</FullscreenDialog>
2022
</template>
2123

2224
<script setup lang="ts">
2325
import { computed, ref, watch, inject, nextTick, type Ref } from 'vue'
2426
import { useI18n } from 'vue-i18n'
27+
import { NFlex } from 'naive-ui'
2528
import FullscreenDialog from './FullscreenDialog.vue'
2629
import OutputDisplayCore from './OutputDisplayCore.vue'
2730
import type { AppServices } from '../types/services';
@@ -129,4 +132,4 @@ const handleCopy = (content: string, type: 'content' | 'reasoning' | 'all') => {
129132
emit('copy', content, type)
130133
}
131134
132-
</script>
135+
</script>

0 commit comments

Comments
 (0)