From 8ff2d4adf374fccfb3a15639d26a94143e0dc58b Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Mon, 22 Jun 2026 15:00:53 +0330 Subject: [PATCH] fix default --- src/components/background/AppBackground.tsx | 6 ++- .../background/PatternBackgroundProvider.tsx | 24 +++++++--- src/components/wrapper/PreferenceWrapper.tsx | 20 +++++++- src/lib/helpers/backgroundUtils.ts | 18 ++++++++ src/lib/helpers/themeBootScript.ts | 2 +- src/lib/helpers/themeCache.ts | 46 ++++++++++++++++++- 6 files changed, 105 insertions(+), 11 deletions(-) diff --git a/src/components/background/AppBackground.tsx b/src/components/background/AppBackground.tsx index eab0dda..f131485 100644 --- a/src/components/background/AppBackground.tsx +++ b/src/components/background/AppBackground.tsx @@ -1,6 +1,7 @@ "use client"; import { usePatternBackground } from "@/components/background/PatternBackgroundProvider"; +import usePreference from "@/hooks/helpers/usePreference"; import { THEME_BG_ELEMENT_ID } from "@/lib/helpers/themeCache"; import { useLayoutEffect } from "react"; @@ -8,11 +9,12 @@ const THEME_BG_IMG_ID = "cached-theme-bg-img"; const THEME_BG_OVERLAY_ID = "cached-theme-bg-overlay"; export default function AppBackground() { + const { state: nightMode } = usePreference("night-mode", false); const { isPattern, backgroundStyle, isCustomImage, customImageSettings } = usePatternBackground(); useLayoutEffect(() => { - if (!isPattern && !isCustomImage) { + if (nightMode || (!isPattern && !isCustomImage)) { document.getElementById(THEME_BG_ELEMENT_ID)?.remove(); return; } @@ -75,7 +77,7 @@ export default function AppBackground() { overlayLayer.style.backgroundColor = overlayOpacity > 0 ? `rgba(0,0,0,${overlayOpacity})` : ""; } - }, [backgroundStyle, isPattern, isCustomImage, customImageSettings]); + }, [backgroundStyle, isCustomImage, isPattern, customImageSettings, nightMode]); return null; } diff --git a/src/components/background/PatternBackgroundProvider.tsx b/src/components/background/PatternBackgroundProvider.tsx index 8e0dbcc..7fcb142 100644 --- a/src/components/background/PatternBackgroundProvider.tsx +++ b/src/components/background/PatternBackgroundProvider.tsx @@ -2,6 +2,7 @@ import { useGetAbout } from "@/app/[name]/(Main)/about/hooks/useAboutData"; import { + applyColorBackgroundCssVariables, applyCustomImageCssVariables, applyPatternCssVariables, clearCustomImageCssVariables, @@ -12,9 +13,11 @@ import { PATTERN_BACKGROUND_OPACITY, resolveBgType, } from "@/lib/helpers/backgroundUtils"; +import usePreference from "@/hooks/helpers/usePreference"; import { applyCachedThemeToDom, buildThemeCacheFromRestaurant, + clearRestaurantBackgroundOverrides, getThemeCache, removeCachedThemeBackground, setThemeCache, @@ -59,6 +62,7 @@ const PatternBackgroundContext = createContext({ export function PatternBackgroundProvider({ children }: { children: ReactNode }) { const { name: restaurantSlug } = useParams<{ name: string }>(); + const { state: nightMode } = usePreference("night-mode", false); const { data: aboutData } = useGetAbout(); const restaurant = aboutData?.data; const [hydratedCache, setHydratedCache] = useState(null); @@ -70,8 +74,8 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode }) ? resolveBgType(hydratedCache) : "color"; - const isPattern = bgType === "pattern"; - const isCustomImage = bgType === "custom"; + const isPattern = !nightMode && bgType === "pattern"; + const isCustomImage = !nightMode && bgType === "custom"; const menuColor = restaurant?.menuColor || hydratedCache?.menuColor || DEFAULT_MENU_COLOR; const baseTint = hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY); @@ -85,10 +89,10 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode }) if (!cached) return; applyCachedThemeToDom(cached); - if (cached.patternDataUrl) { + if (!nightMode && cached.patternDataUrl) { setPatternImageUrl(cached.patternDataUrl); } - }, [restaurantSlug]); + }, [nightMode, restaurantSlug]); useEffect(() => { if (!restaurantSlug) { @@ -99,16 +103,24 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode }) return; } + if (nightMode) { + clearPatternCssVariables(); + clearCustomImageCssVariables(); + clearRestaurantBackgroundOverrides(); + setPatternImageUrl(null); + return; + } + if (!restaurant) return; const themeBase = buildThemeCacheFromRestaurant(restaurant); const currentBgType = themeBase.bgType; if (currentBgType === "color") { - clearPatternCssVariables(); clearCustomImageCssVariables(); removeCachedThemeBackground(); setPatternImageUrl(null); + applyColorBackgroundCssVariables(menuColor); setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null }); return; } @@ -192,7 +204,7 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode }) return () => { cancelled = true; }; - }, [menuColor, restaurant, restaurantSlug]); + }, [menuColor, nightMode, restaurant, restaurantSlug]); const backgroundStyle = useMemo( () => ({ diff --git a/src/components/wrapper/PreferenceWrapper.tsx b/src/components/wrapper/PreferenceWrapper.tsx index c278070..99f8bd1 100644 --- a/src/components/wrapper/PreferenceWrapper.tsx +++ b/src/components/wrapper/PreferenceWrapper.tsx @@ -9,6 +9,7 @@ import { hexToOklch, calculateBrightness } from '@/lib/helpers/colorUtils'; import { applyCachedThemeToDom, buildThemeCacheFromRestaurant, + clearRestaurantBackgroundOverrides, getCachedMenuColor, getThemeCache, setThemeCache, @@ -143,6 +144,11 @@ function PreferenceWrapper({ children }: Props) { patternDataUrl: cached?.patternDataUrl ?? null, }); + const updatedTheme = getThemeCache(restaurantSlug); + if (updatedTheme) { + applyCachedThemeToDom(updatedTheme); + } + if (restaurant.logo) { localStorage.setItem('restaurant-logo', restaurant.logo); } @@ -164,7 +170,19 @@ function PreferenceWrapper({ children }: Props) { useEffect(() => { document.documentElement.setAttribute('data-theme', nightMode ? 'dark' : 'light'); - }, [nightMode]); + + if (nightMode) { + clearRestaurantBackgroundOverrides(); + return; + } + + if (!restaurantSlug) return; + + const cached = getThemeCache(restaurantSlug); + if (cached) { + applyCachedThemeToDom(cached); + } + }, [nightMode, restaurantSlug]); const splashLogo = mounted ? (aboutData?.data?.logo || cachedLogo || undefined) diff --git a/src/lib/helpers/backgroundUtils.ts b/src/lib/helpers/backgroundUtils.ts index b85e078..87cf78d 100644 --- a/src/lib/helpers/backgroundUtils.ts +++ b/src/lib/helpers/backgroundUtils.ts @@ -51,6 +51,8 @@ const isCustomImageBackgroundLegacy = ( export const resolveBgType = ( settings: RestaurantBackgroundSettings, ): BgType => { + if (settings.bgType === null) return "color"; + const normalized = settings.bgType?.toLowerCase(); if ( normalized === "pattern" || @@ -100,6 +102,22 @@ export const colorizeSvg = ( return result; }; +export const applyColorBackgroundCssVariables = (menuColor: string) => { + const root = document.documentElement; + root.removeAttribute("data-pattern-bg"); + root.removeAttribute("data-image-bg"); + root.style.removeProperty("--bg-pattern-base"); + root.style.removeProperty("--bg-pattern-vector"); + root.style.setProperty( + "--background", + hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY), + ); + root.style.setProperty( + "--primary-light", + hexToRgba(menuColor, PRIMARY_LIGHT_OPACITY), + ); +}; + export const applyPatternCssVariables = (menuColor: string) => { const root = document.documentElement; const baseTint = hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY); diff --git a/src/lib/helpers/themeBootScript.ts b/src/lib/helpers/themeBootScript.ts index 64e8aa4..554d7ed 100644 --- a/src/lib/helpers/themeBootScript.ts +++ b/src/lib/helpers/themeBootScript.ts @@ -1,3 +1,3 @@ export function getThemeBootScript(): string { - return `(function(){try{var s=location.pathname.split("/").filter(Boolean)[0],t=null;if(s&&s!=="auth"){var r=localStorage.getItem("restaurant-theme:"+s);if(r)t=JSON.parse(r)}if(!t||t.version!==1||!t.menuColor){var l=localStorage.getItem("theme-primary-color");if(l){var x=l.replace("#","");if(x.length===6){var p=parseInt(x.slice(0,2),16),f=parseInt(x.slice(2,4),16),m=parseInt(x.slice(4,6),16),b="rgba("+p+","+f+","+m+",0.05)";document.documentElement.style.setProperty("--background",b)}}return}function h(n,a){var u=n.replace("#","");if(u.length!==6)return null;var v=parseInt(u.slice(0,2),16),g=parseInt(u.slice(2,4),16),y=parseInt(u.slice(4,6),16);return"rgba("+v+","+g+","+y+","+a+")"}function isUnset(v){return v==null||v===""||v===0}function isCustomImg(th){if(!th.bgUrl)return false;return !isUnset(th.bgBlur)||!isUnset(th.bgOpacity)||!isUnset(th.bgOverlay)}function resolveBgType(th){var bt=(th.bgType||"").toLowerCase();if(bt==="pattern"||bt==="custom"||bt==="color")return bt;if(th.isPattern===true)return"pattern";if(th.isPattern===false&&th.bgUrl&&isCustomImg(th))return"custom";if(th.isPattern===false)return"color";if(isCustomImg(th))return"custom";if(th.bgUrl)return"pattern";return"color"}var e=document.documentElement;if(t.primaryOklch){e.style.setProperty("--primary",t.primaryOklch);e.style.setProperty("--primary-foreground",t.primaryForeground||"oklch(1 0 0)")}var bt=resolveBgType(t);if(bt==="color")return;if(bt==="pattern"){e.setAttribute("data-pattern-bg","true");var k=t.backgroundTint||h(t.menuColor,0.05),w=t.bgPatternVector||h(t.menuColor,0.1),z=t.primaryLight||h(t.menuColor,0.15);k&&(e.style.setProperty("--background",k),e.style.setProperty("--bg-pattern-base",k));w&&e.style.setProperty("--bg-pattern-vector",w);z&&e.style.setProperty("--primary-light",z);if(k){var d=document.createElement("div");d.id="cached-theme-bg";d.setAttribute("aria-hidden","true");d.style.cssText="position:fixed;inset:0;pointer-events:none;z-index:0;background-color:"+k+(t.patternDataUrl?';background-image:url("'+t.patternDataUrl+'");background-repeat:repeat;background-size:auto':"")+";";document.body.appendChild(d)}}else if(bt==="custom"){e.setAttribute("data-image-bg","true");var d2=document.createElement("div");d2.id="cached-theme-bg";d2.setAttribute("aria-hidden","true");d2.style.cssText="position:fixed;inset:0;pointer-events:none;z-index:0;overflow:hidden;";var i=document.createElement("div");i.id="cached-theme-bg-img";i.style.cssText="position:absolute;inset:-40px;background-size:cover;background-position:center;background-repeat:no-repeat;background-image:url(\\""+t.bgUrl+"\\");"+(t.bgBlur?"filter:blur("+t.bgBlur+"px);":"")+"opacity:"+(t.bgOpacity!=null?t.bgOpacity/100:1)+";";d2.appendChild(i);var ov=document.createElement("div");ov.id="cached-theme-bg-overlay";ov.style.cssText="position:absolute;inset:0;"+(t.bgOverlay&&Number(t.bgOverlay)>0?"background-color:rgba(0,0,0,"+Number(t.bgOverlay)/100+");":"");d2.appendChild(ov);document.body.appendChild(d2)}}catch(u){}})();`; + return `(function(){try{function isNight(){try{var p=localStorage.getItem("preference-storage");if(!p)return false;var o=JSON.parse(p);return o&&o.state&&o.state.items&&o.state.items["night-mode"]&&o.state.items["night-mode"].value===true}catch(v){return false}}var night=isNight(),e=document.documentElement;e.setAttribute("data-theme",night?"dark":"light");var s=location.pathname.split("/").filter(Boolean)[0],t=null;if(s&&s!=="auth"){var r=localStorage.getItem("restaurant-theme:"+s);if(r)t=JSON.parse(r)}if(!t||t.version!==1||!t.menuColor){var l=localStorage.getItem("theme-primary-color");if(l&&!night){var x=l.replace("#","");if(x.length===6){var p=parseInt(x.slice(0,2),16),f=parseInt(x.slice(2,4),16),m=parseInt(x.slice(4,6),16),b="rgba("+p+","+f+","+m+",0.05)";e.style.setProperty("--background",b)}}return}function h(n,a){var u=n.replace("#","");if(u.length!==6)return null;var v=parseInt(u.slice(0,2),16),g=parseInt(u.slice(2,4),16),y=parseInt(u.slice(4,6),16);return"rgba("+v+","+g+","+y+","+a+")"}function isUnset(v){return v==null||v===""||v===0}function isCustomImg(th){if(!th.bgUrl)return false;return !isUnset(th.bgBlur)||!isUnset(th.bgOpacity)||!isUnset(th.bgOverlay)}function resolveBgType(th){if(th.bgType===null)return"color";var bt=(th.bgType||"").toLowerCase();if(bt==="pattern"||bt==="custom"||bt==="color")return bt;if(th.isPattern===true)return"pattern";if(th.isPattern===false&&th.bgUrl&&isCustomImg(th))return"custom";if(th.isPattern===false)return"color";if(isCustomImg(th))return"custom";if(th.bgUrl)return"pattern";return"color"}if(t.primaryOklch){e.style.setProperty("--primary",t.primaryOklch);e.style.setProperty("--primary-foreground",t.primaryForeground||"oklch(1 0 0)")}if(night)return;var bt=resolveBgType(t);if(bt==="color"){var k=t.backgroundTint||h(t.menuColor,0.05),z=t.primaryLight||h(t.menuColor,0.15);k&&e.style.setProperty("--background",k);z&&e.style.setProperty("--primary-light",z);return};if(bt==="pattern"){e.setAttribute("data-pattern-bg","true");var k=t.backgroundTint||h(t.menuColor,0.05),w=t.bgPatternVector||h(t.menuColor,0.1),z=t.primaryLight||h(t.menuColor,0.15);k&&(e.style.setProperty("--background",k),e.style.setProperty("--bg-pattern-base",k));w&&e.style.setProperty("--bg-pattern-vector",w);z&&e.style.setProperty("--primary-light",z);if(k){var d=document.createElement("div");d.id="cached-theme-bg";d.setAttribute("aria-hidden","true");d.style.cssText="position:fixed;inset:0;pointer-events:none;z-index:0;background-color:"+k+(t.patternDataUrl?';background-image:url("'+t.patternDataUrl+'");background-repeat:repeat;background-size:auto':"")+";";document.body.appendChild(d)}}else if(bt==="custom"){e.setAttribute("data-image-bg","true");var d2=document.createElement("div");d2.id="cached-theme-bg";d2.setAttribute("aria-hidden","true");d2.style.cssText="position:fixed;inset:0;pointer-events:none;z-index:0;overflow:hidden;";var i=document.createElement("div");i.id="cached-theme-bg-img";i.style.cssText="position:absolute;inset:-40px;background-size:cover;background-position:center;background-repeat:no-repeat;background-image:url(\\""+t.bgUrl+"\\");"+(t.bgBlur?"filter:blur("+t.bgBlur+"px);":"")+"opacity:"+(t.bgOpacity!=null?t.bgOpacity/100:1)+";";d2.appendChild(i);var ov=document.createElement("div");ov.id="cached-theme-bg-overlay";ov.style.cssText="position:absolute;inset:0;"+(t.bgOverlay&&Number(t.bgOverlay)>0?"background-color:rgba(0,0,0,"+Number(t.bgOverlay)/100+");":"");d2.appendChild(ov);document.body.appendChild(d2)}}catch(u){}})();`; } diff --git a/src/lib/helpers/themeCache.ts b/src/lib/helpers/themeCache.ts index 6d72864..9ebedf4 100644 --- a/src/lib/helpers/themeCache.ts +++ b/src/lib/helpers/themeCache.ts @@ -42,6 +42,35 @@ const CATEGORIES_CACHE_PREFIX = "restaurant-categories"; export const THEME_BG_ELEMENT_ID = "cached-theme-bg"; const THEME_BG_IMG_ID = "cached-theme-bg-img"; const THEME_BG_OVERLAY_ID = "cached-theme-bg-overlay"; +const PREFERENCE_STORAGE_KEY = "preference-storage"; + +export function isNightModeEnabled(): boolean { + if (typeof window === "undefined") return false; + + try { + const raw = localStorage.getItem(PREFERENCE_STORAGE_KEY); + if (!raw) return false; + const parsed = JSON.parse(raw) as { + state?: { items?: Record }; + }; + return parsed?.state?.items?.["night-mode"]?.value === true; + } catch { + return false; + } +} + +export function clearRestaurantBackgroundOverrides(): void { + if (typeof document === "undefined") return; + + const root = document.documentElement; + root.removeAttribute("data-pattern-bg"); + root.removeAttribute("data-image-bg"); + root.style.removeProperty("--background"); + root.style.removeProperty("--bg-pattern-base"); + root.style.removeProperty("--bg-pattern-vector"); + root.style.removeProperty("--primary-light"); + document.getElementById(THEME_BG_ELEMENT_ID)?.remove(); +} export function getThemeCacheKey(slug: string): string { return `${CACHE_KEY_PREFIX}:${slug}`; @@ -320,12 +349,27 @@ export function applyCachedThemeToDom(theme: CachedRestaurantTheme): void { ); } + if (isNightModeEnabled()) { + clearRestaurantBackgroundOverrides(); + return; + } + const bgType = resolveBgType(theme); if (bgType === "color") { + document.getElementById(THEME_BG_ELEMENT_ID)?.remove(); + const tint = + theme.backgroundTint ?? + hexToRgba(theme.menuColor, PATTERN_BACKGROUND_OPACITY); + const primaryLight = + theme.primaryLight ?? + hexToRgba(theme.menuColor, PRIMARY_LIGHT_OPACITY); root.removeAttribute("data-pattern-bg"); root.removeAttribute("data-image-bg"); - document.getElementById(THEME_BG_ELEMENT_ID)?.remove(); + root.style.removeProperty("--bg-pattern-base"); + root.style.removeProperty("--bg-pattern-vector"); + root.style.setProperty("--background", tint); + root.style.setProperty("--primary-light", primaryLight); return; }