feat: 统一管理端弹窗与内容区交互样式

- 收敛管理端公共 Modal 链路,新增表单弹窗与普通内容弹窗包装\n- 迁移 Bot、知识库、插件、工作流、资源、MCP、数据中枢与系统管理页面级弹窗\n- 统一内容区工具栏、列表容器、导航与顶部按钮的视觉密度和交互节奏
This commit is contained in:
2026-03-06 19:58:26 +08:00
parent 76c2954a70
commit b191d1aaed
99 changed files with 3148 additions and 1623 deletions

View File

@@ -184,7 +184,7 @@ const getForceMount = computed(() => {
<SheetContent
:append-to="getAppendTo"
:class="
cn('flex w-[520px] flex-col', drawerClass, {
cn('flex w-[520px] flex-col overflow-hidden border border-[hsl(var(--glass-border))/0.18] bg-[hsl(var(--glass-tint))/0.84] shadow-[var(--shadow-float)] supports-[backdrop-filter]:bg-[hsl(var(--glass-tint))/0.62]', drawerClass, {
'!w-full': isMobile || placement === 'bottom' || placement === 'top',
'max-h-[100vh]': placement === 'bottom' || placement === 'top',
hidden: isClosed,
@@ -209,7 +209,7 @@ const getForceMount = computed(() => {
v-if="showHeader"
:class="
cn(
'!flex flex-row items-center justify-between border-b px-6 py-5',
'!flex flex-row items-center justify-between border-b border-[hsl(var(--divider-faint))/0.32] px-6 py-5',
headerClass,
{
'px-4 py-3': closable,
@@ -223,7 +223,7 @@ const getForceMount = computed(() => {
v-if="closable && closeIconPlacement === 'left'"
as-child
:disabled="submitting"
class="data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
class="data-[state=open]:bg-[hsl(var(--surface-contrast-soft))/0.92] ml-[2px] cursor-pointer rounded-full opacity-84 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
>
<slot name="close-icon">
<EasyFlowIconButton>
@@ -264,7 +264,7 @@ const getForceMount = computed(() => {
v-if="closable && closeIconPlacement === 'right'"
as-child
:disabled="submitting"
class="data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
class="data-[state=open]:bg-[hsl(var(--surface-contrast-soft))/0.92] ml-[2px] cursor-pointer rounded-full opacity-84 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
>
<slot name="close-icon">
<EasyFlowIconButton>
@@ -295,7 +295,7 @@ const getForceMount = computed(() => {
v-if="showFooter"
:class="
cn(
'w-full flex-row items-center justify-end border-t p-2 px-3',
'w-full flex-row items-center justify-end border-t border-[hsl(var(--divider-faint))/0.32] p-2 px-3',
footerClass,
)
"

View File

@@ -59,7 +59,7 @@ export class ModalApi {
showCancelButton: true,
showConfirmButton: true,
title: '',
animationType: 'slide',
animationType: 'scale',
};
this.store = new Store<ModalState>(

View File

@@ -7,7 +7,7 @@ import type { ModalApi } from './modal-api';
export interface ModalProps {
/**
* 动画类型
* @default 'slide'
* @default 'scale'
*/
animationType?: 'scale' | 'slide';
/**

View File

@@ -231,12 +231,13 @@ function handleClosed() {
:append-to="getAppendTo"
:class="
cn(
'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col p-0',
shouldFullscreen ? 'sm:rounded-none' : 'sm:rounded-[var(--radius)]',
'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col overflow-hidden border border-[hsl(var(--modal-shell-border-soft))] bg-[hsl(var(--modal-surface))] p-0',
shouldFullscreen
? 'sm:rounded-none'
: 'sm:rounded-[var(--radius-modal)]',
modalClass,
{
'border-border border': bordered,
'shadow-3xl': !bordered,
'border-[hsl(var(--modal-shell-border-soft))]': bordered,
'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':
shouldFullscreen,
'top-1/2 !-translate-y-1/2': centered && !shouldFullscreen,
@@ -248,6 +249,16 @@ function handleClosed() {
:force-mount="getForceMount"
:modal="modal"
:open="state?.isOpen"
:overlay-style="{
backgroundColor:
'hsl(var(--modal-overlay) / var(--modal-overlay-opacity))',
}"
:content-style="{
backdropFilter: 'none',
WebkitBackdropFilter: 'none',
backgroundColor: 'hsl(var(--modal-surface))',
boxShadow: 'var(--modal-shadow)',
}"
:show-close="closable"
:animation-type="animationType"
:z-index="zIndex"
@@ -267,9 +278,8 @@ function handleClosed() {
ref="headerRef"
:class="
cn(
'px-5 py-4',
'px-5 py-4 sm:px-6 sm:py-5',
{
'border-b': bordered,
hidden: !header,
'cursor-move select-none': shouldDraggable,
},
@@ -301,9 +311,13 @@ function handleClosed() {
<div
ref="wrapperRef"
:class="
cn('relative min-h-40 flex-1 overflow-y-auto p-3', contentClass, {
'pointer-events-none': showLoading || submitting,
})
cn(
'relative min-h-0 flex-1 overflow-y-auto bg-[hsl(var(--modal-content-surface))] px-5 pb-5 pt-4 sm:px-6 sm:pb-6',
contentClass,
{
'pointer-events-none': showLoading || submitting,
},
)
"
>
<slot></slot>
@@ -311,7 +325,7 @@ function handleClosed() {
<EasyFlowLoading v-if="showLoading || submitting" spinning />
<EasyFlowIconButton
v-if="fullscreenButton"
class="hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-3 hidden size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block"
class="text-foreground/80 flex-center opacity-78 absolute right-11 top-4 hidden size-8 rounded-full bg-[hsl(var(--modal-preview-surface-strong))/0.76] px-1 text-lg shadow-[0_16px_28px_-24px_hsl(var(--foreground)/0.4)] transition-all hover:-translate-y-0.5 hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block"
@click="handleFullscreen"
>
<Shrink v-if="fullscreen" class="size-3.5" />
@@ -323,9 +337,9 @@ function handleClosed() {
ref="footerRef"
:class="
cn(
'flex-row items-center justify-end p-2',
'flex-row items-center justify-end gap-3 bg-[hsl(var(--modal-footer-surface))] px-5 py-4 sm:px-6',
{
'border-t': bordered,
'border-t border-[hsl(var(--modal-divider))]': bordered,
},
footerClass,
)