diff --git a/server.ts b/server.ts index 6bfa6e3..7d01e5b 100644 --- a/server.ts +++ b/server.ts @@ -129,10 +129,19 @@ function buildConfigScript(config: StationConfig): string { return ``; } +/** Build a gradient CSS value from three color stops. */ +function gradient(from: string, mid: string, to: string): string { + return `linear-gradient(135deg, ${from} 0%, ${mid} 40%, ${to} 100%)`; +} + /** * Build inline CSS custom properties on `:root` so the first paint carries * the correct color scheme — eliminates the color flash that occurs when * ThemeService.apply() runs asynchronously after the API call. + * + * Includes both flat color properties AND derived gradient variables + * (--sky-gradient, --sunset-gradient, --mixed-gradient) so components + * using var() for backgrounds render correctly on the very first paint. */ function buildThemeStyle(config: StationConfig): string { const props: string[] = []; @@ -144,6 +153,15 @@ function buildThemeStyle(config: StationConfig): string { } } + // Derived gradients — mirror the same formulas ThemeService.apply() uses. + // These must be injected server-side; otherwise components referencing + // var(--sky-gradient) etc. fall back to their SCSS build-time defaults + // on first paint, causing a visible color flash. + const cp = (field: keyof StationConfig): string => (config as any)[field] || ''; + props.push(`--sky-gradient: ${gradient(cp('color_primary_dark'), cp('color_primary'), cp('color_primary_light'))}`); + props.push(`--sunset-gradient: ${gradient(cp('color_accent_dark'), cp('color_accent'), cp('color_accent_light'))}`); + props.push(`--mixed-gradient: linear-gradient(135deg, ${cp('color_primary_dark')} 0%, ${cp('color_primary')} 50%, ${cp('color_accent')} 100%)`); + if (props.length === 0) return ''; const css = `:root{${props.join(';')}}`; diff --git a/src/app/about/about.component.scss b/src/app/about/about.component.scss index 2e38f57..bcb91b2 100644 --- a/src/app/about/about.component.scss +++ b/src/app/about/about.component.scss @@ -213,7 +213,7 @@ .about-cta { text-align: center; padding: $spacing-2xl $spacing-lg; - background: $mixed-gradient; + background: var(--mixed-gradient); border-radius: $radius-xl; color: var(--color-white); diff --git a/src/app/events/events.component.scss b/src/app/events/events.component.scss index 7e0a16f..5fa4529 100644 --- a/src/app/events/events.component.scss +++ b/src/app/events/events.component.scss @@ -34,7 +34,7 @@ .event-date { flex-shrink: 0; - background: $mixed-gradient; + background: var(--mixed-gradient); color: var(--color-white); display: flex; flex-direction: column; diff --git a/src/app/login/login.component.scss b/src/app/login/login.component.scss index b74bb98..dea9a2f 100644 --- a/src/app/login/login.component.scss +++ b/src/app/login/login.component.scss @@ -4,7 +4,7 @@ .login-section { @include flex-center; min-height: calc(100vh - 80px); - background: $sky-gradient; + background: var(--sky-gradient); padding: $spacing-xl; } @@ -21,13 +21,13 @@ h1 { font-family: $font-heading; - color: $primary-blue; + color: var(--color-primary); margin: $spacing-sm 0 $spacing-xs; font-size: 1.75rem; } p { - color: $neutral-medium; + color: var(--color-medium); font-size: 0.9rem; } } @@ -49,14 +49,14 @@ display: block; font-size: 0.875rem; font-weight: 600; - color: $neutral-dark; + color: var(--color-dark); margin-bottom: $spacing-xs; } input { width: 100%; padding: $spacing-sm $spacing-md; - border: 1px solid $neutral-light; + border: 1px solid var(--color-light); border-radius: $radius-md; font-size: 1rem; transition: border-color $transition-fast; @@ -64,7 +64,7 @@ &:focus { outline: none; - border-color: $primary-blue; + border-color: var(--color-primary); box-shadow: 0 0 0 3px rgba($primary-blue, 0.15); } } @@ -72,7 +72,7 @@ .login-error { background: rgba($danger-red, 0.1); - color: $danger-red; + color: var(--color-danger); padding: $spacing-sm $spacing-md; border-radius: $radius-md; font-size: 0.875rem; @@ -81,7 +81,7 @@ } .btn-login { - @include button-style($primary-blue, $neutral-white, $primary-blue-light); + @include button-style(var(--color-primary), var(--color-white), var(--color-primary-light)); width: 100%; padding: $spacing-sm $spacing-lg; margin-top: $spacing-sm;