Phase 006: migrate the chat page from naive-ui to Arco Design Vue
Swaps the rendering layer only. Chat store logic, keyboard handling, and the /chat-run Socket.IO contract are untouched, so a mixed UI cannot hide a chat regression behind a library swap. Arco's dropdowns take their items from a #content slot of a-doption children rather than a droplist prop, and Arco Triggers cannot be nested, so the two toolbar menus lost their a-tooltip in favour of a native title. Both rules are recorded in docs/arco-mapping.md, and tests/e2e/chat-input-dropdown.spec.ts plus tests/e2e/chat-rendering-smoke.spec.ts keep the menus, the streaming markdown rendering, and the no-Arco-inside-the-bubble red line from regressing silently.
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { NDrawer, NDrawerContent, NSpin } from 'naive-ui'
|
||||
import { useMessage } from '@/composables/useMessage'
|
||||
import type MarkdownIt from 'markdown-it'
|
||||
import MarkdownItConstructor from 'markdown-it'
|
||||
@@ -488,37 +487,29 @@ async function previewTextFile(path: string, fileName: string): Promise<void> {
|
||||
textPreviewLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function closeTextPreview(): void {
|
||||
textPreviewVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="markdownBody" class="markdown-body" v-html="renderedHtml" @click="handleMarkdownClick"></div>
|
||||
<!-- File preview area -->
|
||||
<NDrawer
|
||||
v-model:show="textPreviewVisible"
|
||||
<!-- File preview area. Lazily mounted: keeps any Arco component out of the
|
||||
message bubble render tree while streaming (Phase 006 §1 perf red line). -->
|
||||
<a-drawer
|
||||
v-if="textPreviewVisible"
|
||||
v-model:visible="textPreviewVisible"
|
||||
:width="PREVIEW_AREA_WIDTH"
|
||||
placement="right"
|
||||
:show-mask="false"
|
||||
:trap-focus="false"
|
||||
:mask="false"
|
||||
unmount-on-close
|
||||
class="markdown-text-preview-drawer"
|
||||
>
|
||||
<NDrawerContent
|
||||
:title="t('download.contentDisplay')"
|
||||
closable
|
||||
:body-content-style="{ padding: 0 }"
|
||||
@close="closeTextPreview"
|
||||
>
|
||||
<NSpin :show="textPreviewLoading">
|
||||
<div v-if="textPreviewContent !== null && textPreviewIsMarkdown" class="text-preview-markdown">
|
||||
<MarkdownRenderer :content="textPreviewContent" />
|
||||
</div>
|
||||
<pre v-else-if="textPreviewContent !== null" class="text-preview-body">{{ textPreviewContent }}</pre>
|
||||
</NSpin>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
<template #title>{{ t('download.contentDisplay') }}</template>
|
||||
<a-spin :loading="textPreviewLoading" class="text-preview-spin">
|
||||
<div v-if="textPreviewContent !== null && textPreviewIsMarkdown" class="text-preview-markdown">
|
||||
<MarkdownRenderer :content="textPreviewContent" />
|
||||
</div>
|
||||
<pre v-else-if="textPreviewContent !== null" class="text-preview-body">{{ textPreviewContent }}</pre>
|
||||
</a-spin>
|
||||
</a-drawer>
|
||||
<Teleport to="body">
|
||||
<div v-if="previewUrl" class="image-preview-overlay" @click.self="previewUrl = null">
|
||||
<img :src="previewUrl" class="image-preview-img" @click="previewUrl = null" />
|
||||
@@ -827,18 +818,24 @@ function closeTextPreview(): void {
|
||||
.markdown-text-preview-drawer {
|
||||
max-width: 100vw;
|
||||
|
||||
.n-drawer-content,
|
||||
.n-drawer-body-content-wrapper {
|
||||
.arco-drawer {
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.text-preview-spin {
|
||||
display: block;
|
||||
|
||||
:deep(.arco-spin-children) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-mobile) {
|
||||
.markdown-text-preview-drawer {
|
||||
max-width: 100vw;
|
||||
|
||||
.n-drawer-content,
|
||||
.n-drawer-body-content-wrapper {
|
||||
.arco-drawer {
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user