background image
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import * as api from "../service/AboutService";
|
||||
import { setPersistedAboutData } from "@/lib/helpers/themeCache";
|
||||
import {
|
||||
getPersistedAboutData,
|
||||
setPersistedAboutData,
|
||||
} from "@/lib/helpers/themeCache";
|
||||
|
||||
export const useGetAbout = () => {
|
||||
const { name } = useParams<{ name: string }>();
|
||||
return useQuery({
|
||||
const query = useQuery({
|
||||
queryKey: ["about", name],
|
||||
queryFn: async () => {
|
||||
const data = await api.getAbout(name);
|
||||
@@ -16,9 +20,18 @@ export const useGetAbout = () => {
|
||||
retry: false,
|
||||
staleTime: 60 * 60_000,
|
||||
gcTime: 24 * 60 * 60_000,
|
||||
refetchOnMount: false,
|
||||
refetchOnMount: "always",
|
||||
refetchOnWindowFocus: false,
|
||||
placeholderData: () => (name ? getPersistedAboutData(name) : undefined),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (name && query.data) {
|
||||
setPersistedAboutData(name, query.data);
|
||||
}
|
||||
}, [name, query.data]);
|
||||
|
||||
return query;
|
||||
};
|
||||
|
||||
export const useGetReviews = () => {
|
||||
|
||||
@@ -23,7 +23,7 @@ export const useGetFoods = () => {
|
||||
},
|
||||
enabled: !!name,
|
||||
staleTime: 5 * 60_000,
|
||||
refetchOnMount: false,
|
||||
refetchOnMount: "always",
|
||||
placeholderData: () => (name ? getPersistedMenuData(name) : undefined),
|
||||
});
|
||||
|
||||
@@ -47,7 +47,7 @@ export const useGetCategories = () => {
|
||||
},
|
||||
enabled: !!name,
|
||||
staleTime: 5 * 60_000,
|
||||
refetchOnMount: false,
|
||||
refetchOnMount: "always",
|
||||
placeholderData: () => (name ? getPersistedCategoriesData(name) : undefined),
|
||||
});
|
||||
|
||||
|
||||
@@ -413,4 +413,21 @@ html[data-pattern-bg="true"] [data-slot="splash-screen"] {
|
||||
|
||||
html[data-pattern-bg="true"] .pattern-secondary-bg {
|
||||
background-color: var(--primary-light) !important;
|
||||
}
|
||||
|
||||
html[data-image-bg="true"] #root {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
html[data-image-bg="true"] [data-slot="dialog-content"] {
|
||||
background-color: var(--container) !important;
|
||||
}
|
||||
|
||||
html[data-image-bg="true"] [data-slot="splash-screen"] {
|
||||
background-color: var(--container) !important;
|
||||
}
|
||||
|
||||
html[data-image-bg="true"] .pattern-secondary-bg {
|
||||
background-color: var(--primary-light) !important;
|
||||
}
|
||||
@@ -4,11 +4,15 @@ import { usePatternBackground } from "@/components/background/PatternBackgroundP
|
||||
import { THEME_BG_ELEMENT_ID } from "@/lib/helpers/themeCache";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
const THEME_BG_IMG_ID = "cached-theme-bg-img";
|
||||
const THEME_BG_OVERLAY_ID = "cached-theme-bg-overlay";
|
||||
|
||||
export default function AppBackground() {
|
||||
const { isPattern, backgroundStyle } = usePatternBackground();
|
||||
const { isPattern, backgroundStyle, isCustomImage, customImageSettings } =
|
||||
usePatternBackground();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!isPattern) {
|
||||
if (!isPattern && !isCustomImage) {
|
||||
document.getElementById(THEME_BG_ELEMENT_ID)?.remove();
|
||||
return;
|
||||
}
|
||||
@@ -25,8 +29,53 @@ export default function AppBackground() {
|
||||
document.body.appendChild(element);
|
||||
}
|
||||
|
||||
Object.assign(element.style, backgroundStyle as Record<string, string>);
|
||||
}, [backgroundStyle, isPattern]);
|
||||
if (isPattern) {
|
||||
element.style.overflow = "";
|
||||
document.getElementById(THEME_BG_IMG_ID)?.remove();
|
||||
document.getElementById(THEME_BG_OVERLAY_ID)?.remove();
|
||||
Object.assign(element.style, backgroundStyle as Record<string, string>);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCustomImage && customImageSettings) {
|
||||
const { bgUrl, bgBlur, bgOpacity, bgOverlay } = customImageSettings;
|
||||
|
||||
element.style.backgroundColor = "";
|
||||
element.style.backgroundImage = "";
|
||||
element.style.overflow = "hidden";
|
||||
|
||||
let imgLayer = document.getElementById(THEME_BG_IMG_ID);
|
||||
if (!imgLayer) {
|
||||
imgLayer = document.createElement("div");
|
||||
imgLayer.id = THEME_BG_IMG_ID;
|
||||
imgLayer.style.position = "absolute";
|
||||
imgLayer.style.inset = "-40px";
|
||||
imgLayer.style.backgroundSize = "cover";
|
||||
imgLayer.style.backgroundPosition = "center";
|
||||
imgLayer.style.backgroundRepeat = "no-repeat";
|
||||
element.appendChild(imgLayer);
|
||||
}
|
||||
|
||||
imgLayer.style.backgroundImage = `url("${bgUrl}")`;
|
||||
imgLayer.style.filter = bgBlur ? `blur(${bgBlur}px)` : "";
|
||||
imgLayer.style.opacity =
|
||||
bgOpacity != null ? String(bgOpacity / 100) : "1";
|
||||
|
||||
let overlayLayer = document.getElementById(THEME_BG_OVERLAY_ID);
|
||||
if (!overlayLayer) {
|
||||
overlayLayer = document.createElement("div");
|
||||
overlayLayer.id = THEME_BG_OVERLAY_ID;
|
||||
overlayLayer.style.position = "absolute";
|
||||
overlayLayer.style.inset = "0";
|
||||
element.appendChild(overlayLayer);
|
||||
}
|
||||
|
||||
const overlayOpacity =
|
||||
bgOverlay != null ? Number(bgOverlay) / 100 : 0;
|
||||
overlayLayer.style.backgroundColor =
|
||||
overlayOpacity > 0 ? `rgba(0,0,0,${overlayOpacity})` : "";
|
||||
}
|
||||
}, [backgroundStyle, isPattern, isCustomImage, customImageSettings]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
|
||||
import { useGetAbout } from "@/app/[name]/(Main)/about/hooks/useAboutData";
|
||||
import {
|
||||
applyCustomImageCssVariables,
|
||||
applyPatternCssVariables,
|
||||
clearCustomImageCssVariables,
|
||||
clearPatternCssVariables,
|
||||
colorizeSvg,
|
||||
hexToRgba,
|
||||
isCustomImageBackground,
|
||||
isPatternBackground,
|
||||
normalizeBgNumber,
|
||||
PATTERN_BACKGROUND_OPACITY,
|
||||
} from "@/lib/helpers/backgroundUtils";
|
||||
import {
|
||||
@@ -16,6 +20,7 @@ import {
|
||||
removeCachedThemeBackground,
|
||||
setThemeCache,
|
||||
svgToDataUrl,
|
||||
themeBackgroundMatches,
|
||||
type CachedRestaurantTheme,
|
||||
} from "@/lib/helpers/themeCache";
|
||||
import { useParams } from "next/navigation";
|
||||
@@ -32,14 +37,25 @@ import {
|
||||
|
||||
const DEFAULT_MENU_COLOR = "#1E3A8A";
|
||||
|
||||
export type CustomImageSettings = {
|
||||
bgUrl: string;
|
||||
bgBlur: number | null;
|
||||
bgOpacity: number | null;
|
||||
bgOverlay: string | null;
|
||||
};
|
||||
|
||||
type PatternBackgroundContextValue = {
|
||||
isPattern: boolean;
|
||||
isCustomImage: boolean;
|
||||
backgroundStyle: CSSProperties;
|
||||
customImageSettings: CustomImageSettings | null;
|
||||
};
|
||||
|
||||
const PatternBackgroundContext = createContext<PatternBackgroundContextValue>({
|
||||
isPattern: false,
|
||||
isCustomImage: false,
|
||||
backgroundStyle: {},
|
||||
customImageSettings: null,
|
||||
});
|
||||
|
||||
export function PatternBackgroundProvider({ children }: { children: ReactNode }) {
|
||||
@@ -52,6 +68,10 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode })
|
||||
const isPattern = restaurant
|
||||
? isPatternBackground(restaurant)
|
||||
: (hydratedCache?.isPattern ?? false);
|
||||
|
||||
const isCustomImage = restaurant
|
||||
? isCustomImageBackground(restaurant)
|
||||
: (!hydratedCache?.isPattern && !!hydratedCache?.bgUrl);
|
||||
const menuColor =
|
||||
restaurant?.menuColor || hydratedCache?.menuColor || DEFAULT_MENU_COLOR;
|
||||
const baseTint = hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY);
|
||||
@@ -84,15 +104,21 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode })
|
||||
|
||||
if (!themeBase.isPattern) {
|
||||
clearPatternCssVariables();
|
||||
removeCachedThemeBackground();
|
||||
setPatternImageUrl(null);
|
||||
setThemeCache(restaurantSlug, {
|
||||
...themeBase,
|
||||
patternDataUrl: null,
|
||||
});
|
||||
|
||||
if (isCustomImageBackground(restaurant)) {
|
||||
applyCustomImageCssVariables();
|
||||
setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
|
||||
} else {
|
||||
clearCustomImageCssVariables();
|
||||
removeCachedThemeBackground();
|
||||
setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
clearCustomImageCssVariables();
|
||||
|
||||
applyPatternCssVariables(menuColor);
|
||||
|
||||
if (!themeBase.bgUrl) {
|
||||
@@ -110,9 +136,9 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode })
|
||||
|
||||
const cached = getThemeCache(restaurantSlug);
|
||||
const cacheHit =
|
||||
cached?.isPattern &&
|
||||
cached.bgUrl === themeBase.bgUrl &&
|
||||
cached.menuColor === menuColor &&
|
||||
cached &&
|
||||
themeBackgroundMatches(cached, restaurant) &&
|
||||
cached.isPattern &&
|
||||
cached.patternDataUrl;
|
||||
|
||||
if (cacheHit) {
|
||||
@@ -178,9 +204,20 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode })
|
||||
[baseTint, patternImageUrl],
|
||||
);
|
||||
|
||||
const customImageSettings = useMemo<CustomImageSettings | null>(() => {
|
||||
const src = restaurant?.bgUrl || hydratedCache?.bgUrl;
|
||||
if (!isCustomImage || !src) return null;
|
||||
return {
|
||||
bgUrl: src,
|
||||
bgBlur: normalizeBgNumber(restaurant?.bgBlur ?? hydratedCache?.bgBlur),
|
||||
bgOpacity: normalizeBgNumber(restaurant?.bgOpacity ?? hydratedCache?.bgOpacity),
|
||||
bgOverlay: restaurant?.bgOverlay ?? hydratedCache?.bgOverlay ?? null,
|
||||
};
|
||||
}, [isCustomImage, restaurant, hydratedCache]);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({ isPattern, backgroundStyle }),
|
||||
[backgroundStyle, isPattern],
|
||||
() => ({ isPattern, isCustomImage, backgroundStyle, customImageSettings }),
|
||||
[backgroundStyle, isPattern, isCustomImage, customImageSettings],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -131,10 +131,14 @@ function PreferenceWrapper({ children }: Props) {
|
||||
const restaurant = aboutData.data;
|
||||
const cached = getThemeCache(restaurantSlug);
|
||||
|
||||
const themeBase = buildThemeCacheFromRestaurant(restaurant);
|
||||
setThemeCache(restaurantSlug, {
|
||||
menuColor,
|
||||
bgUrl: restaurant.bgUrl,
|
||||
isPattern: buildThemeCacheFromRestaurant(restaurant).isPattern,
|
||||
bgBlur: themeBase.bgBlur,
|
||||
bgOpacity: themeBase.bgOpacity,
|
||||
bgOverlay: themeBase.bgOverlay,
|
||||
isPattern: themeBase.isPattern,
|
||||
patternDataUrl: cached?.patternDataUrl ?? null,
|
||||
});
|
||||
|
||||
@@ -155,8 +159,7 @@ function PreferenceWrapper({ children }: Props) {
|
||||
if (seenFingerprint === '|' && currentFingerprint !== '|') {
|
||||
localStorage.setItem(getSplashStorageKey(restaurantSlug), currentFingerprint);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [aboutData?.data?.menuColor, restaurantSlug]);
|
||||
}, [aboutData?.data, restaurantSlug]);
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.setAttribute('data-theme', nightMode ? 'dark' : 'light');
|
||||
|
||||
@@ -4,12 +4,19 @@ export const PRIMARY_LIGHT_OPACITY = 0.15;
|
||||
|
||||
export type RestaurantBackgroundSettings = {
|
||||
bgUrl?: string | null;
|
||||
bgBlur?: number | null;
|
||||
bgOpacity?: number | null;
|
||||
bgBlur?: number | string | null;
|
||||
bgOpacity?: number | string | null;
|
||||
bgOverlay?: string | null;
|
||||
menuColor?: string | null;
|
||||
};
|
||||
|
||||
export const normalizeBgNumber = (value: unknown): number | null => {
|
||||
if (value == null || value === "") return null;
|
||||
const parsed = typeof value === "string" ? Number(value) : value;
|
||||
if (typeof parsed !== "number" || Number.isNaN(parsed)) return null;
|
||||
return parsed;
|
||||
};
|
||||
|
||||
export const hexToRgba = (hex: string, alpha: number): string => {
|
||||
const normalized = hex.replace("#", "");
|
||||
if (normalized.length !== 6) {
|
||||
@@ -82,3 +89,13 @@ export const clearPatternCssVariables = () => {
|
||||
root.style.removeProperty("--primary-light");
|
||||
root.style.removeProperty("--background");
|
||||
};
|
||||
|
||||
export const applyCustomImageCssVariables = () => {
|
||||
const root = document.documentElement;
|
||||
root.setAttribute("data-image-bg", "true");
|
||||
root.removeAttribute("data-pattern-bg");
|
||||
};
|
||||
|
||||
export const clearCustomImageCssVariables = () => {
|
||||
document.documentElement.removeAttribute("data-image-bg");
|
||||
};
|
||||
|
||||
@@ -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+")"}var e=document.documentElement;if(t.primaryOklch){e.style.setProperty("--primary",t.primaryOklch);e.style.setProperty("--primary-foreground",t.primaryForeground||"oklch(1 0 0)")}if(!t.isPattern)return;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)}}catch(u){}})();`;
|
||||
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)}var e=document.documentElement;if(t.primaryOklch){e.style.setProperty("--primary",t.primaryOklch);e.style.setProperty("--primary-foreground",t.primaryForeground||"oklch(1 0 0)")}if(!t.isPattern&&!isCustomImg(t))return;if(t.isPattern){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(isCustomImg(t)){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){}})();`;
|
||||
}
|
||||
|
||||
+121
-34
@@ -1,7 +1,9 @@
|
||||
import { calculateBrightness, hexToOklch } from "@/lib/helpers/colorUtils";
|
||||
import {
|
||||
hexToRgba,
|
||||
isCustomImageBackground,
|
||||
isPatternBackground,
|
||||
normalizeBgNumber,
|
||||
PATTERN_BACKGROUND_OPACITY,
|
||||
PATTERN_VECTOR_OPACITY,
|
||||
PRIMARY_LIGHT_OPACITY,
|
||||
@@ -18,6 +20,9 @@ export type CachedRestaurantTheme = {
|
||||
version: 1;
|
||||
menuColor: string;
|
||||
bgUrl?: string | null;
|
||||
bgBlur?: number | null;
|
||||
bgOpacity?: number | null;
|
||||
bgOverlay?: string | null;
|
||||
isPattern: boolean;
|
||||
patternDataUrl?: string | null;
|
||||
primaryOklch?: string;
|
||||
@@ -34,6 +39,8 @@ const ABOUT_CACHE_PREFIX = "restaurant-about";
|
||||
const MENU_CACHE_PREFIX = "restaurant-menu";
|
||||
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";
|
||||
|
||||
export function getThemeCacheKey(slug: string): string {
|
||||
return `${CACHE_KEY_PREFIX}:${slug}`;
|
||||
@@ -215,7 +222,10 @@ export function setThemeCache(
|
||||
const payload: CachedRestaurantTheme = {
|
||||
...theme,
|
||||
...css,
|
||||
patternDataUrl: theme.patternDataUrl ?? existing?.patternDataUrl ?? null,
|
||||
patternDataUrl:
|
||||
theme.patternDataUrl !== undefined
|
||||
? theme.patternDataUrl
|
||||
: (existing?.patternDataUrl ?? null),
|
||||
version: CACHE_VERSION,
|
||||
};
|
||||
|
||||
@@ -238,18 +248,54 @@ export function setThemeCache(
|
||||
|
||||
export function buildThemeCacheFromRestaurant(
|
||||
settings: RestaurantBackgroundSettings,
|
||||
): Pick<CachedRestaurantTheme, "menuColor" | "bgUrl" | "isPattern"> {
|
||||
): Pick<
|
||||
CachedRestaurantTheme,
|
||||
"menuColor" | "bgUrl" | "bgBlur" | "bgOpacity" | "bgOverlay" | "isPattern"
|
||||
> {
|
||||
return {
|
||||
menuColor: settings.menuColor || "#1E3A8A",
|
||||
bgUrl: settings.bgUrl,
|
||||
bgBlur: normalizeBgNumber(settings.bgBlur),
|
||||
bgOpacity: normalizeBgNumber(settings.bgOpacity),
|
||||
bgOverlay: settings.bgOverlay ?? null,
|
||||
isPattern: isPatternBackground(settings),
|
||||
};
|
||||
}
|
||||
|
||||
export function themeBackgroundMatches(
|
||||
cached: CachedRestaurantTheme,
|
||||
settings: RestaurantBackgroundSettings,
|
||||
): boolean {
|
||||
const next = buildThemeCacheFromRestaurant(settings);
|
||||
return (
|
||||
cached.menuColor === next.menuColor &&
|
||||
cached.bgUrl === next.bgUrl &&
|
||||
cached.bgBlur === next.bgBlur &&
|
||||
cached.bgOpacity === next.bgOpacity &&
|
||||
cached.bgOverlay === next.bgOverlay &&
|
||||
cached.isPattern === next.isPattern
|
||||
);
|
||||
}
|
||||
|
||||
export function svgToDataUrl(svg: string): string {
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
||||
}
|
||||
|
||||
function ensureBgElement(): HTMLElement {
|
||||
let bgElement = document.getElementById(THEME_BG_ELEMENT_ID);
|
||||
if (!bgElement) {
|
||||
bgElement = document.createElement("div");
|
||||
bgElement.id = THEME_BG_ELEMENT_ID;
|
||||
bgElement.setAttribute("aria-hidden", "true");
|
||||
bgElement.style.position = "fixed";
|
||||
bgElement.style.inset = "0";
|
||||
bgElement.style.pointerEvents = "none";
|
||||
bgElement.style.zIndex = "0";
|
||||
document.body.appendChild(bgElement);
|
||||
}
|
||||
return bgElement;
|
||||
}
|
||||
|
||||
export function applyCachedThemeToDom(theme: CachedRestaurantTheme): void {
|
||||
if (typeof document === "undefined") return;
|
||||
|
||||
@@ -263,44 +309,85 @@ export function applyCachedThemeToDom(theme: CachedRestaurantTheme): void {
|
||||
);
|
||||
}
|
||||
|
||||
if (!theme.isPattern) return;
|
||||
const isCustomImage = isCustomImageBackground(theme);
|
||||
|
||||
root.setAttribute("data-pattern-bg", "true");
|
||||
if (!theme.isPattern && !isCustomImage) return;
|
||||
|
||||
if (theme.backgroundTint) {
|
||||
root.style.setProperty("--background", theme.backgroundTint);
|
||||
root.style.setProperty("--bg-pattern-base", theme.backgroundTint);
|
||||
}
|
||||
if (theme.bgPatternVector) {
|
||||
root.style.setProperty("--bg-pattern-vector", theme.bgPatternVector);
|
||||
}
|
||||
if (theme.primaryLight) {
|
||||
root.style.setProperty("--primary-light", theme.primaryLight);
|
||||
if (theme.isPattern) {
|
||||
root.setAttribute("data-pattern-bg", "true");
|
||||
root.removeAttribute("data-image-bg");
|
||||
|
||||
if (theme.backgroundTint) {
|
||||
root.style.setProperty("--background", theme.backgroundTint);
|
||||
root.style.setProperty("--bg-pattern-base", theme.backgroundTint);
|
||||
}
|
||||
if (theme.bgPatternVector) {
|
||||
root.style.setProperty("--bg-pattern-vector", theme.bgPatternVector);
|
||||
}
|
||||
if (theme.primaryLight) {
|
||||
root.style.setProperty("--primary-light", theme.primaryLight);
|
||||
}
|
||||
|
||||
if (!theme.backgroundTint) return;
|
||||
|
||||
const bgElement = ensureBgElement();
|
||||
bgElement.style.overflow = "";
|
||||
|
||||
document.getElementById(THEME_BG_IMG_ID)?.remove();
|
||||
document.getElementById(THEME_BG_OVERLAY_ID)?.remove();
|
||||
|
||||
bgElement.style.backgroundColor = theme.backgroundTint;
|
||||
if (theme.patternDataUrl) {
|
||||
bgElement.style.backgroundImage = `url("${theme.patternDataUrl}")`;
|
||||
bgElement.style.backgroundRepeat = "repeat";
|
||||
bgElement.style.backgroundSize = "auto";
|
||||
} else {
|
||||
bgElement.style.removeProperty("background-image");
|
||||
bgElement.style.removeProperty("background-repeat");
|
||||
bgElement.style.removeProperty("background-size");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!theme.backgroundTint) return;
|
||||
if (isCustomImage && theme.bgUrl) {
|
||||
root.setAttribute("data-image-bg", "true");
|
||||
root.removeAttribute("data-pattern-bg");
|
||||
|
||||
let bgElement = document.getElementById(THEME_BG_ELEMENT_ID);
|
||||
if (!bgElement) {
|
||||
bgElement = document.createElement("div");
|
||||
bgElement.id = THEME_BG_ELEMENT_ID;
|
||||
bgElement.setAttribute("aria-hidden", "true");
|
||||
bgElement.style.position = "fixed";
|
||||
bgElement.style.inset = "0";
|
||||
bgElement.style.pointerEvents = "none";
|
||||
bgElement.style.zIndex = "0";
|
||||
document.body.appendChild(bgElement);
|
||||
}
|
||||
const bgElement = ensureBgElement();
|
||||
bgElement.style.backgroundColor = "";
|
||||
bgElement.style.backgroundImage = "";
|
||||
bgElement.style.overflow = "hidden";
|
||||
|
||||
bgElement.style.backgroundColor = theme.backgroundTint;
|
||||
if (theme.patternDataUrl) {
|
||||
bgElement.style.backgroundImage = `url("${theme.patternDataUrl}")`;
|
||||
bgElement.style.backgroundRepeat = "repeat";
|
||||
bgElement.style.backgroundSize = "auto";
|
||||
} else {
|
||||
bgElement.style.removeProperty("background-image");
|
||||
bgElement.style.removeProperty("background-repeat");
|
||||
bgElement.style.removeProperty("background-size");
|
||||
let imgLayer = document.getElementById(THEME_BG_IMG_ID);
|
||||
if (!imgLayer) {
|
||||
imgLayer = document.createElement("div");
|
||||
imgLayer.id = THEME_BG_IMG_ID;
|
||||
imgLayer.style.position = "absolute";
|
||||
imgLayer.style.inset = "-40px";
|
||||
imgLayer.style.backgroundSize = "cover";
|
||||
imgLayer.style.backgroundPosition = "center";
|
||||
imgLayer.style.backgroundRepeat = "no-repeat";
|
||||
bgElement.appendChild(imgLayer);
|
||||
}
|
||||
|
||||
imgLayer.style.backgroundImage = `url("${theme.bgUrl}")`;
|
||||
imgLayer.style.filter = theme.bgBlur ? `blur(${theme.bgBlur}px)` : "";
|
||||
imgLayer.style.opacity =
|
||||
theme.bgOpacity != null ? String(theme.bgOpacity / 100) : "1";
|
||||
|
||||
let overlayLayer = document.getElementById(THEME_BG_OVERLAY_ID);
|
||||
if (!overlayLayer) {
|
||||
overlayLayer = document.createElement("div");
|
||||
overlayLayer.id = THEME_BG_OVERLAY_ID;
|
||||
overlayLayer.style.position = "absolute";
|
||||
overlayLayer.style.inset = "0";
|
||||
bgElement.appendChild(overlayLayer);
|
||||
}
|
||||
|
||||
const overlayOpacity =
|
||||
theme.bgOverlay != null ? Number(theme.bgOverlay) / 100 : 0;
|
||||
overlayLayer.style.backgroundColor =
|
||||
overlayOpacity > 0 ? `rgba(0,0,0,${overlayOpacity})` : "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
html[data-pattern-bg="true"] .glass-surface {
|
||||
html[data-pattern-bg="true"] .glass-surface,
|
||||
html[data-image-bg="true"] .glass-surface {
|
||||
-webkit-backdrop-filter: blur(1px);
|
||||
backdrop-filter: blur(1px);
|
||||
}
|
||||
@@ -38,7 +39,8 @@ html[data-theme="dark"] .glass-surface--selected {
|
||||
box-shadow: 0px -2px 14px 0px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
html[data-pattern-bg="true"] .glass-surface-nav {
|
||||
html[data-pattern-bg="true"] .glass-surface-nav,
|
||||
html[data-image-bg="true"] .glass-surface-nav {
|
||||
-webkit-backdrop-filter: blur(4px);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user