elmeg-demo/frontend/app/not-found.tsx

125 lines
5.1 KiB
TypeScript

"use client"
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { Home, Search, Shuffle, ArrowLeft, Music, Disc3 } from "lucide-react"
import { useState, useEffect } from "react"
const GOOSE_QUOTES = [
"Looks like this page flew the coop!",
"Honk if you're lost too!",
"This page has migrated to parts unknown.",
"The jam you seek is not in this location.",
"404: Page not found. But hey, at least the vibes are good.",
"This URL took a wrong turn at Tumble.",
"Flodown? More like FlowGONE.",
"Seems this page is still in the Dripfield.",
"The set break got a little too long...",
"Whoops! Someone put this page in the wrong set.",
]
const SONG_SUGGESTIONS = [
{ title: "Tumble", slug: "tumble" },
{ title: "Arcadia", slug: "arcadia" },
{ title: "Hungersite", slug: "hungersite" },
{ title: "Atlas Dogs", slug: "atlas-dogs" },
{ title: "Rockdale", slug: "rockdale" },
]
export default function NotFound() {
const [quote, setQuote] = useState(GOOSE_QUOTES[0])
const [suggestion, setSuggestion] = useState(SONG_SUGGESTIONS[0])
const [isSpinning, setIsSpinning] = useState(false)
useEffect(() => {
// Random quote on mount
setQuote(GOOSE_QUOTES[Math.floor(Math.random() * GOOSE_QUOTES.length)])
setSuggestion(SONG_SUGGESTIONS[Math.floor(Math.random() * SONG_SUGGESTIONS.length)])
}, [])
const shuffleQuote = () => {
setIsSpinning(true)
setTimeout(() => {
setQuote(GOOSE_QUOTES[Math.floor(Math.random() * GOOSE_QUOTES.length)])
setSuggestion(SONG_SUGGESTIONS[Math.floor(Math.random() * SONG_SUGGESTIONS.length)])
setIsSpinning(false)
}, 300)
}
return (
<div className="flex flex-col items-center justify-center min-h-[70vh] text-center px-4">
{/* Animated Disc Icon */}
<div
className="relative mb-6 cursor-pointer group"
onClick={shuffleQuote}
>
<div className={`p-8 rounded-full bg-primary/10 transition-all duration-300 group-hover:bg-primary/20 ${isSpinning ? 'rotate-180 scale-110' : ''}`}>
<Disc3 className="h-16 w-16 text-primary transition-transform group-hover:rotate-12" />
</div>
</div>
{/* 404 Header */}
<div className="mb-4">
<span className="text-8xl font-black bg-gradient-to-r from-primary via-purple-500 to-pink-500 bg-clip-text text-transparent">
404
</span>
</div>
{/* Playful Quote */}
<p className="text-xl font-medium mb-2 max-w-md min-h-[2em] transition-opacity duration-300"
style={{ opacity: isSpinning ? 0 : 1 }}>
{quote}
</p>
{/* Action Buttons */}
<div className="flex flex-wrap gap-3 justify-center mb-8">
<Link href="/">
<Button size="lg" className="gap-2 font-semibold">
<Home className="h-4 w-4" />
Back to Safety
</Button>
</Link>
<Link href="/shows">
<Button variant="outline" size="lg" className="gap-2">
<Search className="h-4 w-4" />
Find a Show
</Button>
</Link>
<Button variant="ghost" size="lg" className="gap-2" onClick={shuffleQuote}>
<Shuffle className="h-4 w-4" />
Shuffle Quote
</Button>
</div>
{/* Song Suggestion Card */}
<div className="bg-muted/50 rounded-xl p-6 max-w-sm border border-border/50">
<p className="text-sm text-muted-foreground mb-3">
While you&apos;re here, maybe check out:
</p>
<Link
href={`/songs/${suggestion.slug}`}
className="flex items-center gap-3 p-3 rounded-lg bg-background hover:bg-primary/5 border border-border/50 transition-all hover:border-primary/20 group"
>
<div className="h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors">
<Music className="h-5 w-5 text-primary" />
</div>
<div className="text-left">
<p className="font-semibold group-hover:text-primary transition-colors">{suggestion.title}</p>
<p className="text-xs text-muted-foreground">Random song suggestion</p>
</div>
</Link>
</div>
{/* Back Link */}
<button
onClick={() => window.history.back()}
className="mt-8 text-sm text-muted-foreground hover:text-primary transition-colors flex items-center gap-1 group"
>
<ArrowLeft className="h-3 w-3 group-hover:-translate-x-1 transition-transform" />
Take me back where I came from
</button>
</div>
)
}