glass mode

This commit is contained in:
hamid zarghami
2026-06-21 12:58:29 +03:30
parent d3ef8e1a98
commit b5653906dc
17 changed files with 325 additions and 211 deletions
@@ -0,0 +1,126 @@
"use client";
import { useGetAbout } from "@/app/[name]/(Main)/about/hooks/useAboutData";
import {
applyPatternCssVariables,
clearPatternCssVariables,
colorizeSvg,
hexToRgba,
isPatternBackground,
PATTERN_BACKGROUND_OPACITY,
} from "@/lib/helpers/backgroundUtils";
import { useParams } from "next/navigation";
import {
createContext,
useContext,
useEffect,
useMemo,
useRef,
useState,
type CSSProperties,
type ReactNode,
} from "react";
const DEFAULT_MENU_COLOR = "#1E3A8A";
type PatternBackgroundContextValue = {
isPattern: boolean;
backgroundStyle: CSSProperties;
};
const PatternBackgroundContext = createContext<PatternBackgroundContextValue>({
isPattern: false,
backgroundStyle: {},
});
export function PatternBackgroundProvider({ children }: { children: ReactNode }) {
const { name: restaurantSlug } = useParams<{ name: string }>();
const { data: aboutData } = useGetAbout();
const restaurant = aboutData?.data;
const [patternImageUrl, setPatternImageUrl] = useState<string | null>(null);
const blobUrlRef = useRef<string | null>(null);
const isPattern = restaurant ? isPatternBackground(restaurant) : false;
const menuColor = restaurant?.menuColor || DEFAULT_MENU_COLOR;
const baseTint = hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY);
useEffect(() => {
const revokeBlobUrl = () => {
if (blobUrlRef.current) {
URL.revokeObjectURL(blobUrlRef.current);
blobUrlRef.current = null;
}
setPatternImageUrl(null);
};
if (!isPattern || !restaurant?.bgUrl || !restaurantSlug) {
clearPatternCssVariables();
revokeBlobUrl();
return;
}
applyPatternCssVariables(menuColor);
let cancelled = false;
const proxyUrl = `/${restaurantSlug}/api/proxy-svg?url=${encodeURIComponent(restaurant.bgUrl)}`;
fetch(proxyUrl)
.then((response) => {
if (!response.ok) {
throw new Error("Failed to fetch background pattern");
}
return response.text();
})
.then((svg) => {
if (cancelled) return;
revokeBlobUrl();
const blob = new Blob([colorizeSvg(svg, menuColor)], {
type: "image/svg+xml;charset=utf-8",
});
const blobUrl = URL.createObjectURL(blob);
blobUrlRef.current = blobUrl;
setPatternImageUrl(blobUrl);
})
.catch(() => {
if (!cancelled) {
revokeBlobUrl();
}
});
return () => {
cancelled = true;
clearPatternCssVariables();
revokeBlobUrl();
};
}, [isPattern, menuColor, restaurant?.bgUrl, restaurantSlug]);
const backgroundStyle = useMemo<CSSProperties>(
() => ({
backgroundColor: baseTint,
...(patternImageUrl
? {
backgroundImage: `url("${patternImageUrl}")`,
backgroundRepeat: "repeat",
backgroundSize: "auto",
}
: {}),
}),
[baseTint, patternImageUrl],
);
const value = useMemo(
() => ({ isPattern, backgroundStyle }),
[backgroundStyle, isPattern],
);
return (
<PatternBackgroundContext.Provider value={value}>
{children}
</PatternBackgroundContext.Provider>
);
}
export function usePatternBackground() {
return useContext(PatternBackgroundContext);
}