/* * @Author: liuJie * @Date: 2026-01-30 19:47:19 * @LastEditors: liuJie * @LastEditTime: 2026-01-30 20:20:59 * @Describe: 单独抽离换肤 */ import { ref, onMounted, onBeforeUnmount } from 'vue' import * as monaco from 'monaco-editor' type EditorTheme = 'vs-light' | 'vs-dark' type ThemeClass = 'light' | 'dark' interface UseLocalEditorThemeOptions { defaultTheme?: EditorTheme autoToggleTheme?: boolean } export function useLocalEditorTheme( options: UseLocalEditorThemeOptions = {} ) { const { defaultTheme = 'vs-light', autoToggleTheme = false } = options /** 当前 Monaco 主题(语法) */ const monacoTheme = ref(defaultTheme) /** 当前 UI 主题(样式) */ const themeClass = ref( defaultTheme === 'vs-dark' ? 'dark' : 'light' ) /** 系统暗黑监听 */ let mediaQuery: MediaQueryList | null = null const applyTheme = (theme: EditorTheme) => { monacoTheme.value = theme themeClass.value = theme === 'vs-dark' ? 'dark' : 'light' monaco.editor.setTheme(theme) } /** 手动切换 */ const toggleTheme = () => { applyTheme( monacoTheme.value === 'vs-light' ? 'vs-dark' : 'vs-light' ) } /** 系统主题变化 */ const handleSystemThemeChange = (e: MediaQueryListEvent) => { applyTheme(e.matches ? 'vs-dark' : 'vs-light') } onMounted(() => { applyTheme(defaultTheme) if (autoToggleTheme) { mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') applyTheme(mediaQuery.matches ? 'vs-dark' : 'vs-light') mediaQuery.addEventListener('change', handleSystemThemeChange) } }) onBeforeUnmount(() => { if (mediaQuery) { mediaQuery.removeEventListener('change', handleSystemThemeChange) } }) return { monacoTheme, themeClass, toggleTheme, setTheme: applyTheme } }