Skip to content

Themes & Styling

import { Tabs, TabItem } from ‘@astrojs/starlight/components’;

dicechess-analytics-ui uses Tailwind CSS v4 coupled with CSS Custom Properties to implement a high-performance, themeable, and premium UI.


Select a theme tab below to see how the platform looks in different styles.

![Dark Theme](/dicechess-analytics-ui/assets/themes/dark.png) ![Light Theme](/dicechess-analytics-ui/assets/themes/light.png) ![Dracula Theme](/dicechess-analytics-ui/assets/themes/dracula.png) ![Nord Theme](/dicechess-analytics-ui/assets/themes/nord.png) ![Solarized Theme](/dicechess-analytics-ui/assets/themes/solarized-dark.png) ![Tokyo Night Theme](/dicechess-analytics-ui/assets/themes/tokyo-night.png) ![Gruvbox Theme](/dicechess-analytics-ui/assets/themes/gruvbox.png)

In Tailwind v4, theme tokens are defined directly inside CSS using the @theme directive in src/app.css.

These tokens are mapped to CSS Custom Properties (variables) that change dynamically depending on the active data-theme attribute on the <html> root element.

@theme {
/* Semantic Status Tokens (theme-aware) */
--color-danger: var(--danger);
--color-badge-accent: var(--badge-accent);
/* Theme Mapping */
--color-background: var(--bg-app);
--color-surface: var(--bg-surface);
--color-surface-hover: var(--bg-surface-hover);
--color-border: var(--border-subtle);
--color-border-strong: var(--border-strong);
--color-content: var(--text-primary);
--color-content-muted: var(--text-muted);
--color-primary: var(--accent);
--color-primary-hover: var(--accent-hover);
--color-primary-content: var(--accent-content, #ffffff);
/* Fixed Domain Tokens */
--color-piece-white: #ffffff;
--color-piece-black: #1e293b;
--color-dice-surface: var(--bg-dice);
}

Each custom theme defines concrete values for the semantic variables in src/app.css. For example, the Tokyo Night and Gruvbox themes configure colors like this:

[data-theme='tokyo-night'] {
--bg-app: #1a1b26;
--bg-surface: #24283b;
--bg-surface-hover: #2f334d;
--border-subtle: #414868;
--border-strong: #7aa2f7;
--text-primary: #a9b1d6;
--text-muted: #565f89;
--accent: #7aa2f7;
--accent-hover: #bb9af7;
--accent-content: #1a1b26;
--bg-dice: #414868;
}
[data-theme='gruvbox'] {
--bg-app: #282828;
--bg-surface: #3c3836;
--bg-surface-hover: #504945;
--border-subtle: #665c54;
--border-strong: #d5c4a1;
--text-primary: #ebdbb2;
--text-muted: #a89984;
--accent: #fe8019;
--accent-hover: #fabd2f;
--accent-content: #282828;
--bg-dice: #665c54;
}

The active theme state is managed reactively via themeStore.svelte.ts.

  • Default Detection: Automatically detects user system preferences via window.matchMedia('(prefers-color-scheme: light)') if no theme is saved.
  • Persistent Cache: Keeps theme preference cached locally via localStorage (key: dicechess-theme).
  • DOM Modification: Updates the data-theme attribute on document.documentElement and synchronizes the browser tab’s theme color via the <meta name="theme-color"> header.
class ThemeStore {
theme = $state<Theme>('dark');
setTheme(newTheme: Theme) {
this.theme = newTheme;
if (typeof window !== 'undefined') {
try {
localStorage.setItem('dicechess-theme', newTheme);
} catch (_e) {
// Ignored
}
this.applyTheme(newTheme);
}
}
private applyTheme(theme: Theme) {
if (typeof document !== 'undefined') {
document.documentElement.setAttribute('data-theme', theme);
const metaTag = document.getElementById('theme-color-meta');
if (metaTag && metaColors[theme]) {
metaTag.setAttribute('content', metaColors[theme]);
}
}
}
}