🐛 fix(theme): 统一 Monaco 与通用弹窗主题细节

- 统一 Monaco 编辑器背景变量并避免全局主题相互污染
- 为自定义主题补充编辑器表面变量及兼容处理
- 区分 DataGrid 数据编辑器与 SQL 定义编辑器字号
- 修复 V2 输入框重复边框和弹窗关闭按钮错位
- 支持可缩放弹窗内容及 Monaco 编辑器自适应填充
This commit is contained in:
Syngnat
2026-07-28 16:00:24 +08:00
parent cef273f228
commit d3fabe29d4
12 changed files with 261 additions and 21 deletions

View File

@@ -1,8 +1,10 @@
import { describe, expect, it } from 'vitest';
import {
CUSTOM_THEME_MAX_BYTES,
ensureCustomThemeMonacoSurfaceVars,
extractComputedCustomThemeAntTokens,
extractCustomThemeAntTokens,
sanitizeCustomThemeDefinition,
sanitizeCustomThemeList,
validateCustomThemeCss,
} from './customTheme';
@@ -49,6 +51,32 @@ describe('custom theme CSS validation', () => {
);
});
it('injects --gn-monaco-bg for hand-written themes that only set panel', () => {
const css = 'body[data-custom-theme] {\n --gn-bg-panel: #f7faf8;\n}';
const next = ensureCustomThemeMonacoSurfaceVars(css);
expect(next).toContain('--gn-monaco-bg: var(--gn-bg-panel)');
expect(next).toContain('--gn-bg-panel: #f7faf8');
});
it('does not override an explicit --gn-monaco-bg in custom theme CSS', () => {
const css = 'body[data-custom-theme] {\n --gn-bg-panel: #111;\n --gn-monaco-bg: #222;\n}';
expect(ensureCustomThemeMonacoSurfaceVars(css)).toBe(css);
});
it('sanitizes custom themes and ensures Monaco surface token', () => {
const theme = sanitizeCustomThemeDefinition({
schemaVersion: 1,
id: 'hand-written',
name: 'Hand',
sourceFileName: 'hand.css',
baseMode: 'dark',
css: 'body[data-custom-theme] { --gn-bg-panel: #1d202b; --gn-accent: #8b5cf6; }',
createdAt: 1,
updatedAt: 1,
});
expect(theme?.css).toContain('--gn-monaco-bg: var(--gn-bg-panel)');
});
it('extracts safe CSS color tokens for Ant Design without accepting arbitrary values', () => {
const tokens = extractCustomThemeAntTokens(`
body[data-custom-theme] {

View File

@@ -218,6 +218,27 @@ export const createCustomThemeId = (): string => {
return `theme-${randomId.toLowerCase().replace(/[^a-z0-9_-]/g, '-')}`.slice(0, 80);
};
/**
* Ensure Monaco surface token exists for hand-written custom themes.
* Presets already define it; user CSS that only sets --gn-bg-panel still needs this.
* If the theme already declares --gn-monaco-bg, leave it alone (user override wins).
*/
export const ensureCustomThemeMonacoSurfaceVars = (css: string): string => {
const source = String(css || '');
if (/--gn-monaco-bg\s*:/.test(source)) return source;
const trimmed = source.trimEnd();
const appendix = [
'',
'/* GoNavi: Monaco surface follows panel unless the theme overrides --gn-monaco-bg */',
'body[data-custom-theme],',
'body[data-custom-theme][data-ui-version="v2"] {',
' --gn-monaco-bg: var(--gn-bg-panel);',
'}',
'',
].join('\n');
return trimmed ? `${trimmed}\n${appendix}` : appendix.trimStart();
};
export const sanitizeCustomThemeDefinition = (value: unknown): CustomThemeDefinition | null => {
if (!value || typeof value !== 'object') return null;
const raw = value as Record<string, unknown>;
@@ -242,7 +263,7 @@ export const sanitizeCustomThemeDefinition = (value: unknown): CustomThemeDefini
name: sanitizeCustomThemeName(raw.name, deriveCustomThemeName(sourceFileName)),
sourceFileName,
baseMode: sanitizeCustomThemeBaseMode(raw.baseMode),
css: validation.css,
css: ensureCustomThemeMonacoSurfaceVars(validation.css),
createdAt,
updatedAt,
};
@@ -375,6 +396,7 @@ body[data-custom-theme][data-ui-version="v2"] {
--gn-bg-chrome: #171a23;
--gn-bg-panel: #1d202b;
--gn-bg-panel-2: #232733;
--gn-monaco-bg: var(--gn-bg-panel);
--gn-bg-hover: rgba(255, 255, 255, 0.06);
--gn-bg-active: rgba(255, 255, 255, 0.10);
--gn-bg-selected: rgba(139, 92, 246, 0.18);

View File

@@ -254,6 +254,7 @@ body[data-custom-theme][data-ui-version="v2"] {
--gn-bg-chrome: ${palette.chrome};
--gn-bg-panel: ${palette.panel};
--gn-bg-panel-2: ${palette.panel2};
--gn-monaco-bg: var(--gn-bg-panel);
--gn-bg-input: ${palette.input};
--gn-bg-subtle: ${palette.panel2};
--gn-bg-hover: ${palette.hover};