feat(dependencies): add Lottie animation libraries and refactor NotFoundPage
- 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.
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
"use client";
|
||||
|
||||
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Link from "next/link";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
/** Served from `public/lottie/404.lottie` (mirrored in `src/assets/lottie/404.lottie` for the repo). */
|
||||
const LOTTIE_URL = "/lottie/404.lottie";
|
||||
|
||||
export default function NotFoundContent() {
|
||||
const { resolvedTheme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [loadError, setLoadError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const mode = mounted && resolvedTheme === "dark" ? "dark" : "light";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"relative isolate flex min-h-svh w-full flex-col overflow-hidden",
|
||||
"bg-gray-1 dark:bg-dark",
|
||||
)}
|
||||
>
|
||||
{/* Ambient mesh */}
|
||||
<div
|
||||
className="pointer-events-none absolute -left-1/4 top-0 h-[min(85vh,720px)] w-[min(85vw,720px)] rounded-full bg-primary/[0.22] blur-[100px] dark:bg-primary/[0.12]"
|
||||
aria-hidden
|
||||
/>
|
||||
<div
|
||||
className="pointer-events-none absolute -right-1/4 bottom-0 h-[min(70vh,560px)] w-[min(70vw,560px)] rounded-full bg-blue/[0.18] blur-[90px] dark:bg-blue/[0.1]"
|
||||
aria-hidden
|
||||
/>
|
||||
<div
|
||||
className="pointer-events-none absolute left-1/2 top-1/3 h-64 w-64 -translate-x-1/2 rounded-full bg-primary/[0.08] blur-3xl dark:bg-primary/[0.06]"
|
||||
aria-hidden
|
||||
/>
|
||||
|
||||
{/* Vignette + fine grid */}
|
||||
<div
|
||||
className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_80%_55%_at_50%_38%,transparent_0%,rgba(17,25,40,0.04)_55%,rgba(17,25,40,0.09)_100%)] dark:bg-[radial-gradient(ellipse_80%_55%_at_50%_38%,transparent_0%,rgba(0,0,0,0.35)_55%,rgba(0,0,0,0.65)_100%)]"
|
||||
aria-hidden
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
"pointer-events-none absolute inset-0 opacity-[0.45] dark:opacity-[0.22]",
|
||||
"[background-image:linear-gradient(to_right,rgba(17,25,40,0.06)_1px,transparent_1px),linear-gradient(to_bottom,rgba(17,25,40,0.06)_1px,transparent_1px)]",
|
||||
"dark:[background-image:linear-gradient(to_right,rgba(148,163,184,0.08)_1px,transparent_1px),linear-gradient(to_bottom,rgba(148,163,184,0.08)_1px,transparent_1px)]",
|
||||
)}
|
||||
style={{
|
||||
backgroundSize: "28px 28px",
|
||||
backgroundPosition: "0 0",
|
||||
}}
|
||||
aria-hidden
|
||||
/>
|
||||
|
||||
{/* Frame accents */}
|
||||
<div className="pointer-events-none absolute left-5 top-5 h-16 w-16 border-l-2 border-t-2 border-primary/40 dark:border-primary/35 sm:left-8 sm:top-8" />
|
||||
<div className="pointer-events-none absolute bottom-5 right-5 h-16 w-16 border-b-2 border-r-2 border-primary/40 dark:border-primary/35 sm:bottom-8 sm:right-8" />
|
||||
|
||||
<div className="relative z-10 flex flex-1 flex-col items-center justify-center px-4 py-14 sm:px-6 sm:py-16">
|
||||
<div className="w-full max-w-xl">
|
||||
{/* Gradient hairline frame */}
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-[1.75rem] p-[1px] shadow-5",
|
||||
"bg-gradient-to-br from-primary/55 via-primary/[0.12] to-blue/35",
|
||||
"dark:from-primary/45 dark:via-primary/[0.08] dark:to-blue/25",
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"relative overflow-hidden rounded-[1.7rem]",
|
||||
"bg-white/[0.92] backdrop-blur-2xl dark:bg-dark-2/[0.88]",
|
||||
"border border-white/60 dark:border-dark-3/80",
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-primary/35 to-transparent"
|
||||
aria-hidden
|
||||
/>
|
||||
|
||||
<div className="relative px-6 pb-8 pt-7 sm:px-10 sm:pb-10 sm:pt-9">
|
||||
<div className="mb-6 flex flex-col items-center gap-3 text-center sm:mb-8">
|
||||
<span className="inline-flex items-center gap-2 rounded-full border border-stroke/90 bg-gray-1/90 px-3 py-1 font-mono text-[10px] font-semibold uppercase tracking-[0.28em] text-gray-6 shadow-theme-xs dark:border-dark-3 dark:bg-dark/60 dark:text-dark-6">
|
||||
<span
|
||||
className="h-1.5 w-1.5 shrink-0 rounded-full bg-primary shadow-[0_0_10px_rgba(87,80,241,0.65)]"
|
||||
aria-hidden
|
||||
/>
|
||||
Route not found
|
||||
</span>
|
||||
|
||||
<h1 className="text-[clamp(3.25rem,12vw,5.5rem)] font-bold leading-none tracking-tight">
|
||||
<span className="bg-gradient-to-br from-dark via-dark to-gray-7 bg-clip-text text-transparent dark:from-white dark:via-white dark:to-dark-6">
|
||||
4
|
||||
</span>
|
||||
<span className="bg-gradient-to-br from-primary via-primary to-blue bg-clip-text text-transparent">
|
||||
0
|
||||
</span>
|
||||
<span className="bg-gradient-to-br from-dark via-dark to-gray-7 bg-clip-text text-transparent dark:from-white dark:via-white dark:to-dark-6">
|
||||
4
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="max-w-sm text-body-sm text-gray-6 dark:text-dark-6">
|
||||
This URL is not mapped in the panel. The page may have moved
|
||||
or the link could be mistyped.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative mx-auto w-full max-w-[min(100%,400px)]">
|
||||
<div
|
||||
className="pointer-events-none absolute -inset-3 rounded-2xl bg-gradient-to-b from-primary/[0.07] to-transparent dark:from-primary/[0.05]"
|
||||
aria-hidden
|
||||
/>
|
||||
<div className="relative [&_canvas]:mx-auto [&_canvas]:block [&_canvas]:h-auto [&_canvas]:w-full">
|
||||
{loadError ? (
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-h-[200px] w-full items-center justify-center rounded-2xl border border-dashed border-error/40 bg-gray-1/50 dark:border-error/35 dark:bg-dark/40",
|
||||
"animate-pulse",
|
||||
)}
|
||||
role="alert"
|
||||
>
|
||||
<span className="text-body-xs font-medium text-gray-6 dark:text-dark-6">
|
||||
Could not load illustration
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<DotLottieReact
|
||||
key={mode}
|
||||
src={LOTTIE_URL}
|
||||
loop
|
||||
autoplay
|
||||
className="h-auto w-full max-w-full drop-shadow-[0_12px_40px_rgba(87,80,241,0.12)] dark:drop-shadow-[0_12px_48px_rgba(0,0,0,0.35)]"
|
||||
aria-hidden
|
||||
onError={() => setLoadError(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 flex flex-col items-stretch gap-3 sm:mt-10 sm:flex-row sm:items-center sm:justify-center sm:gap-4">
|
||||
<Link
|
||||
href="/"
|
||||
className={cn(
|
||||
"shadow-theme-xs relative isolate inline-flex w-full items-center justify-center overflow-hidden rounded-xl bg-gradient-to-r from-primary to-primary/85 py-[11px] px-6 text-center text-body-sm font-semibold text-white transition hover:opacity-95",
|
||||
"focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
|
||||
"sm:flex-1 sm:max-w-[200px]",
|
||||
)}
|
||||
>
|
||||
Back to dashboard
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
typeof window !== "undefined" && window.history.back()
|
||||
}
|
||||
className={cn(
|
||||
"rounded-xl border border-stroke bg-white/90 px-6 py-3 text-body-sm font-semibold text-dark shadow-theme-xs",
|
||||
"transition hover:border-primary/40 hover:text-primary",
|
||||
"dark:border-dark-3 dark:bg-dark/80 dark:text-white dark:hover:border-primary/35 dark:hover:bg-dark-3",
|
||||
"sm:flex-1 sm:max-w-[200px]",
|
||||
)}
|
||||
>
|
||||
Go back
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="mt-6 text-center font-mono text-[10px] uppercase tracking-[0.35em] text-gray-5 dark:text-dark-5">
|
||||
Opp lens · admin
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user