feat(theme): dynamic CSS custom properties for presets, light/dark mode and individual color overrides
All checks were successful
Production Build & Deploy / build-and-deploy (push) Successful in 49s

This commit is contained in:
Daniel S
2026-08-09 23:02:21 +02:00
parent 30b407d2e8
commit 4355bb8406
3 changed files with 43 additions and 5 deletions

View File

@@ -20,7 +20,10 @@ interface Props {
const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('user-agent') ?? ''); const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('user-agent') ?? '');
const activePreset = THEME_PRESETS[themeConfig.activePreset] || THEME_PRESETS.corporateDark; const activePreset = THEME_PRESETS[themeConfig.activePreset] || THEME_PRESETS.corporateDark;
const colors = activePreset.colors; const colors = {
...activePreset.colors,
...(themeConfig.customColors || {})
};
const { title, description = "Professionelles Webdesign & moderne Websites.", ogImage } = Astro.props; const { title, description = "Professionelles Webdesign & moderne Websites.", ogImage } = Astro.props;
@@ -54,10 +57,11 @@ const { title, description = "Professionelles Webdesign & moderne Websites.", og
html.light { html.light {
--theme-bg: #F8FAFC; --theme-bg: #F8FAFC;
--theme-card-bg: rgba(255, 255, 255, 0.7); --theme-card-bg: rgba(255, 255, 255, 0.85);
--theme-text: #0F172A; --theme-text: #0F172A;
--theme-border: rgba(0, 0, 0, 0.1); --theme-border: rgba(0, 0, 0, 0.1);
} }
</style> </style>
<!-- Inline theme initialization to prevent FOUC --> <!-- Inline theme initialization to prevent FOUC -->

View File

@@ -154,12 +154,12 @@ const presets = Object.values(THEME_PRESETS);
<!-- Sidebar Column --> <!-- Sidebar Column -->
<div class="space-y-8"> <div class="space-y-8">
<!-- Theme Preset Picker --> <!-- Theme Preset Picker & Custom Colors -->
<div class="glass-panel rounded-2xl p-6 space-y-4"> <div class="glass-panel rounded-2xl p-6 space-y-4">
<h2 class="text-lg font-bold text-sky-400 uppercase tracking-wider flex items-center gap-2"> <h2 class="text-lg font-bold text-sky-400 uppercase tracking-wider flex items-center gap-2">
Theme Preset (10 Styles) Theme Preset (10 Styles)
</h2> </h2>
<div class="space-y-2 max-h-[320px] overflow-y-auto pr-1"> <div class="space-y-2 max-h-[220px] overflow-y-auto pr-1">
{presets.map((p) => ( {presets.map((p) => (
<label class={`flex items-center justify-between p-3 rounded-xl border transition-all cursor-pointer ${themeConfig.activePreset === p.id ? 'border-sky-400 bg-sky-400/10' : 'border-white/5 hover:border-white/20 bg-slate-950/40'}`}> <label class={`flex items-center justify-between p-3 rounded-xl border transition-all cursor-pointer ${themeConfig.activePreset === p.id ? 'border-sky-400 bg-sky-400/10' : 'border-white/5 hover:border-white/20 bg-slate-950/40'}`}>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
@@ -173,7 +173,30 @@ const presets = Object.values(THEME_PRESETS);
</label> </label>
))} ))}
</div> </div>
<!-- Custom Colors Section -->
<h3 class="text-xs font-bold text-slate-400 uppercase tracking-wider pt-3 border-t border-white/10">Individuelle Farbvergabe (Overrides)</h3>
<p class="text-[10px] text-slate-400">Überschreibe hier gezielt einzelne Preset-Farben:</p>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<label class="block text-[10px] text-slate-400 mb-1">Hintergrund (Bg)</label>
<input type="color" id="customColorBg" value={themeConfig.customColors?.bg || (THEME_PRESETS[themeConfig.activePreset] || THEME_PRESETS.corporateDark).colors.bg} class="w-full h-8 rounded bg-slate-900 border border-white/10 cursor-pointer p-0.5" />
</div> </div>
<div>
<label class="block text-[10px] text-slate-400 mb-1">Akzentfarbe</label>
<input type="color" id="customColorAccent" value={themeConfig.customColors?.accent || (THEME_PRESETS[themeConfig.activePreset] || THEME_PRESETS.corporateDark).colors.accent} class="w-full h-8 rounded bg-slate-900 border border-white/10 cursor-pointer p-0.5" />
</div>
<div>
<label class="block text-[10px] text-slate-400 mb-1">Textfarbe</label>
<input type="color" id="customColorText" value={themeConfig.customColors?.text || (THEME_PRESETS[themeConfig.activePreset] || THEME_PRESETS.corporateDark).colors.text} class="w-full h-8 rounded bg-slate-900 border border-white/10 cursor-pointer p-0.5" />
</div>
<div>
<label class="block text-[10px] text-slate-400 mb-1">Rahmenfarbe (Border)</label>
<input type="text" id="customColorBorder" value={themeConfig.customColors?.border || ''} placeholder="rgba(255,255,255,0.1)" class="w-full h-8 rounded bg-slate-900 border border-white/10 text-[10px] px-2 text-white" />
</div>
</div>
</div>
<!-- SMTP Config --> <!-- SMTP Config -->
<div class="glass-panel rounded-3xl p-6 space-y-4"> <div class="glass-panel rounded-3xl p-6 space-y-4">
@@ -258,8 +281,15 @@ const presets = Object.values(THEME_PRESETS);
themeConfig: { themeConfig: {
activePreset: selectedPreset activePreset: selectedPreset,
customColors: {
bg: getVal('customColorBg'),
accent: getVal('customColorAccent'),
text: getVal('customColorText'),
border: getVal('customColorBorder')
}
}, },
smtpConfig: { smtpConfig: {
host: getVal('smtpHost'), host: getVal('smtpHost'),
port: getNum('smtpPort'), port: getNum('smtpPort'),

View File

@@ -100,10 +100,14 @@ export interface ThemeConfig {
glassBorderRadius?: string; // 'rounded-lg' | 'rounded-xl' | 'rounded-2xl' glassBorderRadius?: string; // 'rounded-lg' | 'rounded-xl' | 'rounded-2xl'
customColors?: { customColors?: {
bg?: string; bg?: string;
cardBg?: string;
text?: string;
accent?: string; accent?: string;
border?: string;
}; };
} }
export interface SmtpConfig { export interface SmtpConfig {
host: string; host: string;
port: number; port: number;