| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- import { reactive, computed, watchEffect } from 'vue';
- import { theme as antdTheme } from 'ant-design-vue';
- // Single shared theme state. `import { theme } from '@/composables/useTheme.js'`
- // from any component to read/toggle. Boot side-effects (apply current
- // theme to <body>/<html>) run once at module load so the page is in the
- // right theme before Vue mounts.
- const STORAGE_DARK = 'dark-mode';
- const STORAGE_ULTRA = 'isUltraDarkThemeEnabled';
- function readBool(key, fallback) {
- const raw = localStorage.getItem(key);
- if (raw === null) return fallback;
- return raw === 'true';
- }
- const isDark = readBool(STORAGE_DARK, true);
- const isUltra = readBool(STORAGE_ULTRA, true);
- export const theme = reactive({
- isDark,
- isUltra,
- });
- export const currentTheme = computed(() => (theme.isDark ? 'dark' : 'light'));
- // AD-Vue 4 theme config consumed by every page's <a-config-provider>.
- // Three modes — light / dark / ultra-dark — all share AD-Vue's vanilla
- // blue primary. Dark uses a neutral grey palette modelled on VS Code's
- // Dark+ chrome (`#1e1e1e` editor, `#252526` sidebar, `#2d2d30` panel),
- // so the panel reads as a familiar modern IDE rather than the older
- // navy shade. Ultra-dark stays pure-black on darkAlgorithm.
- const DARK_TOKENS = {
- colorBgBase: '#1e1e1e',
- colorBgLayout: '#1e1e1e',
- colorBgContainer: '#252526',
- colorBgElevated: '#2d2d30',
- };
- const ULTRA_DARK_TOKENS = {
- colorBgBase: '#000',
- colorBgLayout: '#000',
- colorBgContainer: '#0a0a0a',
- colorBgElevated: '#141414',
- };
- // AD-Vue 4 hardcodes navy `#001529` / `#002140` as the Layout sider
- // + trigger backgrounds and `#001529` / `#000c17` as the dark Menu item
- // backgrounds (see node_modules/ant-design-vue/es/{layout,menu}/style/
- // index.js). Override at the component-token level so the sider blends
- // with darkAlgorithm's neutral surfaces. Sider/trigger use the same
- // `#252526` / `#333333` tones VS Code does for its activity bar.
- const DARK_LAYOUT_TOKENS = {
- colorBgHeader: '#252526',
- colorBgTrigger: '#333333',
- colorBgBody: '#1e1e1e',
- };
- const ULTRA_DARK_LAYOUT_TOKENS = {
- colorBgHeader: '#0a0a0a',
- colorBgTrigger: '#141414',
- colorBgBody: '#000',
- };
- const DARK_MENU_TOKENS = {
- colorItemBg: '#252526',
- colorSubItemBg: '#1e1e1e',
- menuSubMenuBg: '#252526',
- };
- const ULTRA_DARK_MENU_TOKENS = {
- colorItemBg: '#0a0a0a',
- colorSubItemBg: '#000',
- menuSubMenuBg: '#0a0a0a',
- };
- export const antdThemeConfig = computed(() => {
- if (!theme.isDark) {
- return { algorithm: antdTheme.defaultAlgorithm };
- }
- return {
- algorithm: antdTheme.darkAlgorithm,
- token: theme.isUltra ? ULTRA_DARK_TOKENS : DARK_TOKENS,
- components: {
- Layout: theme.isUltra ? ULTRA_DARK_LAYOUT_TOKENS : DARK_LAYOUT_TOKENS,
- Menu: theme.isUltra ? ULTRA_DARK_MENU_TOKENS : DARK_MENU_TOKENS,
- },
- };
- });
- export function toggleTheme() {
- theme.isDark = !theme.isDark;
- }
- export function toggleUltra() {
- theme.isUltra = !theme.isUltra;
- }
- // Briefly disable theme transition animations while a toggle is in
- // flight, then re-enable on mouseleave. Mirrors the legacy panel's
- // behavior of preventing flicker when hovering the theme menu.
- export function pauseAnimationsUntilLeave(elementId) {
- document.documentElement.setAttribute('data-theme-animations', 'off');
- const el = document.getElementById(elementId);
- if (!el) return;
- const restore = () => {
- document.documentElement.removeAttribute('data-theme-animations');
- el.removeEventListener('mouseleave', restore);
- el.removeEventListener('touchend', restore);
- };
- el.addEventListener('mouseleave', restore);
- el.addEventListener('touchend', restore);
- }
- // Apply theme to DOM and persist whenever it changes.
- watchEffect(() => {
- document.body.setAttribute('class', theme.isDark ? 'dark' : 'light');
- localStorage.setItem(STORAGE_DARK, String(theme.isDark));
- if (theme.isUltra) {
- document.documentElement.setAttribute('data-theme', 'ultra-dark');
- } else {
- document.documentElement.removeAttribute('data-theme');
- }
- localStorage.setItem(STORAGE_ULTRA, String(theme.isUltra));
- // Keep the global #message container's class in sync so AD-Vue toasts
- // pick up the right styling.
- const msg = document.getElementById('message');
- if (msg) msg.className = theme.isDark ? 'dark' : 'light';
- });
|