useUIClient,
} from './providers.js'
export {
+ deleteFromLocalStorage,
deleteLocalStorageByKeyPattern,
getFromLocalStorage,
getLocalStorage,
export const DEFAULT_THEME: ThemeName = 'tokyo-night-storm'
export const THEME_STORAGE_KEY = 'ecs-ui-theme'
+const THEME_COLOR_SCHEME: Record<ThemeName, 'dark' | 'light'> = {
+ 'catppuccin-latte': 'light',
+ dracula: 'dark',
+ 'gruvbox-dark': 'dark',
+ 'rose-pine': 'dark',
+ 'sap-horizon': 'light',
+ 'teal-dark': 'dark',
+ 'teal-light': 'light',
+ 'tokyo-night-storm': 'dark',
+}
+
export type ThemeName = (typeof THEME_IDS)[number]
/**
const lastError: Ref<null | string> = ref(null)
/**
- * Applies a theme by setting the data-theme attribute on the document root.
+ * Applies a theme by setting data-theme and data-color-scheme attributes on the document root.
* Disables CSS transitions during the swap to prevent color flash (VueUse pattern).
- * The color-scheme is handled by CSS [data-theme] declarations.
* @param themeName - The theme name to apply
*/
function applyTheme (themeName: ThemeName): void {
// Disable CSS transitions during theme swap to prevent color flash (VueUse pattern).
document.documentElement.classList.add('theme-switching')
document.documentElement.setAttribute('data-theme', themeName)
+ document.documentElement.setAttribute('data-color-scheme', THEME_COLOR_SCHEME[themeName])
// Force reflow so browsers apply the transition-disable before restoring transitions.
// eslint-disable-next-line no-void
void document.documentElement.offsetHeight
import { useSimulatorControl } from '@/shared/composables/useSimulatorControl.js'
import ConfirmDialog from './components/ConfirmDialog.vue'
+import SimulatorBar from './components/SimulatorBar.vue'
+import StationCard from './components/StationCard.vue'
/**
* Creates a lazy-loaded dialog component with shared loading/error boundaries.
const StartTransactionDialog = defineAsyncDialog(
() => import('./components/dialogs/StartTransactionDialog.vue')
)
-import SimulatorBar from './components/SimulatorBar.vue'
-import StationCard from './components/StationCard.vue'
const $chargingStations = useChargingStations()
/* Light-theme pill overrides — state colours are already dark (Material 700)
* and readable on light backgrounds without white mixing. */
-:root[data-theme='catppuccin-latte'] .modern-pill--ok,
-:root[data-theme='sap-horizon'] .modern-pill--ok,
-:root[data-theme='teal-light'] .modern-pill--ok {
+:root[data-color-scheme='light'] .modern-pill--ok {
color: var(--color-state-ok);
background-color: color-mix(in srgb, var(--color-state-ok) 14%, transparent);
border-color: color-mix(in srgb, var(--color-state-ok) 35%, transparent);
}
-:root[data-theme='catppuccin-latte'] .modern-pill--warn,
-:root[data-theme='sap-horizon'] .modern-pill--warn,
-:root[data-theme='teal-light'] .modern-pill--warn {
+:root[data-color-scheme='light'] .modern-pill--warn {
color: var(--color-state-warn);
background-color: color-mix(in srgb, var(--color-state-warn) 18%, transparent);
border-color: color-mix(in srgb, var(--color-state-warn) 50%, transparent);
}
-:root[data-theme='catppuccin-latte'] .modern-pill--err,
-:root[data-theme='sap-horizon'] .modern-pill--err,
-:root[data-theme='teal-light'] .modern-pill--err {
+:root[data-color-scheme='light'] .modern-pill--err {
color: var(--color-state-err);
background-color: color-mix(in srgb, var(--color-state-err) 14%, transparent);
border-color: color-mix(in srgb, var(--color-state-err) 35%, transparent);
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
+ deleteFromLocalStorage,
getFromLocalStorage,
getLocalStorage,
resetToggleButtonState,
useConfiguration,
useTemplates,
} from '@/core/index.js'
-import { deleteFromLocalStorage } from '@/core/storage.js'
import { useFetchData } from '@/shared/composables/useFetchData.js'
import { toastMock } from '../setup.js'