25f8bde229
- Added `@lottiefiles/dotlottie-react` and `lottie-react` dependencies for enhanced animation capabilities. - Refactored the NotFoundPage component to utilize a dedicated NotFoundContent component, improving code organization and readability. - Updated package.json and pnpm-lock.yaml to reflect new dependencies and their versions.
81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import rawLoadingMain from "@/assets/lottie/loading-main.json";
|
|
import { applyLoadingLottieTheme } from "@/lib/lottie-theme";
|
|
import { cn } from "@/lib/utils";
|
|
import Lottie from "lottie-react";
|
|
import { useTheme } from "next-themes";
|
|
import { useEffect, useMemo, useState } from "react";
|
|
|
|
interface IProps {
|
|
className?: string | null;
|
|
}
|
|
|
|
/**
|
|
* Extract of `animations/main.json` from `public/lottie/loading.lottie` (regenerate when
|
|
* the .lottie changes: `unzip -p public/lottie/loading.lottie animations/main.json > src/assets/lottie/loading-main.json`).
|
|
*/
|
|
const LOTTIE_RAW = rawLoadingMain as object;
|
|
|
|
/**
|
|
* Route-level loader: SVG Lottie via `lottie-react` (reliable on refresh). Source animation
|
|
* stays in sync with `public/lottie/loading.lottie` via the bundled extract above.
|
|
*/
|
|
const Loading = ({ className }: IProps) => {
|
|
const { resolvedTheme } = useTheme();
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
const mode = mounted && resolvedTheme === "dark" ? "dark" : "light";
|
|
|
|
const animationData = useMemo(
|
|
() => applyLoadingLottieTheme(LOTTIE_RAW, mode),
|
|
[mode],
|
|
);
|
|
|
|
return (
|
|
<div
|
|
role="status"
|
|
aria-busy="true"
|
|
aria-live="polite"
|
|
className={cn(
|
|
"relative flex min-h-svh w-full min-w-0 flex-1 flex-col items-center justify-center overflow-hidden",
|
|
"bg-gray-1 dark:bg-dark",
|
|
className,
|
|
)}
|
|
>
|
|
<div
|
|
className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_75%_55%_at_50%_45%,transparent,rgba(17,25,40,0.06))] dark:bg-[radial-gradient(ellipse_75%_55%_at_50%_45%,transparent,rgba(0,0,0,0.45))]"
|
|
aria-hidden
|
|
/>
|
|
|
|
<div className="pointer-events-none absolute left-6 top-6 h-14 w-14 border-l-2 border-t-2 border-primary/45 dark:border-primary/40 sm:left-10 sm:top-10" />
|
|
<div className="pointer-events-none absolute bottom-6 right-6 h-14 w-14 border-b-2 border-r-2 border-primary/45 dark:border-primary/40 sm:bottom-10 sm:right-10" />
|
|
|
|
<div className="relative z-10 flex flex-col items-center gap-6 px-8">
|
|
<div className="relative aspect-square w-[min(200px,55vw)] shrink-0">
|
|
<div className="absolute inset-0 flex items-center justify-center [&_svg]:h-full [&_svg]:w-full [&_svg]:max-h-full [&_svg]:max-w-full">
|
|
<Lottie
|
|
key={mode}
|
|
animationData={animationData}
|
|
loop
|
|
className="h-full w-full"
|
|
aria-hidden
|
|
/>
|
|
</div>
|
|
</div>
|
|
<p className="font-mono text-[11px] font-semibold uppercase tracking-[0.45em] text-gray-6 dark:text-dark-6">
|
|
Loading
|
|
</p>
|
|
</div>
|
|
|
|
<span className="sr-only">Loading, please wait.</span>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Loading;
|