feat(ui): 完成新版 UI 全量改造

- 整体布局:按新版 UI 重构左侧导航、对象树、连接分组和右键菜单体系

- 数据视图:优化 DDL 侧栏、横向滚动、筛选输入、编辑入口和虚拟表格体验

- AI 面板:重构新版入口、输入区、模型选择、快捷键和悬浮布局

- 标签与快捷键:补齐 Tab 悬浮信息、复制交互和 Mac/Windows 快捷键配置

- 工程质量:新增 v2 主题样式、菜单组件、外观工具和回归测试覆盖
This commit is contained in:
Syngnat
2026-05-22 17:38:00 +08:00
parent 1d90aed187
commit 24d9db4c51
35 changed files with 11121 additions and 742 deletions

View File

@@ -1,31 +1,26 @@
import { describe, expect, it } from 'vitest';
import {
SIDEBAR_UTILITY_ITEM_KEYS,
resolveAIEntryPlacement,
resolveAIEdgeHandleAttachment,
resolveAIEdgeHandleDockStyle,
resolveAIEdgeHandleStyle,
resolveLegacyAIEdgeHandleAttachment,
resolveLegacyAIEdgeHandleDockStyle,
resolveLegacyAIEdgeHandleStyle,
} from './aiEntryLayout';
describe('ai entry layout', () => {
it('keeps the sidebar utility group compact and free of the AI entry', () => {
it('keeps legacy sidebar utility buttons limited to tools and settings', () => {
expect(SIDEBAR_UTILITY_ITEM_KEYS).toEqual(['tools', 'settings']);
});
it('anchors the AI entry to the content edge', () => {
expect(resolveAIEntryPlacement()).toBe('content-edge');
it('attaches the legacy closed AI handle to the content shell', () => {
expect(resolveLegacyAIEdgeHandleAttachment(false)).toBe('content-shell');
});
it('attaches the closed handle to the content shell', () => {
expect(resolveAIEdgeHandleAttachment(false)).toBe('content-shell');
it('attaches the legacy open AI handle to the panel shell', () => {
expect(resolveLegacyAIEdgeHandleAttachment(true)).toBe('panel-shell');
});
it('attaches the open handle to the panel shell', () => {
expect(resolveAIEdgeHandleAttachment(true)).toBe('panel-shell');
});
it('keeps the closed handle docked on the content edge', () => {
expect(resolveAIEdgeHandleDockStyle('content-shell')).toMatchObject({
it('keeps the legacy closed handle docked on the content edge', () => {
expect(resolveLegacyAIEdgeHandleDockStyle('content-shell')).toMatchObject({
position: 'absolute',
top: 16,
right: 0,
@@ -33,8 +28,8 @@ describe('ai entry layout', () => {
});
});
it('keeps the open handle outside the panel shell to avoid header overlap', () => {
expect(resolveAIEdgeHandleDockStyle('panel-shell')).toMatchObject({
it('keeps the legacy open handle outside the panel shell to avoid header overlap', () => {
expect(resolveLegacyAIEdgeHandleDockStyle('panel-shell')).toMatchObject({
position: 'absolute',
top: 16,
right: '100%',
@@ -42,8 +37,8 @@ describe('ai entry layout', () => {
});
});
it('uses the attached active appearance when the AI panel is open', () => {
const style = resolveAIEdgeHandleStyle({
it('uses the attached active appearance when the legacy AI panel is open', () => {
const style = resolveLegacyAIEdgeHandleStyle({
darkMode: true,
aiPanelVisible: true,
effectiveUiScale: 1,
@@ -55,17 +50,4 @@ describe('ai entry layout', () => {
expect(style.borderRight).toBe('none');
expect(style.height).toBe(24);
});
it('uses the subdued attached appearance when the AI panel is closed', () => {
const style = resolveAIEdgeHandleStyle({
darkMode: false,
aiPanelVisible: false,
effectiveUiScale: 1,
});
expect(style.color).toBe('rgba(22,32,51,0.82)');
expect(style.background).toBe('rgba(15,23,42,0.04)');
expect(style.paddingInline).toBe(8);
expect(style.borderRadius).toBe('10px 0 0 10px');
});
});