Files
New-Optic/components/LiquidGlass.tsx

98 lines
3.0 KiB
TypeScript

"use client";
import { useEffect } from "react";
declare global {
interface Window {
liquidGL?: ((options: Record<string, unknown>) => unknown) & {
registerDynamic?: (elements: string | Element[]) => void;
syncWith?: () => unknown;
};
html2canvas?: unknown;
}
}
export default function LiquidGlass() {
useEffect(() => {
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
const userAgent = navigator.userAgent || "";
const isMobileUserAgent = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|Tablet/i.test(userAgent);
const hasCoarsePrimaryPointer = window.matchMedia("(pointer: coarse)").matches;
if (isMobileUserAgent || hasCoarsePrimaryPointer) return;
if (!document.querySelector(".liquidGL-pane")) return;
let cancelled = false;
let attempts = 0;
function loadScript(src: string) {
return new Promise<void>((resolve, reject) => {
const existing = document.querySelector<HTMLScriptElement>(`script[src="${src}"]`);
if (existing) {
if (existing.dataset.loaded === "true") resolve();
existing.addEventListener("load", () => resolve(), { once: true });
existing.addEventListener("error", () => reject(new Error(`Failed to load ${src}`)), { once: true });
return;
}
const script = document.createElement("script");
script.src = src;
script.async = true;
script.dataset.liquidDependency = "true";
script.addEventListener("load", () => {
script.dataset.loaded = "true";
resolve();
});
script.addEventListener("error", () => reject(new Error(`Failed to load ${src}`)));
document.body.appendChild(script);
});
}
const init = () => {
attempts += 1;
if (cancelled) return;
if (!window.liquidGL || !window.html2canvas) {
if (attempts < 50) window.setTimeout(init, 120);
return;
}
try {
window.liquidGL({
snapshot: "body",
target: ".liquidGL-pane",
resolution: 1.2,
refraction: 0.012,
bevelDepth: 0.052,
bevelWidth: 0.18,
frost: 0.85,
shadow: true,
specular: true,
reveal: "fade",
tilt: true,
tiltFactor: 3.5,
magnify: 1.01
});
window.liquidGL.registerDynamic?.(".liquid-dynamic");
window.liquidGL.syncWith?.();
} catch (error) {
console.warn("liquidGL could not initialise; CSS glass fallback remains active.", error);
}
};
Promise.all([
loadScript("https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"),
loadScript("/scripts/liquidGL.js")
])
.then(init)
.catch((error) => console.warn("liquidGL dependencies could not load; CSS glass fallback remains active.", error));
return () => {
cancelled = true;
};
}, []);
return null;
}