diff --git a/frontend/src/App.tool-center.test.ts b/frontend/src/App.tool-center.test.ts index 108e76d9..32da0f27 100644 --- a/frontend/src/App.tool-center.test.ts +++ b/frontend/src/App.tool-center.test.ts @@ -161,6 +161,18 @@ describe('tool center menu entries', () => { expect(shortcutSource).not.toContain('renderUtilityModalTitle'); }); + it('does not render an extra top back button in the tool center detail header', () => { + const detailHeaderSource = appSource.slice( + appSource.indexOf("{activeToolCenterPane ? ("), + appSource.indexOf('
', appSource.indexOf("{activeToolCenterPane ? (")), + ); + + expect(detailHeaderSource).toContain('activeToolCenterPaneItem?.title ?? activeToolCenterGroup.title'); + expect(detailHeaderSource).toContain('activeToolCenterPaneItem?.description ?? activeToolCenterGroup.description'); + expect(detailHeaderSource).not.toContain('
{renderToolCenterPane()} @@ -4505,10 +4523,14 @@ function App() { padding: '12px 12px', borderRadius: 12, border: `1px solid ${active - ? (darkMode ? 'rgba(255,214,102,0.3)' : 'rgba(24,144,255,0.24)') + ? (isV2Ui + ? v2AntPrimaryBorderColor + : (darkMode ? 'rgba(255,214,102,0.3)' : 'rgba(24,144,255,0.24)')) : (darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(16,24,40,0.08)')}`, background: active - ? (darkMode ? 'linear-gradient(180deg, rgba(255,214,102,0.12) 0%, rgba(255,214,102,0.06) 100%)' : 'linear-gradient(180deg, rgba(24,144,255,0.10) 0%, rgba(24,144,255,0.05) 100%)') + ? (isV2Ui + ? `linear-gradient(180deg, ${v2AntPrimaryBgHoverColor} 0%, ${v2AntPrimaryBgColor} 100%)` + : (darkMode ? 'linear-gradient(180deg, rgba(255,214,102,0.12) 0%, rgba(255,214,102,0.06) 100%)' : 'linear-gradient(180deg, rgba(24,144,255,0.10) 0%, rgba(24,144,255,0.05) 100%)')) : (darkMode ? 'rgba(255,255,255,0.02)' : 'rgba(255,255,255,0.72)'), color: active ? (darkMode ? '#f5f7ff' : '#162033') : (darkMode ? 'rgba(255,255,255,0.82)' : '#3f4b5e'), cursor: 'pointer', @@ -4657,10 +4679,14 @@ function App() { padding: '14px 14px', borderRadius: 14, border: `1px solid ${active - ? (darkMode ? 'rgba(255,214,102,0.3)' : 'rgba(24,144,255,0.24)') + ? (isV2Ui + ? v2AntPrimaryBorderColor + : (darkMode ? 'rgba(255,214,102,0.3)' : 'rgba(24,144,255,0.24)')) : (darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(16,24,40,0.08)')}`, background: active - ? (darkMode ? 'linear-gradient(180deg, rgba(255,214,102,0.12) 0%, rgba(255,214,102,0.06) 100%)' : 'linear-gradient(180deg, rgba(24,144,255,0.10) 0%, rgba(24,144,255,0.05) 100%)') + ? (isV2Ui + ? `linear-gradient(180deg, ${v2AntPrimaryBgHoverColor} 0%, ${v2AntPrimaryBgColor} 100%)` + : (darkMode ? 'linear-gradient(180deg, rgba(255,214,102,0.12) 0%, rgba(255,214,102,0.06) 100%)' : 'linear-gradient(180deg, rgba(24,144,255,0.10) 0%, rgba(24,144,255,0.05) 100%)')) : (darkMode ? 'rgba(255,255,255,0.02)' : 'rgba(255,255,255,0.72)'), color: active ? (darkMode ? '#f5f7ff' : '#162033') : (darkMode ? 'rgba(255,255,255,0.82)' : '#3f4b5e'), cursor: 'pointer', @@ -4668,7 +4694,7 @@ function App() { >
{item.label} - {active ? : null} + {active ? : null}
{item.description} @@ -4896,13 +4922,19 @@ function App() { padding: '9px 10px', borderRadius: 10, border: `1px solid ${isFocused - ? (darkMode ? 'rgba(255,214,102,0.54)' : 'rgba(24,144,255,0.54)') + ? (isV2Ui + ? v2AntPrimaryBorderHoverColor + : (darkMode ? 'rgba(255,214,102,0.54)' : 'rgba(24,144,255,0.54)')) : (darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(16,24,40,0.08)')}`, boxShadow: isFocused - ? (darkMode ? '0 0 0 2px rgba(255,214,102,0.14)' : '0 0 0 2px rgba(24,144,255,0.12)') + ? (isV2Ui + ? `0 0 0 2px ${v2AntControlActiveBg}` + : (darkMode ? '0 0 0 2px rgba(255,214,102,0.14)' : '0 0 0 2px rgba(24,144,255,0.12)')) : 'none', background: isFocused - ? (darkMode ? 'linear-gradient(90deg, rgba(255,214,102,0.12) 0%, rgba(255,255,255,0.045) 100%)' : 'linear-gradient(90deg, rgba(24,144,255,0.10) 0%, rgba(255,255,255,0.78) 100%)') + ? (isV2Ui + ? `linear-gradient(90deg, ${v2AntPrimaryBgHoverColor} 0%, rgba(255,255,255,0.045) 100%)` + : (darkMode ? 'linear-gradient(90deg, rgba(255,214,102,0.12) 0%, rgba(255,255,255,0.045) 100%)' : 'linear-gradient(90deg, rgba(24,144,255,0.10) 0%, rgba(255,255,255,0.78) 100%)')) : checked ? (darkMode ? 'rgba(255,255,255,0.045)' : 'rgba(255,255,255,0.62)') : (darkMode ? 'rgba(255,255,255,0.02)' : 'rgba(16,24,40,0.025)'), @@ -4923,10 +4955,10 @@ function App() { fontSize: 11, fontWeight: 800, background: isFocused - ? (darkMode ? 'rgba(255,214,102,0.22)' : 'rgba(24,144,255,0.14)') + ? (isV2Ui ? v2AntPrimaryBgHoverColor : (darkMode ? 'rgba(255,214,102,0.22)' : 'rgba(24,144,255,0.14)')) : (darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(16,24,40,0.05)'), color: isFocused - ? (darkMode ? '#ffd666' : '#1677ff') + ? (isV2Ui ? v2AntPrimaryColor : (darkMode ? '#ffd666' : '#1677ff')) : (darkMode ? 'rgba(255,255,255,0.56)' : 'rgba(16,24,40,0.5)'), }}> {checked && indexInRow >= 0 ? indexInRow + 1 : '-'} @@ -4946,8 +4978,8 @@ function App() { lineHeight: '16px', padding: '0 6px', borderRadius: 999, - background: darkMode ? 'rgba(255,214,102,0.16)' : 'rgba(24,144,255,0.10)', - color: darkMode ? '#ffd666' : '#1677ff', + background: isV2Ui ? v2AntPrimaryBgColor : (darkMode ? 'rgba(255,214,102,0.16)' : 'rgba(24,144,255,0.10)'), + color: isV2Ui ? v2AntPrimaryColor : (darkMode ? '#ffd666' : '#1677ff'), }}> {t('app.theme.tab_display.badge.current')} diff --git a/frontend/src/components/ConnectionModal.tsx b/frontend/src/components/ConnectionModal.tsx index 8954ebe8..6503f4f3 100644 --- a/frontend/src/components/ConnectionModal.tsx +++ b/frontend/src/components/ConnectionModal.tsx @@ -482,8 +482,9 @@ const ConnectionModal: React.FC<{ () => buildOverlayWorkbenchTheme(darkMode, { disableBackdropFilter: disableLocalBackdropFilter, + uiVersion: appearance.uiVersion, }), - [darkMode, disableLocalBackdropFilter, appearance.uiVersion], + [appearance.uiVersion, darkMode, disableLocalBackdropFilter], ); const tunnelSectionStyle: React.CSSProperties = { diff --git a/frontend/src/components/Sidebar.locate-toolbar.test.tsx b/frontend/src/components/Sidebar.locate-toolbar.test.tsx index 9c4c837e..bd915168 100644 --- a/frontend/src/components/Sidebar.locate-toolbar.test.tsx +++ b/frontend/src/components/Sidebar.locate-toolbar.test.tsx @@ -1066,10 +1066,11 @@ describe('Sidebar locate toolbar', () => { expect(css).toMatch(/\.gn-v2-tree-count \{[^}]*font-size: clamp\(10px, calc\(var\(--gn-sidebar-tree-font-size, var\(--gn-font-size-sm, 12px\)\) - 1px\), 16px\);/s); expect(css).toMatch(/\.gn-v2-tree-title\.is-redis-db \.gn-v2-tree-label \{[^}]*display: inline-flex;[^}]*gap: 6px;/s); expect(css).toMatch(/\.gn-v2-redis-db-alias \{[^}]*color: var\(--gn-fg-5\);[^}]*opacity: 0\.78;/s); - expect(css).toMatch(/\.gn-v2-connection-rail \{[^}]*width: calc\(38px \* var\(--gn-ui-scale, 1\)\);[^}]*flex: 0 0 calc\(38px \* var\(--gn-ui-scale, 1\)\);/s); - expect(css).toMatch(/\.gn-v2-rail-item,\s*body\[data-ui-version="v2"\] \.gn-v2-rail-tool \{[^}]*width: calc\(36px \* var\(--gn-ui-scale, 1\)\);[^}]*height: calc\(38px \* var\(--gn-ui-scale, 1\)\);[^}]*font-size: var\(--gn-font-size-sm, 12px\);/s); - expect(css).toMatch(/\.gn-v2-rail-tool \{[^}]*height: calc\(32px \* var\(--gn-ui-scale, 1\)\);/s); - expect(css).toMatch(/\.gn-v2-rail-tool \{[^}]*width: calc\(24px \* var\(--gn-ui-scale, 1\)\);/s); + expect(css).toContain('--gn-v2-rail-scale: calc(var(--gn-ui-scale, 1) * var(--gn-sidebar-rail-scale, 1));'); + expect(css).toMatch(/\.gn-v2-connection-rail \{[^}]*width: calc\(38px \* var\(--gn-v2-rail-scale\)\);[^}]*flex: 0 0 calc\(38px \* var\(--gn-v2-rail-scale\)\);/s); + expect(css).toMatch(/body\[data-ui-version="v2"\] \.gn-v2-rail-item,\s*body\[data-ui-version="v2"\] \.gn-v2-rail-tool \{[^}]*width: calc\(36px \* var\(--gn-v2-rail-scale\)\);[^}]*height: calc\(38px \* var\(--gn-v2-rail-scale\)\);[^}]*font-size: calc\(var\(--gn-font-size-sm, 12px\) \* var\(--gn-sidebar-rail-scale, 1\)\);/s); + expect(css).toMatch(/\.gn-v2-rail-tool \{[^}]*height: calc\(32px \* var\(--gn-v2-rail-scale\)\);/s); + expect(css).toMatch(/\.gn-v2-rail-tool \{[^}]*width: calc\(24px \* var\(--gn-v2-rail-scale\)\);/s); expect(css).toMatch(/\.gn-v2-active-connection-trigger \{[^}]*height: 34px;[^}]*border: 0;[^}]*background: transparent;/s); expect(css).toMatch(/\.gn-v2-active-connection-query-action \{[^}]*max-width: 96px;[^}]*font-size: 12px;/s); expect(css).not.toContain('.gn-v2-active-connection-trigger:hover'); @@ -1155,25 +1156,22 @@ describe('Sidebar locate toolbar', () => { expect(source).not.toContain('treeHeight - V2_TREE_HORIZONTAL_SCROLL_BOTTOM_RESERVE'); expect(source).toContain('height={effectiveTreeHeight}'); expect(source).toContain('treeData={isV2Ui ? v2VisibleTreeData : displayTreeData}'); - expect(source).not.toContain('__v2-tree-horizontal-scroll-spacer__'); - expect(source).not.toContain('v2TreeDataWithScrollSpacer'); expect(css).toMatch(/\.gn-v2-explorer-tree-shell \{[^}]*--gn-v2-tree-horizontal-scroll-reserve: 32px;[^}]*overflow: hidden !important;/s); expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.sidebar-tree-scroll-content \{[^}]*display: flex;[^}]*height: 100%;[^}]*padding: 4px 0 0;/s); expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree \{[^}]*flex: 1 1 auto;[^}]*width: 100%;[^}]*min-width: 0;[^}]*height: 100%;/s); - expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list \{[^}]*position: relative;[^}]*height: 100%;[^}]*min-height: 0;[^}]*box-sizing: border-box;[^}]*padding-bottom: var\(--gn-v2-tree-horizontal-scroll-reserve\);/s); + expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list \{[^}]*position: relative;[^}]*height: 100%;[^}]*min-height: 0;[^}]*box-sizing: border-box;/s); expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-holder-inner \{[^}]*width: 100%;[^}]*min-width: 100%;/s); expect(css).not.toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-holder-inner \{[^}]*width: max-content;/s); expect(css).not.toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list \{[^}]*position: static !important;/s); - expect(css).not.toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-holder \{[^}]*calc\(100% - var\(--gn-v2-tree-horizontal-scroll-reserve\)\)/s); + expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-holder \{[^}]*height: calc\(100% - var\(--gn-v2-tree-horizontal-scroll-reserve\)\);[^}]*max-height: calc\(100% - var\(--gn-v2-tree-horizontal-scroll-reserve\)\) !important;/s); expect(css).not.toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-holder \{[^}]*overflow-x: auto !important;/s); - expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-holder \{[^}]*padding-bottom: var\(--gn-v2-tree-horizontal-scroll-reserve\);/s); - expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-scrollbar-horizontal \{[^}]*height: 12px !important;[^}]*bottom: calc\(\(var\(--gn-v2-tree-horizontal-scroll-reserve\) - 12px\) \/ 2\) !important;/s); - expect(css).not.toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-scrollbar-horizontal \{[^}]*bottom: calc\(\(var\(--gn-v2-tree-horizontal-scroll-reserve\) - 12px\) \* -1\) !important;/s); - expect(css).not.toContain('.gn-v2-tree-horizontal-scroll-spacer'); + expect(css).not.toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-holder \{[^}]*padding-bottom: var\(--gn-v2-tree-horizontal-scroll-reserve\);/s); + expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-scrollbar-horizontal \{[^}]*height: 12px !important;[^}]*bottom: 0 !important;/s); + expect(css).not.toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-scrollbar-horizontal \{[^}]*bottom: calc\(\(var\(--gn-v2-tree-horizontal-scroll-reserve\) - 12px\) \/ 2\) !important;/s); const horizontalScrollbarCss = readCssRuleBlock(css, 'body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-list-scrollbar-horizontal'); expect(horizontalScrollbarCss).toContain('border-radius: 999px !important;'); - expect(horizontalScrollbarCss).toContain('background: color-mix(in srgb, var(--gn-bg-panel-2) 88%, var(--gn-bg-panel) 12%) !important;'); - expect(horizontalScrollbarCss).toContain('box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gn-br-2) 40%, transparent) !important;'); + expect(horizontalScrollbarCss).toContain('background: transparent !important;'); + expect(horizontalScrollbarCss).toContain('box-shadow: none !important;'); expect(css).toMatch(/\.gn-v2-explorer-tree-shell \.ant-tree-list-scrollbar-horizontal \.ant-tree-list-scrollbar-thumb \{[^}]*height: 8px !important;/s); const treeContentWrapperCss = readCssRuleBlock(css, 'body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-node-content-wrapper'); expect(treeContentWrapperCss).toContain('min-width: 100%;'); @@ -1339,10 +1337,18 @@ describe('Sidebar locate toolbar', () => { const source = readSidebarSource(); expect(source).toContain("if (v2ExplorerFilter === 'all') {"); + expect(source).toContain('return displayTreeData;'); expect(source).toContain('gn-v2-tree-connection-copy'); expect(source).not.toContain('gn-v2-tree-connection-meta'); }); + it('remounts the v2 tree when object filters change to avoid rc-tree node reuse drift', () => { + const source = readSidebarSource(); + + expect(source).toContain("key={isV2Ui ? `v2-tree-${v2ExplorerFilter}` : 'legacy-tree'}"); + expect(source).toContain('treeData={isV2Ui ? v2VisibleTreeData : displayTreeData}'); + }); + it('reorders dragged connections instead of only moving them between groups', () => { const source = readSidebarSource(); const utilsSource = readFileSync(new URL('./sidebarV2Utils.ts', import.meta.url), 'utf8'); diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 58c673c3..4efa8a55 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -457,8 +457,11 @@ const Sidebar: React.FC<{ }; const bgMain = getBg('#141414'); const overlayTheme = useMemo( - () => buildOverlayWorkbenchTheme(darkMode, { disableBackdropFilter: disableLocalBackdropFilter }), - [darkMode, disableLocalBackdropFilter, appearance.uiVersion], + () => buildOverlayWorkbenchTheme(darkMode, { + disableBackdropFilter: disableLocalBackdropFilter, + uiVersion: isV2Ui ? 'v2' : 'legacy', + }), + [darkMode, disableLocalBackdropFilter, isV2Ui], ); const modalPanelStyle = useMemo(() => ({ background: overlayTheme.shellBg, @@ -2920,6 +2923,7 @@ const Sidebar: React.FC<{ >
{ @@ -87,8 +89,11 @@ export const useAppUtilityStyles = ({ }), [effectiveBlurFilter, darkMode, effectiveUiScale, isOpaqueUtilityMode, isSidebarCompact, utilityButtonBgColor, utilityButtonBorderColor, utilityButtonShadow]); const disableLocalBackdropFilter = isMacLikePlatform(); const overlayTheme = useMemo( - () => buildOverlayWorkbenchTheme(darkMode, { disableBackdropFilter: disableLocalBackdropFilter }), - [darkMode, disableLocalBackdropFilter], + () => buildOverlayWorkbenchTheme(darkMode, { + disableBackdropFilter: disableLocalBackdropFilter, + uiVersion: isV2Ui ? 'v2' : 'legacy', + }), + [darkMode, disableLocalBackdropFilter, isV2Ui], ); const sidebarQuickActionBaseStyle = useMemo(() => ({ diff --git a/frontend/src/utils/overlayWorkbenchTheme.test.ts b/frontend/src/utils/overlayWorkbenchTheme.test.ts index 68fa64da..66d2c065 100644 --- a/frontend/src/utils/overlayWorkbenchTheme.test.ts +++ b/frontend/src/utils/overlayWorkbenchTheme.test.ts @@ -23,4 +23,14 @@ describe('buildOverlayWorkbenchTheme', () => { const darkTheme = buildOverlayWorkbenchTheme(true, { disableBackdropFilter: true }); expect(darkTheme.shellBackdropFilter).toBe('none'); }); + + it('builds v2 theme tokens from explicit uiVersion instead of reading body state', () => { + const darkTheme = buildOverlayWorkbenchTheme(true, { uiVersion: 'v2' }); + const lightTheme = buildOverlayWorkbenchTheme(false, { uiVersion: 'v2' }); + + expect(darkTheme.iconColor).toBe('#22c55e'); + expect(darkTheme.selectedText).toBe('#4ade80'); + expect(lightTheme.iconColor).toBe('#16a34a'); + expect(lightTheme.selectedText).toBe('#15803d'); + }); }); diff --git a/frontend/src/utils/overlayWorkbenchTheme.ts b/frontend/src/utils/overlayWorkbenchTheme.ts index d8e3e8d0..25444ce0 100644 --- a/frontend/src/utils/overlayWorkbenchTheme.ts +++ b/frontend/src/utils/overlayWorkbenchTheme.ts @@ -1,15 +1,5 @@ import { resolveTextInputSafeBackdropFilter } from './appearance'; -/** - * 是否处于 v2 界面版本。 - * 读取 body[data-ui-version],由 App.tsx 在切换时设置。 - * 在 SSR / 测试环境(无 document)时安全 fallback 为 false。 - */ -const isV2 = (): boolean => { - if (typeof document === 'undefined' || !document.body) return false; - return document.body.getAttribute('data-ui-version') === 'v2'; -}; - type OverlayWorkbenchTheme = { isDark: boolean; shellBg: string; @@ -30,15 +20,19 @@ type OverlayWorkbenchTheme = { export const buildOverlayWorkbenchTheme = ( darkMode: boolean, - options?: { disableBackdropFilter?: boolean }, + options?: { + disableBackdropFilter?: boolean; + uiVersion?: 'legacy' | 'v2'; + }, ): OverlayWorkbenchTheme => { const shellBackdropFilter = resolveTextInputSafeBackdropFilter( darkMode ? 'blur(18px)' : 'none', options?.disableBackdropFilter ?? false, ); + const uiVersion = options?.uiVersion ?? 'legacy'; // ─── v2 palette ────────────────────────────────────────────── - if (isV2()) { + if (uiVersion === 'v2') { if (darkMode) { return { isDark: true, diff --git a/frontend/src/v2-theme.css b/frontend/src/v2-theme.css index 3775d9df..ca416113 100644 --- a/frontend/src/v2-theme.css +++ b/frontend/src/v2-theme.css @@ -2629,12 +2629,12 @@ body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-list { height: 100%; min-height: 0; box-sizing: border-box; - padding-bottom: var(--gn-v2-tree-horizontal-scroll-reserve); } body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-list-holder { box-sizing: border-box; - padding-bottom: var(--gn-v2-tree-horizontal-scroll-reserve); + height: calc(100% - var(--gn-v2-tree-horizontal-scroll-reserve)); + max-height: calc(100% - var(--gn-v2-tree-horizontal-scroll-reserve)) !important; scrollbar-width: thin; } @@ -2642,10 +2642,10 @@ body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-list-scrollbar-h height: 12px !important; left: 8px !important; right: 8px !important; - bottom: calc((var(--gn-v2-tree-horizontal-scroll-reserve) - 12px) / 2) !important; + bottom: 0 !important; border-radius: 999px !important; - background: color-mix(in srgb, var(--gn-bg-panel-2) 88%, var(--gn-bg-panel) 12%) !important; - box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gn-br-2) 40%, transparent) !important; + background: transparent !important; + box-shadow: none !important; } body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-list-scrollbar-horizontal .ant-tree-list-scrollbar-thumb { @@ -3126,25 +3126,28 @@ body[data-ui-version="v2"] .gn-v2-empty-workbench { min-height: 100%; display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(280px, 0.65fr); - gap: 18px; - padding: 24px; - background: var(--gn-bg-app); + align-content: stretch; + gap: 0; + padding: 0; + background: var(--gn-bg-panel-2); } body[data-ui-version="v2"] .gn-v2-empty-hero, body[data-ui-version="v2"] .gn-v2-empty-panel { align-self: stretch; - border: 0.5px solid var(--gn-br-1); - border-radius: 8px; - background: color-mix(in srgb, var(--gn-bg-panel) 88%, transparent); - box-shadow: var(--gn-shadow-card); + border: 0; + border-radius: 0; + background: transparent; + box-shadow: none; } body[data-ui-version="v2"] .gn-v2-empty-hero { display: flex; flex-direction: column; - justify-content: center; - padding: 40px; + justify-content: flex-start; + min-height: 0; + background: var(--gn-bg-panel-2); + padding: 28px 28px 24px 30px; } body[data-ui-version="v2"] .gn-v2-empty-eyebrow { @@ -3160,10 +3163,10 @@ body[data-ui-version="v2"] .gn-v2-empty-eyebrow { body[data-ui-version="v2"] .gn-v2-empty-hero h1 { max-width: 720px; - margin: 18px 0 0; + margin: 12px 0 0; color: var(--gn-fg-1); - font-size: 40px; - line-height: 1.08; + font-size: 34px; + line-height: 1.1; font-weight: 800; } @@ -3175,17 +3178,17 @@ body[data-ui-version="v2"] .gn-v2-empty-hero h1 { body[data-ui-version="v2"] .gn-v2-empty-hero p { max-width: 560px; - margin: 16px 0 0; + margin: 12px 0 0; color: var(--gn-fg-3); - font-size: 14px; - line-height: 1.7; + font-size: 13px; + line-height: 1.6; } body[data-ui-version="v2"] .gn-v2-empty-actions { display: flex; flex-wrap: wrap; gap: 10px; - margin-top: 28px; + margin-top: 20px; } body[data-ui-version="v2"] .gn-v2-empty-actions .ant-btn { @@ -3194,10 +3197,12 @@ body[data-ui-version="v2"] .gn-v2-empty-actions .ant-btn { } body[data-ui-version="v2"] .gn-v2-empty-panel { - padding: 18px; + border-left: 0.5px solid var(--gn-br-1); + background: var(--gn-bg-panel-2); + padding: 16px 16px 16px 18px; display: flex; flex-direction: column; - gap: 10px; + gap: 8px; font-family: var(--gn-font-sans); } @@ -3216,18 +3221,19 @@ body[data-ui-version="v2"] .gn-v2-panel-heading { body[data-ui-version="v2"] .gn-v2-empty-panel button { width: 100%; - min-height: 70px; + min-height: 62px; display: grid; grid-template-columns: 34px minmax(0, 1fr); - gap: 12px; + gap: 10px; align-items: center; text-align: left; border: 0.5px solid var(--gn-br-1); - border-radius: 8px; - background: var(--gn-bg-panel-2); + border-radius: 6px; + background: color-mix(in srgb, var(--gn-bg-panel-2) 88%, var(--gn-bg-panel) 12%); color: var(--gn-fg-1); cursor: pointer; font-family: var(--gn-font-sans); + padding: 10px 12px; } body[data-ui-version="v2"] .gn-v2-empty-panel button:hover { @@ -3240,7 +3246,7 @@ body[data-ui-version="v2"] .gn-v2-empty-panel button > .anticon { height: 34px; display: grid; place-items: center; - border-radius: 8px; + border-radius: 6px; color: var(--gn-accent); background: var(--gn-accent-soft); } @@ -3267,6 +3273,31 @@ body[data-ui-version="v2"] .gn-v2-empty-panel small { line-height: 1.45; } +@media (max-width: 1360px) { + body[data-ui-version="v2"] .gn-v2-empty-workbench { + grid-template-columns: minmax(0, 1.28fr) minmax(260px, 0.72fr); + } + + body[data-ui-version="v2"] .gn-v2-empty-hero { + padding: 24px 22px 22px 24px; + } + + body[data-ui-version="v2"] .gn-v2-empty-panel { + padding: 14px 14px 14px 16px; + } +} + +@media (max-width: 1120px) { + body[data-ui-version="v2"] .gn-v2-empty-workbench { + grid-template-columns: minmax(0, 1fr); + } + + body[data-ui-version="v2"] .gn-v2-empty-panel { + border-left: 0; + border-top: 0.5px solid var(--gn-br-1); + } +} + /* ─── Full V2 workbench shell: app / topbar / workspace ─ */ body[data-ui-version="v2"] .gn-v2-app-root { background: var(--gn-bg-app) !important; @@ -3413,7 +3444,7 @@ body[data-ui-version="v2"] .gn-v2-tab-workbench { display: flex; flex-direction: column; overflow: hidden; - background: var(--gn-bg-panel); + background: var(--gn-bg-panel-2); } body[data-ui-version="v2"] .gn-v2-main-tabs > .ant-tabs-nav {