mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-18 16:30:32 +08:00
fix: Monaco syntax highlighting broken by CSS injection #5440
This commit is contained in:
parent
b3dc48d07e
commit
be97a27ba3
@ -18,6 +18,61 @@ import { useVerge } from "@/hooks/use-verge";
|
|||||||
import { defaultDarkTheme, defaultTheme } from "@/pages/_theme";
|
import { defaultDarkTheme, defaultTheme } from "@/pages/_theme";
|
||||||
import { useSetThemeMode, useThemeMode } from "@/services/states";
|
import { useSetThemeMode, useThemeMode } from "@/services/states";
|
||||||
|
|
||||||
|
const CSS_INJECTION_SCOPE_ROOT = "[data-css-injection-root]";
|
||||||
|
const CSS_INJECTION_SCOPE_LIMIT =
|
||||||
|
':is(.monaco-editor .view-lines, .monaco-editor .view-line, .monaco-editor .margin, .monaco-editor .margin-view-overlays, .monaco-editor .view-overlays, .monaco-editor [class^="mtk"], .monaco-editor [class*=" mtk"])';
|
||||||
|
const TOP_LEVEL_AT_RULES = [
|
||||||
|
"@charset",
|
||||||
|
"@import",
|
||||||
|
"@namespace",
|
||||||
|
"@font-face",
|
||||||
|
"@keyframes",
|
||||||
|
"@counter-style",
|
||||||
|
"@page",
|
||||||
|
"@property",
|
||||||
|
"@font-feature-values",
|
||||||
|
"@color-profile",
|
||||||
|
];
|
||||||
|
let cssScopeSupport: boolean | null = null;
|
||||||
|
|
||||||
|
const canUseCssScope = () => {
|
||||||
|
if (cssScopeSupport !== null) {
|
||||||
|
return cssScopeSupport;
|
||||||
|
}
|
||||||
|
if (typeof document === "undefined") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const testStyle = document.createElement("style");
|
||||||
|
testStyle.textContent = "@scope (:root) { }";
|
||||||
|
document.head.appendChild(testStyle);
|
||||||
|
cssScopeSupport = !!testStyle.sheet?.cssRules?.length;
|
||||||
|
document.head.removeChild(testStyle);
|
||||||
|
} catch {
|
||||||
|
cssScopeSupport = false;
|
||||||
|
}
|
||||||
|
return cssScopeSupport;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapCssInjectionWithScope = (css?: string) => {
|
||||||
|
if (!css?.trim()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const lowerCss = css.toLowerCase();
|
||||||
|
const hasTopLevelOnlyRule = TOP_LEVEL_AT_RULES.some((rule) =>
|
||||||
|
lowerCss.includes(rule),
|
||||||
|
);
|
||||||
|
if (hasTopLevelOnlyRule) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const scopeRoot = CSS_INJECTION_SCOPE_ROOT;
|
||||||
|
const scopeLimit = CSS_INJECTION_SCOPE_LIMIT;
|
||||||
|
const scopedBlock = `@scope (${scopeRoot}) to (${scopeLimit}) {
|
||||||
|
${css}
|
||||||
|
}`;
|
||||||
|
return scopedBlock;
|
||||||
|
};
|
||||||
|
|
||||||
const languagePackMap: Record<string, any> = {
|
const languagePackMap: Record<string, any> = {
|
||||||
zh: { ...zhXDataGrid },
|
zh: { ...zhXDataGrid },
|
||||||
fa: { ...faXDataGrid },
|
fa: { ...faXDataGrid },
|
||||||
@ -134,8 +189,27 @@ export const useCustomTheme = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const legacyQuery = mediaQuery as MediaQueryListLegacy;
|
const legacyQuery = mediaQuery as MediaQueryListLegacy;
|
||||||
legacyQuery.addListener?.(handleChange);
|
const legacyAddListener = (
|
||||||
return () => legacyQuery.removeListener?.(handleChange);
|
legacyQuery as {
|
||||||
|
addListener?: (
|
||||||
|
listener: (this: MediaQueryList, event: MediaQueryListEvent) => void,
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
).addListener;
|
||||||
|
legacyAddListener?.call(legacyQuery, handleChange);
|
||||||
|
return () => {
|
||||||
|
const legacyRemoveListener = (
|
||||||
|
legacyQuery as {
|
||||||
|
removeListener?: (
|
||||||
|
listener: (
|
||||||
|
this: MediaQueryList,
|
||||||
|
event: MediaQueryListEvent,
|
||||||
|
) => void,
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
).removeListener;
|
||||||
|
legacyRemoveListener?.call(legacyQuery, handleChange);
|
||||||
|
};
|
||||||
}, [theme_mode, setMode]);
|
}, [theme_mode, setMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -264,6 +338,7 @@ export const useCustomTheme = () => {
|
|||||||
? String(setting.background_opacity)
|
? String(setting.background_opacity)
|
||||||
: "1",
|
: "1",
|
||||||
);
|
);
|
||||||
|
rootEle.setAttribute("data-css-injection-root", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
let styleElement = document.querySelector("style#verge-theme");
|
let styleElement = document.querySelector("style#verge-theme");
|
||||||
@ -274,6 +349,11 @@ export const useCustomTheme = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (styleElement) {
|
if (styleElement) {
|
||||||
|
let scopedCss: string | null = null;
|
||||||
|
if (canUseCssScope() && setting.css_injection) {
|
||||||
|
scopedCss = wrapCssInjectionWithScope(setting.css_injection);
|
||||||
|
}
|
||||||
|
const effectiveInjectedCss = scopedCss ?? setting.css_injection ?? "";
|
||||||
const globalStyles = `
|
const globalStyles = `
|
||||||
/* 修复滚动条样式 */
|
/* 修复滚动条样式 */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
@ -323,7 +403,7 @@ export const useCustomTheme = () => {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
styleElement.innerHTML = (setting.css_injection || "") + globalStyles;
|
styleElement.innerHTML = effectiveInjectedCss + globalStyles;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { palette } = muiTheme;
|
const { palette } = muiTheme;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user