diff --git a/web-app/src/containers/ColorPickerAppBgColor.tsx b/web-app/src/containers/ColorPickerAppBgColor.tsx
index 36566d03b..c60b34f13 100644
--- a/web-app/src/containers/ColorPickerAppBgColor.tsx
+++ b/web-app/src/containers/ColorPickerAppBgColor.tsx
@@ -1,4 +1,4 @@
-import { useAppearance, isDefaultColor, useBlurSupport } from '@/hooks/useAppearance'
+import { useAppearance, useBlurSupport } from '@/hooks/useAppearance'
import { cn } from '@/lib/utils'
import { RgbaColor, RgbaColorPicker } from 'react-colorful'
import { IconColorPicker } from '@tabler/icons-react'
@@ -62,6 +62,15 @@ export function ColorPickerAppBgColor() {
},
]
+ // Check if a color is the default color (considering both dark and light themes)
+ const isColorDefault = (color: RgbaColor): boolean => {
+ const isDarkDefault = color.r === 25 && color.g === 25 && color.b === 25
+ const isLightDefault = color.r === 255 && color.g === 255 && color.b === 255
+ // Accept both 0.4 and 1 as valid default alpha values (handles blur detection timing)
+ const hasDefaultAlpha = Math.abs(color.a - 0.4) < 0.01 || Math.abs(color.a - 1) < 0.01
+ return (isDarkDefault || isLightDefault) && hasDefaultAlpha
+ }
+
return (
{predefineAppBgColor.map((item, i) => {
@@ -69,13 +78,13 @@ export function ColorPickerAppBgColor() {
(item.r === appBgColor.r &&
item.g === appBgColor.g &&
item.b === appBgColor.b &&
- item.a === appBgColor.a) ||
- (isDefaultColor(appBgColor) && isDefaultColor(item))
+ Math.abs(item.a - appBgColor.a) < 0.01) ||
+ (isColorDefault(appBgColor) && isColorDefault(item))
return (
{
diff --git a/web-app/src/hooks/useAppearance.ts b/web-app/src/hooks/useAppearance.ts
index 874c8ae84..1d422d90f 100644
--- a/web-app/src/hooks/useAppearance.ts
+++ b/web-app/src/hooks/useAppearance.ts
@@ -109,10 +109,14 @@ const isColorEqual = (color1: RgbaColor, color2: RgbaColor): boolean => {
// Helper function to check if color is default (not customized)
export const isDefaultColor = (color: RgbaColor): boolean => {
- return (
- isColorEqual(color, defaultAppBgColor) ||
- isColorEqual(color, defaultLightAppBgColor)
- )
+ // Check if RGB matches default (ignore alpha since it changes based on blur support)
+ const isDarkDefault = color.r === 25 && color.g === 25 && color.b === 25
+ const isLightDefault = color.r === 255 && color.g === 255 && color.b === 255
+
+ // Consider it default if RGB matches and alpha is either 0.4 or 1 (common values)
+ const hasDefaultAlpha = Math.abs(color.a - 0.4) < 0.01 || Math.abs(color.a - 1) < 0.01
+
+ return (isDarkDefault || isLightDefault) && hasDefaultAlpha
}
export const isDefaultColorMainView = (color: RgbaColor): boolean => {
@@ -213,8 +217,11 @@ export const useAppearance = create
()(
defaultFontSize
)
- // Reset app background color
- const defaultBg = isDark ? defaultAppBgColor : defaultLightAppBgColor
+ // Reset app background color with correct alpha based on blur support
+ const currentAlpha = blurEffectsSupported && IS_TAURI ? 0.4 : 1
+ const defaultBg = isDark
+ ? { r: 25, g: 25, b: 25, a: currentAlpha }
+ : { r: 255, g: 255, b: 255, a: currentAlpha }
const culoriRgbBg = rgb({
mode: 'rgb',
r: defaultBg.r / 255,
@@ -351,12 +358,11 @@ export const useAppearance = create()(
// If color is being set to default, use theme-appropriate default
let finalColor = color
if (isDefaultColor(color)) {
- finalColor = isDark ? defaultAppBgColor : defaultLightAppBgColor
- }
-
- // Force alpha to 1 if blur effects are not supported
- if (!blurEffectsSupported && (IS_WINDOWS || IS_LINUX || !IS_TAURI)) {
- finalColor = { ...finalColor, a: 1 }
+ // Use current blur support state to determine alpha
+ const currentAlpha = blurEffectsSupported && IS_TAURI ? 0.4 : 1
+ finalColor = isDark
+ ? { r: 25, g: 25, b: 25, a: currentAlpha }
+ : { r: 255, g: 255, b: 255, a: currentAlpha }
}
// Convert RGBA to a format culori can work with
@@ -629,11 +635,9 @@ export const useAppearance = create()(
// Get the current theme state
const { isDark } = useTheme.getState()
- // If stored color is default, use theme-appropriate default
- let finalColor = state.appBgColor
- if (isDefaultColor(state.appBgColor)) {
- finalColor = isDark ? defaultAppBgColor : defaultLightAppBgColor
- }
+ // Just use the stored color as-is during rehydration
+ // The AppearanceProvider will handle alpha normalization after blur detection
+ const finalColor = state.appBgColor
let finalColorMainView = state.appMainViewBgColor
if (isDefaultColorMainView(state.appMainViewBgColor)) {
diff --git a/web-app/src/providers/AppearanceProvider.tsx b/web-app/src/providers/AppearanceProvider.tsx
index 70c9a881f..290c42231 100644
--- a/web-app/src/providers/AppearanceProvider.tsx
+++ b/web-app/src/providers/AppearanceProvider.tsx
@@ -31,6 +31,28 @@ export function AppearanceProvider() {
const { isDark } = useTheme()
const showAlphaSlider = useBlurSupport()
+ // Force re-apply appearance on mount to fix theme desync issues on Windows
+ // This ensures that when navigating to routes (like logs), the theme is properly applied
+ useEffect(() => {
+ const {
+ setAppBgColor,
+ setAppMainViewBgColor,
+ appBgColor,
+ appMainViewBgColor,
+ } = useAppearance.getState()
+
+ // Re-trigger setters to ensure CSS variables are applied with correct theme
+ setAppBgColor(appBgColor)
+ setAppMainViewBgColor(appMainViewBgColor)
+ }, []) // Run once on mount
+
+ // Update colors when blur support changes (important for Windows/Linux)
+ useEffect(() => {
+ const { setAppBgColor, appBgColor } = useAppearance.getState()
+ // Re-apply color to update alpha based on blur support
+ setAppBgColor(appBgColor)
+ }, [showAlphaSlider])
+
// Apply appearance settings on mount and when they change
useEffect(() => {
// Apply font size
@@ -197,6 +219,10 @@ export function AppearanceProvider() {
setAppDestructiveBgColor,
} = useAppearance.getState()
+ // Force re-apply all colors when theme changes to ensure correct dark/light defaults
+ // This is especially important on Windows where the theme might not be properly
+ // synchronized when navigating to different routes (e.g., logs page)
+
// If using default background color, update it when theme changes
if (isDefaultColor(appBgColor)) {
// This will trigger the appropriate updates for both background and text color