127 lines
5.4 KiB
TypeScript
127 lines
5.4 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("")
|
||
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 Goose/Music Icon */}
|
||
<div className="relative mb-6 group cursor-pointer" onClick={shuffleQuote}>
|
||
<div className={`transition-transform duration-300 ${isSpinning ? 'rotate-180 scale-110' : ''}`}>
|
||
<Disc3 className="h-32 w-32 text-primary/20 group-hover:text-primary/40 transition-colors" />
|
||
</div>
|
||
<span className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-6xl group-hover:scale-110 transition-transform">
|
||
🪿
|
||
</span>
|
||
</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>
|
||
|
||
<p className="text-muted-foreground text-sm mb-8">
|
||
Click the goose for a new message ☝️
|
||
</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'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>
|
||
)
|
||
}
|