Theming System
A centralized design system that lets you customize all colors across the admin panel and public site with minimal configuration. Changes apply automatically to all components including Sonner toasts, forms, cards, and more.
Quick Start
Customizing Colors
Edit config/theme.ts:
export const themeConfig = {
admin: {
primary: {
light: 'indigo', // Change to 'blue', 'violet', 'emerald', etc.
dark: 'indigo',
},
background: {
light: 'slate', // Change to 'gray', 'zinc', 'stone', etc.
dark: 'slate',
},
neutral: {
light: 'slate', // For text/borders
dark: 'slate',
},
},
site: {
primary: {
light: 'violet', // Different from admin!
dark: 'violet',
},
background: {
light: 'stone',
dark: 'stone',
},
neutral: {
light: 'stone',
dark: 'stone',
},
},
}
Available Colors:
slate, gray, zinc, neutral, stone, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose
What Gets Themed?
✅ All admin pages (dashboard, post editor, etc.) ✅ All site pages (homepage, post views, etc.) ✅ Sonner toast notifications ✅ All form components ✅ Cards, modals, dialogs ✅ Buttons and links ✅ Borders and dividers ✅ Automatically adapts to light/dark mode
How It Works
1. Theme Detection
URL-based automatic detection:
/admin/*→ Admin theme (indigo + slate by default)Everything else → Site theme (violet + stone by default)
2. CSS Variables
Themes defined in inertia/css/app.css:
[data-theme='admin'] {
--color-standout: var(--color-indigo-600);
--color-neutral-high: var(--color-slate-900);
--color-backdrop-low: var(--color-slate-50);
}
[data-theme='site'] {
--color-standout: var(--color-violet-600);
--color-neutral-high: var(--color-stone-900);
--color-backdrop-low: var(--color-stone-50);
}
3. Tailwind Integration
Use the named color tokens:
bg-standout,text-on-hightext-neutral-{low|medium|high}bg-backdrop-{low|medium|high}border-line
Adonis EOS uses a design token system built on Tailwind CSS for consistent, customizable theming.
Design System
The theme is defined in inertia/css/app.css using CSS custom properties.
Color Tokens
Contrast Levels
The system uses a naming convention based on contrast levels rather than fixed color values. This allows for a seamless convention between light and dark site modes, as the meaning of "low contrast" or "high contrast" remains consistent even when the actual colors flip:
low: Low contrast against the primary surface. Typically used for the base background or subtle elements.
medium: Medium contrast. Used for elevated surfaces, secondary buttons, or supporting text.
high: High contrast. Used for primary text (headings), important borders, or prominent UI elements.
Semantic Colors
--backdrop-low /* Base background (Low contrast) */
--backdrop-medium /* Secondary background (Medium contrast) */
--backdrop-high /* Elevated surfaces (High contrast) */
--line /* Borders and dividers */
--neutral-low /* Subtle text (Low contrast) */
--neutral-medium /* Body text (Medium contrast) */
--neutral-high /* Headings (High contrast) */
--standout /* Primary action background */
--on-high /* Text/Icons on high-contrast backgrounds (like standout) */
--accent /* Secondary action background */
--on-accent /* Text/Icons on accent background */
Usage
These tokens are available as Tailwind classes:
<div className="bg-backdrop-low border-line">
<h1 className="text-neutral-high">Heading</h1>
<p className="text-neutral-medium">Body text</p>
<button className="bg-standout text-on-high">Action</button>
</div>
Dark Mode
Dark mode is automatically handled via CSS custom properties. The system adapts based on prefers-color-scheme.
Media Variants
Images can have separate dark mode versions:
# Upload base image
demo-logo.png
# Generate dark variant (automatically tinted)
POST /api/media/:id/variants { "theme": "dark" }
# Override with custom dark image
POST /api/media/:id/override { "theme": "dark", file: ... }
Configure dark mode adjustments:
# .env
MEDIA_DARK_BRIGHTNESS=0.8 # 0-1, lower = darker
MEDIA_DARK_SATURATION=0.7 # 0-1, lower = desaturated
Typography
Font configuration in tailwind.config.ts:
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
serif: ['Georgia', 'serif'],
mono: ['Monaco', 'monospace']
}
}
}
Use in components:
<h1 className="font-sans">Sans-serif heading</h1>
<blockquote className="font-serif">Serif quote</blockquote>
<code className="font-mono">Monospace code</code>
Spacing
Consistent spacing scale:
p-2- 0.5rem (8px)p-4- 1rem (16px)p-6- 1.5rem (24px)p-8- 2rem (32px)p-12- 3rem (48px)
Breakpoints
Responsive design breakpoints:
sm:- 640px (mobile)md:- 768px (tablet)lg:- 1024px (desktop)xl:- 1280px (large desktop)2xl:- 1536px (extra large)
Customizing Themes
1. Update CSS Variables
Edit inertia/css/app.css:
:root {
--standout: 220 90% 56%; /* HSL values */
--on-high: 0 0% 100%;
}
@media (prefers-color-scheme: dark) {
:root {
--standout: 220 85% 65%;
--on-high: 220 20% 10%;
}
}
2. Extend Tailwind Config
Add custom utilities in tailwind.config.ts:
theme: {
extend: {
colors: {
brand: {
primary: 'hsl(var(--standout))',
secondary: 'hsl(var(--accent))'
}
}
}
}
3. Module Background Options
Modules support background customization:
{
"props": {
"backgroundColor": "bg-backdrop-medium"
}
}
Available options:
bg-backdrop-low(default)bg-backdrop-mediumbg-backdrop-highbg-transparent
Logo Management
Upload light and dark logos in /admin/settings:
Light Logo: Used in light mode
Dark Logo: Used in dark mode
Logos are automatically swapped based on theme.
Best Practices
Use semantic tokens instead of hardcoded colors
Test both themes when building custom components
Provide fallbacks for older browsers
Optimize images for both light and dark modes
Maintain contrast for accessibility (WCAG AA)
Using Themes in Components
// ✅ DO: Use the simplified tokens (Tailwind color names backed by CSS vars)
<div className="bg-backdrop-low border border-line-low rounded">
<h1 className="text-neutral-high">Title</h1>
<p className="text-neutral-low">Description</p>
<button className="bg-standout text-on-high rounded px-3 py-2">
Click Me
</button>
</div>
// ❌ DON'T: Hardcode specific colors or numbered classes
<div className="bg-slate-50 text-slate-900">
<button className="bg-indigo-600">Click</button>
</div>
Testing Themes
# 1. View admin theme
http://localhost:3333/admin
# 2. View site theme
http://localhost:3333/
# 3. Toggle dark mode (browser console)
localStorage.setItem('theme-mode', 'dark')
location.reload()
localStorage.setItem('theme-mode', 'light')
location.reload()
Current Default Theme
Admin: Professional, clean (Indigo + Slate) Site: Brand-focused, elegant (Violet + Stone)
Both support automatic light/dark mode and can be changed instantly by editing one file!
Resources
Advanced theming rules:
.cursor/rules/theming.md