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

@@ -70,6 +70,15 @@ function handleClick() {
emit('click', item);
}
function handleKeydown(event: KeyboardEvent) {
if (event.key !== 'Enter' && event.key !== ' ') {
return;
}
event.preventDefault();
handleClick();
}
onMounted(() => {
subMenu?.addSubMenu?.(item);
rootMenu?.addMenuItem?.(item);
@@ -90,7 +99,9 @@ onBeforeUnmount(() => {
is('collapse-show-title', collapseShowTitle),
]"
role="menuitem"
:tabindex="disabled ? -1 : 0"
@click.stop="handleClick"
@keydown="handleKeydown"
>
<EasyFlowTooltip
v-if="showTooltip"

View File

@@ -377,12 +377,13 @@ $namespace: easyflow;
text-decoration: none;
cursor: pointer;
background: var(--menu-item-active-background-color);
box-shadow: var(--menu-item-shadow);
}
@mixin menu-item {
position: relative;
display: flex;
// gap: 12px;
gap: 10px;
align-items: center;
height: var(--menu-item-height);
padding: var(--menu-item-padding-y) var(--menu-item-padding-x);
@@ -401,7 +402,13 @@ $namespace: easyflow;
background 0.15s ease,
color 0.15s ease,
padding 0.15s ease,
border-color 0.15s ease;
border-color 0.15s ease,
box-shadow 0.15s ease,
transform 0.15s ease;
&::before {
display: none;
}
&.is-disabled {
cursor: not-allowed;
@@ -425,6 +432,12 @@ $namespace: easyflow;
outline: none;
}
&:focus-visible {
box-shadow:
0 0 0 1px hsl(var(--glass-border) / 0.72),
0 0 0 4px hsl(var(--ring) / 0.16);
}
* {
vertical-align: bottom;
}
@@ -445,68 +458,106 @@ $namespace: easyflow;
.#{$namespace}-menu__popup-container,
.#{$namespace}-menu {
--menu-title-width: 140px;
--menu-item-icon-size: 16px;
--menu-item-height: 38px;
--menu-item-padding-y: 21px;
--menu-item-padding-x: 12px;
--menu-item-popup-padding-y: 20px;
--menu-item-popup-padding-x: 12px;
--menu-item-margin-y: 2px;
--menu-item-margin-x: 0px;
--menu-item-collapse-padding-y: 23.5px;
--menu-item-icon-size: 18px;
--menu-item-height: 40px;
--menu-item-padding-y: 0px;
--menu-item-padding-x: 14px;
--menu-item-popup-padding-y: 0px;
--menu-item-popup-padding-x: 14px;
--menu-item-margin-y: 4px;
--menu-item-margin-x: 8px;
--menu-item-collapse-padding-y: 0px;
--menu-item-collapse-padding-x: 0px;
--menu-item-collapse-margin-y: 4px;
--menu-item-collapse-margin-x: 0px;
--menu-item-radius: 0px;
--menu-item-indent: 16px;
--menu-item-collapse-margin-x: 8px;
--menu-item-radius: 14px;
--menu-item-shadow:
inset 0 1px 0 hsl(var(--nav-sheen) / 0.54),
0 22px 40px -30px hsl(var(--primary) / 0.24);
--menu-item-indent: 18px;
--menu-font-size: 14px;
--menu-item-indicator-width: 0px;
&.is-dark {
--menu-background-color: hsl(var(--menu));
// --menu-submenu-opened-background-color: hsl(var(--menu-opened-dark));
--menu-item-background-color: var(--menu-background-color);
--menu-item-color: hsl(216.92, 15.12%, 33.73% / 80%);
--menu-item-hover-color: hsl(var(--accent-foreground));
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--accent-foreground));
--menu-item-active-background-color: hsl(var(--accent));
--menu-background-color: hsl(var(--nav-surface));
--menu-item-background-color: transparent;
--menu-item-color: hsl(var(--nav-item-muted-foreground));
--menu-item-hover-color: hsl(var(--foreground));
--menu-item-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.78),
hsl(var(--glass-tint) / 0.46)
);
--menu-item-active-color: hsl(var(--nav-item-active-foreground));
--menu-item-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active) / 0.92) 0%,
hsl(var(--nav-item-hover) / 0.72) 54%,
hsl(var(--glass-tint) / 0.52) 100%
);
--menu-submenu-hover-color: hsl(var(--foreground));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--foreground));
--menu-submenu-active-background-color: transparent;
--menu-submenu-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.78),
hsl(var(--glass-tint) / 0.46)
);
--menu-submenu-active-color: hsl(var(--nav-item-active-foreground));
--menu-submenu-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active) / 0.92) 0%,
hsl(var(--nav-item-hover) / 0.72) 54%,
hsl(var(--glass-tint) / 0.52) 100%
);
--menu-submenu-background-color: var(--menu-background-color);
}
&.is-light {
--menu-background-color: hsl(var(--menu));
// --menu-submenu-opened-background-color: hsl(var(--menu-opened));
--menu-item-background-color: var(--menu-background-color);
--menu-item-color: hsl(216.92, 15.12%, 33.73%);
--menu-item-hover-color: var(--menu-item-color);
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--primary));
--menu-item-active-background-color: hsl(var(--primary) / 15%);
--menu-submenu-hover-color: hsl(var(--primary));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--primary));
--menu-submenu-active-background-color: transparent;
--menu-background-color: hsl(var(--nav-surface));
--menu-item-background-color: transparent;
--menu-item-color: hsl(var(--nav-item-muted-foreground));
--menu-item-hover-color: hsl(var(--foreground));
--menu-item-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.78),
hsl(var(--glass-tint) / 0.46)
);
--menu-item-active-color: hsl(var(--nav-item-active-foreground));
--menu-item-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active) / 0.92) 0%,
hsl(var(--nav-item-hover) / 0.72) 54%,
hsl(var(--glass-tint) / 0.52) 100%
);
--menu-submenu-hover-color: hsl(var(--foreground));
--menu-submenu-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.78),
hsl(var(--glass-tint) / 0.46)
);
--menu-submenu-active-color: hsl(var(--nav-item-active-foreground));
--menu-submenu-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active) / 0.92) 0%,
hsl(var(--nav-item-hover) / 0.72) 54%,
hsl(var(--glass-tint) / 0.52) 100%
);
--menu-submenu-background-color: var(--menu-background-color);
}
&.is-rounded {
--menu-item-margin-x: 8px;
--menu-item-collapse-margin-x: 6px;
--menu-item-radius: 8px;
--menu-item-collapse-margin-x: 8px;
--menu-item-radius: 10px;
}
&.is-horizontal:not(.is-rounded) {
--menu-item-height: 40px;
--menu-item-radius: 6px;
--menu-item-radius: 14px;
}
&.is-horizontal.is-rounded {
--menu-item-height: 40px;
--menu-item-radius: 6px;
--menu-item-radius: 14px;
--menu-item-padding-x: 12px;
}
@@ -519,25 +570,61 @@ $namespace: easyflow;
--menu-background-color: transparent;
&.is-dark {
--menu-item-hover-color: hsl(var(--accent-foreground));
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--accent-foreground));
--menu-item-active-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--foreground));
--menu-submenu-active-background-color: hsl(var(--accent));
--menu-submenu-hover-color: hsl(var(--accent-foreground));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-item-hover-color: hsl(var(--foreground));
--menu-item-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.98),
hsl(var(--nav-surface-subtle) / 0.84)
);
--menu-item-active-color: hsl(var(--nav-item-active-foreground));
--menu-item-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active)) 0%,
hsl(var(--nav-item-hover) / 0.98) 55%,
hsl(var(--glass-tint) / 0.98) 100%
);
--menu-submenu-active-color: hsl(var(--nav-item-active-foreground));
--menu-submenu-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active)) 0%,
hsl(var(--nav-item-hover) / 0.98) 55%,
hsl(var(--glass-tint) / 0.98) 100%
);
--menu-submenu-hover-color: hsl(var(--foreground));
--menu-submenu-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.98),
hsl(var(--nav-surface-subtle) / 0.84)
);
}
&.is-light {
--menu-item-active-color: hsl(var(--primary));
--menu-item-active-background-color: hsl(var(--primary) / 15%);
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-hover-color: hsl(var(--primary));
--menu-submenu-active-color: hsl(var(--primary));
--menu-submenu-active-background-color: hsl(var(--primary) / 15%);
--menu-submenu-hover-color: hsl(var(--primary));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--nav-item-active-foreground));
--menu-item-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active)) 0%,
hsl(var(--nav-item-hover) / 0.98) 55%,
hsl(var(--glass-tint) / 0.98) 100%
);
--menu-item-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.98),
hsl(var(--nav-surface-subtle) / 0.84)
);
--menu-item-hover-color: hsl(var(--foreground));
--menu-submenu-active-color: hsl(var(--nav-item-active-foreground));
--menu-submenu-active-background-color: linear-gradient(
135deg,
hsl(var(--nav-item-active)) 0%,
hsl(var(--nav-item-hover) / 0.98) 55%,
hsl(var(--glass-tint) / 0.98) 100%
);
--menu-submenu-hover-color: hsl(var(--foreground));
--menu-submenu-hover-background-color: linear-gradient(
180deg,
hsl(var(--nav-item-hover) / 0.98),
hsl(var(--nav-surface-subtle) / 0.84)
);
}
}
}
@@ -674,6 +761,10 @@ $namespace: easyflow;
&.is-active {
background: var(--menu-item-active-background-color) !important;
border-radius: var(--menu-item-radius);
&::before {
left: 8px;
}
}
}
@@ -719,7 +810,7 @@ $namespace: easyflow;
flex-shrink: 0;
width: var(--menu-item-icon-size);
height: var(--menu-item-icon-size);
margin-right: 8px;
margin-right: 0;
vertical-align: middle;
text-align: center;
}
@@ -741,6 +832,7 @@ $namespace: easyflow;
align-items: center;
width: 100%;
height: var(--menu-item-height);
gap: 10px;
span {
@include menu-title;
@@ -775,6 +867,8 @@ $namespace: easyflow;
text-decoration: none;
cursor: pointer;
background: var(--menu-item-hover-background-color) !important;
box-shadow: 0 18px 34px -30px hsl(var(--primary) / 0.18);
transform: translateX(2px);
}
.#{$namespace}-menu-tooltip__trigger {
@@ -809,8 +903,20 @@ $namespace: easyflow;
cursor: pointer;
background: var(--menu-submenu-active-background-color);
fill: var(--menu-submenu-active-color);
box-shadow: var(--menu-item-shadow);
}
}
&:focus-visible {
outline: none;
}
&:focus-visible > .#{$namespace}-sub-menu-content,
&:focus-within > .#{$namespace}-sub-menu-content {
box-shadow:
0 0 0 1px hsl(var(--glass-border) / 0.72),
0 0 0 4px hsl(var(--ring) / 0.16);
}
}
.#{$namespace}-sub-menu-content {
@@ -833,6 +939,7 @@ $namespace: easyflow;
&__title {
@include menu-title;
font-weight: 500;
}
&.is-collapse-show-title {
@@ -866,10 +973,13 @@ $namespace: easyflow;
text-decoration: none;
cursor: pointer;
background: var(--menu-submenu-hover-background-color) !important;
// svg {
// fill: var(--menu-submenu-hover-color);
// }
box-shadow: 0 18px 34px -30px hsl(var(--primary) / 0.18);
transform: translateX(2px);
}
}
.#{$namespace}-sub-menu .#{$namespace}-menu-item,
.#{$namespace}-sub-menu .#{$namespace}-sub-menu-content {
font-size: 13px;
}
</style>

View File

@@ -120,6 +120,15 @@ function handleClick() {
});
}
function handleKeydown(event: KeyboardEvent) {
if (event.key !== 'Enter' && event.key !== ' ') {
return;
}
event.preventDefault();
handleClick();
}
function handleMouseenter(event: FocusEvent | MouseEvent, showTimeout = 300) {
if (event.type === 'focus') {
return;
@@ -197,9 +206,11 @@ onBeforeUnmount(() => {
is('active', active),
is('disabled', disabled),
]"
:tabindex="disabled ? -1 : 0"
@focus="handleMouseenter"
@mouseenter="handleMouseenter"
@mouseleave="() => handleMouseleave()"
@keydown="handleKeydown"
>
<template v-if="rootMenu.isMenuPopup">
<EasyFlowHoverCard