bgType
This commit is contained in:
@@ -45,6 +45,7 @@ export interface Restaurant {
|
|||||||
domain: string;
|
domain: string;
|
||||||
score: Score;
|
score: Score;
|
||||||
plan: "base" | "premium";
|
plan: "base" | "premium";
|
||||||
|
bgType?: "pattern" | "custom" | "color";
|
||||||
bgBlur?: number;
|
bgBlur?: number;
|
||||||
bgOpacity?: number;
|
bgOpacity?: number;
|
||||||
bgOverlay?: string;
|
bgOverlay?: string;
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ import {
|
|||||||
clearPatternCssVariables,
|
clearPatternCssVariables,
|
||||||
colorizeSvg,
|
colorizeSvg,
|
||||||
hexToRgba,
|
hexToRgba,
|
||||||
isCustomImageBackground,
|
|
||||||
isPatternBackground,
|
|
||||||
normalizeBgNumber,
|
normalizeBgNumber,
|
||||||
PATTERN_BACKGROUND_OPACITY,
|
PATTERN_BACKGROUND_OPACITY,
|
||||||
|
resolveBgType,
|
||||||
} from "@/lib/helpers/backgroundUtils";
|
} from "@/lib/helpers/backgroundUtils";
|
||||||
import {
|
import {
|
||||||
applyCachedThemeToDom,
|
applyCachedThemeToDom,
|
||||||
@@ -65,13 +64,14 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode })
|
|||||||
const [hydratedCache, setHydratedCache] = useState<CachedRestaurantTheme | null>(null);
|
const [hydratedCache, setHydratedCache] = useState<CachedRestaurantTheme | null>(null);
|
||||||
const [patternImageUrl, setPatternImageUrl] = useState<string | null>(null);
|
const [patternImageUrl, setPatternImageUrl] = useState<string | null>(null);
|
||||||
|
|
||||||
const isPattern = restaurant
|
const bgType = restaurant
|
||||||
? isPatternBackground(restaurant)
|
? resolveBgType(restaurant)
|
||||||
: (hydratedCache?.isPattern ?? false);
|
: hydratedCache
|
||||||
|
? resolveBgType(hydratedCache)
|
||||||
|
: "color";
|
||||||
|
|
||||||
const isCustomImage = restaurant
|
const isPattern = bgType === "pattern";
|
||||||
? isCustomImageBackground(restaurant)
|
const isCustomImage = bgType === "custom";
|
||||||
: (!hydratedCache?.isPattern && !!hydratedCache?.bgUrl);
|
|
||||||
const menuColor =
|
const menuColor =
|
||||||
restaurant?.menuColor || hydratedCache?.menuColor || DEFAULT_MENU_COLOR;
|
restaurant?.menuColor || hydratedCache?.menuColor || DEFAULT_MENU_COLOR;
|
||||||
const baseTint = hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY);
|
const baseTint = hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY);
|
||||||
@@ -93,6 +93,7 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode })
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!restaurantSlug) {
|
if (!restaurantSlug) {
|
||||||
clearPatternCssVariables();
|
clearPatternCssVariables();
|
||||||
|
clearCustomImageCssVariables();
|
||||||
removeCachedThemeBackground();
|
removeCachedThemeBackground();
|
||||||
setPatternImageUrl(null);
|
setPatternImageUrl(null);
|
||||||
return;
|
return;
|
||||||
@@ -101,19 +102,22 @@ export function PatternBackgroundProvider({ children }: { children: ReactNode })
|
|||||||
if (!restaurant) return;
|
if (!restaurant) return;
|
||||||
|
|
||||||
const themeBase = buildThemeCacheFromRestaurant(restaurant);
|
const themeBase = buildThemeCacheFromRestaurant(restaurant);
|
||||||
|
const currentBgType = themeBase.bgType;
|
||||||
|
|
||||||
if (!themeBase.isPattern) {
|
if (currentBgType === "color") {
|
||||||
|
clearPatternCssVariables();
|
||||||
|
clearCustomImageCssVariables();
|
||||||
|
removeCachedThemeBackground();
|
||||||
|
setPatternImageUrl(null);
|
||||||
|
setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentBgType === "custom") {
|
||||||
clearPatternCssVariables();
|
clearPatternCssVariables();
|
||||||
setPatternImageUrl(null);
|
setPatternImageUrl(null);
|
||||||
|
applyCustomImageCssVariables();
|
||||||
if (isCustomImageBackground(restaurant)) {
|
setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
|
||||||
applyCustomImageCssVariables();
|
|
||||||
setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
|
|
||||||
} else {
|
|
||||||
clearCustomImageCssVariables();
|
|
||||||
removeCachedThemeBackground();
|
|
||||||
setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ function PreferenceWrapper({ children }: Props) {
|
|||||||
const themeBase = buildThemeCacheFromRestaurant(restaurant);
|
const themeBase = buildThemeCacheFromRestaurant(restaurant);
|
||||||
setThemeCache(restaurantSlug, {
|
setThemeCache(restaurantSlug, {
|
||||||
menuColor,
|
menuColor,
|
||||||
|
bgType: themeBase.bgType,
|
||||||
bgUrl: restaurant.bgUrl,
|
bgUrl: restaurant.bgUrl,
|
||||||
bgBlur: themeBase.bgBlur,
|
bgBlur: themeBase.bgBlur,
|
||||||
bgOpacity: themeBase.bgOpacity,
|
bgOpacity: themeBase.bgOpacity,
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ export const PATTERN_BACKGROUND_OPACITY = 0.05;
|
|||||||
export const PATTERN_VECTOR_OPACITY = 0.1;
|
export const PATTERN_VECTOR_OPACITY = 0.1;
|
||||||
export const PRIMARY_LIGHT_OPACITY = 0.15;
|
export const PRIMARY_LIGHT_OPACITY = 0.15;
|
||||||
|
|
||||||
|
export type BgType = "pattern" | "custom" | "color";
|
||||||
|
|
||||||
export type RestaurantBackgroundSettings = {
|
export type RestaurantBackgroundSettings = {
|
||||||
|
bgType?: BgType | string | null;
|
||||||
bgUrl?: string | null;
|
bgUrl?: string | null;
|
||||||
bgBlur?: number | string | null;
|
bgBlur?: number | string | null;
|
||||||
bgOpacity?: number | string | null;
|
bgOpacity?: number | string | null;
|
||||||
bgOverlay?: string | null;
|
bgOverlay?: string | null;
|
||||||
menuColor?: string | null;
|
menuColor?: string | null;
|
||||||
|
isPattern?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const normalizeBgNumber = (value: unknown): number | null => {
|
export const normalizeBgNumber = (value: unknown): number | null => {
|
||||||
@@ -32,7 +36,7 @@ export const hexToRgba = (hex: string, alpha: number): string => {
|
|||||||
const isUnsetBgValue = (value: unknown): boolean =>
|
const isUnsetBgValue = (value: unknown): boolean =>
|
||||||
value == null || value === "" || value === 0;
|
value == null || value === "" || value === 0;
|
||||||
|
|
||||||
export const isCustomImageBackground = (
|
const isCustomImageBackgroundLegacy = (
|
||||||
settings: RestaurantBackgroundSettings,
|
settings: RestaurantBackgroundSettings,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
if (!settings.bgUrl) return false;
|
if (!settings.bgUrl) return false;
|
||||||
@@ -44,8 +48,40 @@ export const isCustomImageBackground = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isPatternBackground = (settings: RestaurantBackgroundSettings): boolean =>
|
export const resolveBgType = (
|
||||||
!isCustomImageBackground(settings);
|
settings: RestaurantBackgroundSettings,
|
||||||
|
): BgType => {
|
||||||
|
const normalized = settings.bgType?.toLowerCase();
|
||||||
|
if (
|
||||||
|
normalized === "pattern" ||
|
||||||
|
normalized === "custom" ||
|
||||||
|
normalized === "color"
|
||||||
|
) {
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.isPattern === true) return "pattern";
|
||||||
|
if (settings.isPattern === false && settings.bgUrl && isCustomImageBackgroundLegacy(settings)) {
|
||||||
|
return "custom";
|
||||||
|
}
|
||||||
|
if (settings.isPattern === false) return "color";
|
||||||
|
if (isCustomImageBackgroundLegacy(settings)) return "custom";
|
||||||
|
if (settings.bgUrl) return "pattern";
|
||||||
|
|
||||||
|
return "color";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isCustomImageBackground = (
|
||||||
|
settings: RestaurantBackgroundSettings,
|
||||||
|
): boolean => resolveBgType(settings) === "custom";
|
||||||
|
|
||||||
|
export const isPatternBackground = (
|
||||||
|
settings: RestaurantBackgroundSettings,
|
||||||
|
): boolean => resolveBgType(settings) === "pattern";
|
||||||
|
|
||||||
|
export const isColorBackground = (
|
||||||
|
settings: RestaurantBackgroundSettings,
|
||||||
|
): boolean => resolveBgType(settings) === "color";
|
||||||
|
|
||||||
export const colorizeSvg = (
|
export const colorizeSvg = (
|
||||||
svg: string,
|
svg: string,
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export function getThemeBootScript(): string {
|
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)}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){}})();`;
|
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){}})();`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { calculateBrightness, hexToOklch } from "@/lib/helpers/colorUtils";
|
import { calculateBrightness, hexToOklch } from "@/lib/helpers/colorUtils";
|
||||||
import {
|
import {
|
||||||
hexToRgba,
|
hexToRgba,
|
||||||
isCustomImageBackground,
|
resolveBgType,
|
||||||
isPatternBackground,
|
|
||||||
normalizeBgNumber,
|
normalizeBgNumber,
|
||||||
PATTERN_BACKGROUND_OPACITY,
|
PATTERN_BACKGROUND_OPACITY,
|
||||||
PATTERN_VECTOR_OPACITY,
|
PATTERN_VECTOR_OPACITY,
|
||||||
PRIMARY_LIGHT_OPACITY,
|
PRIMARY_LIGHT_OPACITY,
|
||||||
|
type BgType,
|
||||||
type RestaurantBackgroundSettings,
|
type RestaurantBackgroundSettings,
|
||||||
} from "@/lib/helpers/backgroundUtils";
|
} from "@/lib/helpers/backgroundUtils";
|
||||||
import type { AboutResponse } from "@/app/[name]/(Main)/about/types/Types";
|
import type { AboutResponse } from "@/app/[name]/(Main)/about/types/Types";
|
||||||
@@ -19,6 +19,7 @@ import type { QueryClient } from "@tanstack/react-query";
|
|||||||
export type CachedRestaurantTheme = {
|
export type CachedRestaurantTheme = {
|
||||||
version: 1;
|
version: 1;
|
||||||
menuColor: string;
|
menuColor: string;
|
||||||
|
bgType?: BgType;
|
||||||
bgUrl?: string | null;
|
bgUrl?: string | null;
|
||||||
bgBlur?: number | null;
|
bgBlur?: number | null;
|
||||||
bgOpacity?: number | null;
|
bgOpacity?: number | null;
|
||||||
@@ -250,15 +251,24 @@ export function buildThemeCacheFromRestaurant(
|
|||||||
settings: RestaurantBackgroundSettings,
|
settings: RestaurantBackgroundSettings,
|
||||||
): Pick<
|
): Pick<
|
||||||
CachedRestaurantTheme,
|
CachedRestaurantTheme,
|
||||||
"menuColor" | "bgUrl" | "bgBlur" | "bgOpacity" | "bgOverlay" | "isPattern"
|
| "menuColor"
|
||||||
|
| "bgType"
|
||||||
|
| "bgUrl"
|
||||||
|
| "bgBlur"
|
||||||
|
| "bgOpacity"
|
||||||
|
| "bgOverlay"
|
||||||
|
| "isPattern"
|
||||||
> {
|
> {
|
||||||
|
const bgType = resolveBgType(settings);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
menuColor: settings.menuColor || "#1E3A8A",
|
menuColor: settings.menuColor || "#1E3A8A",
|
||||||
|
bgType,
|
||||||
bgUrl: settings.bgUrl,
|
bgUrl: settings.bgUrl,
|
||||||
bgBlur: normalizeBgNumber(settings.bgBlur),
|
bgBlur: normalizeBgNumber(settings.bgBlur),
|
||||||
bgOpacity: normalizeBgNumber(settings.bgOpacity),
|
bgOpacity: normalizeBgNumber(settings.bgOpacity),
|
||||||
bgOverlay: settings.bgOverlay ?? null,
|
bgOverlay: settings.bgOverlay ?? null,
|
||||||
isPattern: isPatternBackground(settings),
|
isPattern: bgType === "pattern",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +279,7 @@ export function themeBackgroundMatches(
|
|||||||
const next = buildThemeCacheFromRestaurant(settings);
|
const next = buildThemeCacheFromRestaurant(settings);
|
||||||
return (
|
return (
|
||||||
cached.menuColor === next.menuColor &&
|
cached.menuColor === next.menuColor &&
|
||||||
|
cached.bgType === next.bgType &&
|
||||||
cached.bgUrl === next.bgUrl &&
|
cached.bgUrl === next.bgUrl &&
|
||||||
cached.bgBlur === next.bgBlur &&
|
cached.bgBlur === next.bgBlur &&
|
||||||
cached.bgOpacity === next.bgOpacity &&
|
cached.bgOpacity === next.bgOpacity &&
|
||||||
@@ -309,11 +320,16 @@ export function applyCachedThemeToDom(theme: CachedRestaurantTheme): void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCustomImage = isCustomImageBackground(theme);
|
const bgType = resolveBgType(theme);
|
||||||
|
|
||||||
if (!theme.isPattern && !isCustomImage) return;
|
if (bgType === "color") {
|
||||||
|
root.removeAttribute("data-pattern-bg");
|
||||||
|
root.removeAttribute("data-image-bg");
|
||||||
|
document.getElementById(THEME_BG_ELEMENT_ID)?.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (theme.isPattern) {
|
if (bgType === "pattern") {
|
||||||
root.setAttribute("data-pattern-bg", "true");
|
root.setAttribute("data-pattern-bg", "true");
|
||||||
root.removeAttribute("data-image-bg");
|
root.removeAttribute("data-image-bg");
|
||||||
|
|
||||||
@@ -349,7 +365,7 @@ export function applyCachedThemeToDom(theme: CachedRestaurantTheme): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCustomImage && theme.bgUrl) {
|
if (bgType === "custom" && theme.bgUrl) {
|
||||||
root.setAttribute("data-image-bg", "true");
|
root.setAttribute("data-image-bg", "true");
|
||||||
root.removeAttribute("data-pattern-bg");
|
root.removeAttribute("data-pattern-bg");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user