RSS Git Download  Clone
Raw Blame History 3kB 101 lines
import { defineStore } from 'pinia'
import { ref } from 'vue'

// Theme classification -- matches React themes/index.ts
export const DARK_THEMES = ['dark', 'darkNeu', 'darkoBluo', 'matrix']
export const LIGHT_THEMES = ['light', 'enterprise', 'redis']
export const ALL_THEME_KEYS = ['light', 'enterprise', 'dark', 'darkNeu', 'darkoBluo', 'matrix', 'redis']

export function isDarkTheme(key: string): boolean {
    return DARK_THEMES.includes(key)
}

const STORAGE_KEY = 'p3xr-theme'
const AUTO = 'auto'

function getSystemDark(): boolean {
    return typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches
}

function normalizeThemeKey(raw: string): string {
    // Handle Angular format: p3xrThemeDark -> dark, p3xrThemeEnterprise -> enterprise
    if (raw.startsWith('p3xrTheme')) {
        const name = raw.replace('p3xrTheme', '')
        return name.charAt(0).toLowerCase() + name.slice(1)
    }
    return raw
}

function readStored(): string {
    try {
        const raw = localStorage.getItem(STORAGE_KEY) || AUTO
        if (raw === AUTO) return AUTO
        return normalizeThemeKey(raw)
    } catch { return AUTO }
}

function applyBodyClasses(resolved: string): void {
    if (typeof document === 'undefined') return
    const dark = isDarkTheme(resolved)
    const scheme = dark ? 'dark' : 'light'
    document.documentElement.setAttribute('data-color-scheme', scheme)
    document.documentElement.style.colorScheme = scheme
    document.body.style.colorScheme = scheme
    document.body.classList.toggle('p3xr-theme-dark', dark)
    document.body.classList.toggle('p3xr-theme-light', !dark)
    // Update the <meta name="color-scheme"> tag set in index.html
    const meta = document.querySelector('meta[name="color-scheme"]') as HTMLMetaElement
    if (meta) meta.content = scheme
}

// Same logic as Angular ThemeService
function resolveThemeKey(stored: string): string {
    if (stored === AUTO) return getSystemDark() ? 'dark' : 'enterprise'
    return stored
}

export const useThemeStore = defineStore('theme', () => {
    const stored = readStored()
    const isAuto = ref(stored === AUTO)
    const themeKey = ref(resolveThemeKey(stored))
    const storedValue = ref(stored)

    // Apply on initial load
    applyBodyClasses(themeKey.value)

    function setTheme(choice: string) {
        const auto = choice === AUTO
        const resolved = auto ? resolveThemeKey(AUTO) : choice
        try { localStorage.setItem(STORAGE_KEY, choice) } catch {}

        applyBodyClasses(resolved)

        // Notify Electron parent
        try {
            window.parent?.postMessage({ type: 'p3x-theme-change', dark: isDarkTheme(resolved) }, '*')
        } catch {}

        isAuto.value = auto
        themeKey.value = resolved
        storedValue.value = choice
    }

    // Listen for system theme changes (auto mode)
    if (typeof window !== 'undefined' && window.matchMedia) {
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
            if (isAuto.value) {
                const resolved = getSystemDark() ? 'dark' : 'enterprise'
                applyBodyClasses(resolved)
                themeKey.value = resolved
            }
        })
    }

    return {
        isAuto,
        themeKey,
        storedValue,
        setTheme,
    }
})