404lab 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/core/templates.js +5 -3
- package/package.json +1 -1
- package/templates/AmongUs.tsx +92 -109
- package/templates/BlueGlitch.tsx +34 -32
- package/templates/BugGame.tsx +479 -0
- package/templates/GeeksforGeeks.tsx +38 -44
- package/templates/Google.tsx +51 -37
- package/templates/MacOs.tsx +82 -68
- package/templates/ModernPage.tsx +45 -24
- package/templates/Particles.tsx +35 -18
- package/templates/Poet.tsx +99 -71
- package/templates/RetroTv.tsx +22 -18
- package/templates/SimplePage.tsx +32 -17
- package/templates/Snow.tsx +54 -21
- package/templates/StoneAge.tsx +75 -33
- package/templates/StrangerThings.tsx +11 -10
- package/templates/{Terminal404.tsx → Terminal.tsx} +20 -10
- package/templates/Vercel.tsx +78 -32
- package/templates/Void.tsx +345 -0
package/templates/Poet.tsx
CHANGED
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { cn } from "@/components/ui/cn";
|
|
6
6
|
|
|
7
7
|
const Poet = ({ className }: { className?: string }) => {
|
|
8
|
-
|
|
9
|
-
hidden: { opacity: 0 },
|
|
10
|
-
visible: {
|
|
11
|
-
opacity: 1,
|
|
12
|
-
transition: { staggerChildren: 0.15, delayChildren: 0.5 }
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const lineVariants = {
|
|
17
|
-
hidden: { opacity: 0, x: -10 },
|
|
18
|
-
visible: { opacity: 1, x: 0, transition: { duration: 0.8 } }
|
|
19
|
-
};
|
|
8
|
+
|
|
20
9
|
|
|
21
10
|
return (
|
|
22
11
|
<div
|
|
@@ -50,73 +39,117 @@ const Poet = ({ className }: { className?: string }) => {
|
|
|
50
39
|
}
|
|
51
40
|
`}</style>
|
|
52
41
|
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
opacity:
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
42
|
+
<style jsx global>{`
|
|
43
|
+
@keyframes floatRotate {
|
|
44
|
+
0% { transform: translateY(20%) rotate(-10deg); opacity: 0; }
|
|
45
|
+
10% { opacity: 0.1; }
|
|
46
|
+
90% { opacity: 0.1; }
|
|
47
|
+
100% { transform: translateY(80%) rotate(0deg); opacity: 0; left: 120%; }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@keyframes fadeIn {
|
|
51
|
+
from { opacity: 0; }
|
|
52
|
+
to { opacity: 1; }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@keyframes slideInLeft {
|
|
56
|
+
from { opacity: 0; transform: translateX(-10px); }
|
|
57
|
+
to { opacity: 1; transform: translateX(0); }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@keyframes slideInUp {
|
|
61
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
62
|
+
to { opacity: 1; transform: translateY(0); }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@keyframes gentleFloat {
|
|
66
|
+
0%, 100% { transform: translateY(0) rotate(0); }
|
|
67
|
+
50% { transform: translateY(-10px) rotate(2deg); }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.animate-float-bg {
|
|
71
|
+
animation: floatRotate 15s linear infinite;
|
|
72
|
+
animation-delay: 2s;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.animate-slide-up {
|
|
76
|
+
animation: slideInUp 0.8s ease-out forwards;
|
|
77
|
+
opacity: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.animate-fade-in {
|
|
81
|
+
animation: fadeIn 0.8s ease-out forwards;
|
|
82
|
+
opacity: 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.animate-slide-in-left {
|
|
86
|
+
animation: slideInLeft 0.8s ease-out forwards;
|
|
87
|
+
opacity: 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.animate-gentle-float {
|
|
91
|
+
animation: gentleFloat 5s ease-in-out infinite;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.delay-100 { animation-delay: 100ms; }
|
|
95
|
+
.delay-200 { animation-delay: 200ms; }
|
|
96
|
+
.delay-300 { animation-delay: 300ms; }
|
|
97
|
+
.delay-400 { animation-delay: 400ms; }
|
|
98
|
+
.delay-500 { animation-delay: 500ms; }
|
|
99
|
+
.delay-600 { animation-delay: 600ms; }
|
|
100
|
+
.delay-700 { animation-delay: 700ms; }
|
|
101
|
+
.delay-800 { animation-delay: 800ms; }
|
|
102
|
+
.delay-900 { animation-delay: 900ms; }
|
|
103
|
+
.delay-3000 { animation-delay: 3s; }
|
|
104
|
+
`}</style>
|
|
105
|
+
|
|
106
|
+
<div
|
|
107
|
+
className="absolute z-0 pointer-events-none scale-[2] left-[-120%] top-[20%] animate-float-bg"
|
|
67
108
|
>
|
|
68
109
|
<svg width="200" height="100" viewBox="0 0 200 100" fill="currentColor" className="text-black">
|
|
69
110
|
<path d="M100 50 C120 40 150 20 180 20 C160 40 140 50 100 50 C60 50 40 40 20 20 C50 20 80 40 100 50 Z" />
|
|
70
111
|
<path d="M100 50 C110 55 120 65 100 80 C80 65 90 55 100 50 Z" />
|
|
71
112
|
</svg>
|
|
72
|
-
</
|
|
113
|
+
</div>
|
|
73
114
|
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
animate={{ opacity: 1, y: 0 }}
|
|
77
|
-
className="parchment w-full max-w-4xl min-h-[70vh] rounded-sm p-8 md:p-16 flex flex-col md:flex-row gap-12 border border-[#d4c5a1] relative z-10"
|
|
115
|
+
<div
|
|
116
|
+
className="parchment w-full max-w-4xl min-h-[70vh] rounded-sm p-6 xs:p-8 md:p-16 flex flex-col md:flex-row gap-8 md:gap-12 border border-[#d4c5a1] relative z-10 animate-slide-up m-4"
|
|
78
117
|
>
|
|
79
118
|
<div className="flex-1 gothic-font">
|
|
80
|
-
<
|
|
81
|
-
variants={containerVariants}
|
|
82
|
-
initial="hidden"
|
|
83
|
-
animate="visible"
|
|
119
|
+
<div
|
|
84
120
|
className="text-[#2c241a] space-y-2 md:space-y-3"
|
|
85
121
|
>
|
|
86
|
-
<
|
|
122
|
+
<p className="text-sm md:text-base opacity-60 mb-8 tracking-widest uppercase animate-slide-in-left delay-500">
|
|
87
123
|
// Archive: /missing.pdf
|
|
88
|
-
</
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
<
|
|
94
|
-
<
|
|
95
|
-
<
|
|
124
|
+
</p>
|
|
125
|
+
|
|
126
|
+
<p className="animate-slide-in-left delay-600">Once upon a midnight dreary,</p>
|
|
127
|
+
<p className="animate-slide-in-left delay-700">While I web surfed, weak and weary,</p>
|
|
128
|
+
<p className="animate-slide-in-left delay-800">For pages long forgotten yore.</p>
|
|
129
|
+
<p className="animate-slide-in-left delay-900">When I clicked my fav'rite href,</p>
|
|
130
|
+
<p className="animate-slide-in-left" style={{ animationDelay: '1050ms' }}>Suddenly there came a warning,</p>
|
|
131
|
+
<p className="animate-slide-in-left" style={{ animationDelay: '1200ms' }}>and my heart was filled with mourning,</p>
|
|
96
132
|
|
|
97
|
-
<
|
|
133
|
+
<p className="pt-2 sm:pt-4 text-lg sm:text-xl md:text-2xl italic font-medium animate-slide-in-left" style={{ animationDelay: '1350ms' }}>
|
|
98
134
|
Mourning for my dear "/missing.pdf",
|
|
99
|
-
</
|
|
135
|
+
</p>
|
|
100
136
|
|
|
101
|
-
<
|
|
137
|
+
<p className="pt-2 sm:pt-4 animate-slide-in-left" style={{ animationDelay: '1500ms' }}>"Tis not possible!" I muttered,</p>
|
|
102
138
|
|
|
103
|
-
<
|
|
139
|
+
<p className="text-xl sm:text-2xl md:text-3xl font-bold leading-tight animate-slide-in-left" style={{ animationDelay: '1650ms' }}>
|
|
104
140
|
"Give thine pages, I implore!"
|
|
105
|
-
</
|
|
141
|
+
</p>
|
|
106
142
|
|
|
107
|
-
<
|
|
108
|
-
<span className="text-5xl md:text-7xl font-black text-[#8b0000] drop-shadow-sm">404</span>
|
|
109
|
-
<p className="text-lg md:text-xl font-bold mt-2 opacity-80 uppercase tracking-tighter">
|
|
143
|
+
<div className="pt-8 sm:pt-12 animate-slide-in-left" style={{ animationDelay: '1800ms' }}>
|
|
144
|
+
<span className="text-4xl sm:text-5xl md:text-7xl font-black text-[#8b0000] drop-shadow-sm">404</span>
|
|
145
|
+
<p className="text-base sm:text-lg md:text-xl font-bold mt-2 opacity-80 uppercase tracking-tighter">
|
|
110
146
|
Quoth the server, "Nevermore."
|
|
111
147
|
</p>
|
|
112
|
-
</
|
|
113
|
-
</
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
animate={{ opacity: 1 }}
|
|
118
|
-
transition={{ delay: 3 }}
|
|
119
|
-
className="mt-12 flex gap-6"
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div
|
|
152
|
+
className="mt-12 flex gap-6 animate-fade-in delay-3000"
|
|
120
153
|
>
|
|
121
154
|
<Link
|
|
122
155
|
href="/"
|
|
@@ -127,17 +160,12 @@ const Poet = ({ className }: { className?: string }) => {
|
|
|
127
160
|
<button className="px-6 py-2 text-[#2c241a]/60 font-bold hover:text-[#2c241a] transition-all">
|
|
128
161
|
Mourn Again
|
|
129
162
|
</button>
|
|
130
|
-
</
|
|
163
|
+
</div>
|
|
131
164
|
</div>
|
|
132
165
|
|
|
133
166
|
<div className="w-full md:w-1/3 flex flex-col items-center justify-center grayscale opacity-80 contrast-125">
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
y: [0, -10, 0],
|
|
137
|
-
rotate: [0, 2, 0]
|
|
138
|
-
}}
|
|
139
|
-
transition={{ duration: 5, repeat: Infinity, ease: "easeInOut" }}
|
|
140
|
-
className="relative"
|
|
167
|
+
<div
|
|
168
|
+
className="relative animate-gentle-float"
|
|
141
169
|
>
|
|
142
170
|
<svg width="200" height="280" viewBox="0 0 200 280" className="text-[#2c241a]">
|
|
143
171
|
<path fill="currentColor" d="M100 20 C120 20 160 40 160 100 C160 160 120 200 100 220 C80 200 40 160 40 100 C40 40 80 20 100 20 Z" opacity="0.1" />
|
|
@@ -145,9 +173,9 @@ const Poet = ({ className }: { className?: string }) => {
|
|
|
145
173
|
<path stroke="currentColor" strokeWidth="2" d="M100 150 L100 240 M80 220 L120 220" />
|
|
146
174
|
<circle cx="100" cy="80" r="40" fill="none" stroke="currentColor" strokeWidth="1" opacity="0.2" />
|
|
147
175
|
</svg>
|
|
148
|
-
</
|
|
176
|
+
</div>
|
|
149
177
|
</div>
|
|
150
|
-
</
|
|
178
|
+
</div>
|
|
151
179
|
</div>
|
|
152
180
|
);
|
|
153
181
|
};
|
package/templates/RetroTv.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import { cn } from "@/components/ui/cn";
|
|
7
7
|
|
|
8
8
|
const RetroTv = ({ className }: { className?: string }) => {
|
|
@@ -121,21 +121,27 @@ const RetroTv = ({ className }: { className?: string }) => {
|
|
|
121
121
|
animation: scanline 8s linear infinite;
|
|
122
122
|
z-index: 3;
|
|
123
123
|
}
|
|
124
|
+
|
|
125
|
+
@keyframes tvOn {
|
|
126
|
+
from { transform: scale(0.8); opacity: 0; }
|
|
127
|
+
to { transform: scale(1); opacity: 1; }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.animate-tv-on {
|
|
131
|
+
animation: tvOn 0.3s ease-out forwards;
|
|
132
|
+
}
|
|
124
133
|
`}</style>
|
|
125
134
|
|
|
126
135
|
<div className="relative w-full max-w-4xl flex flex-col items-center">
|
|
127
136
|
<div className="w-full bg-[#2a2a2a] p-4 sm:p-8 rounded-[3rem] border-8 border-[#333] tv-frame">
|
|
128
137
|
<div className="aspect-[4/3] w-full bg-black rounded-[2rem] overflow-hidden crt-curve border-4 border-black box-content relative">
|
|
129
|
-
<AnimatePresence>
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
/>
|
|
137
|
-
)}
|
|
138
|
-
</AnimatePresence>
|
|
138
|
+
{/* <AnimatePresence> was here, replaced with conditional rendering and CSS based transitions */}
|
|
139
|
+
{!isOn && (
|
|
140
|
+
<div
|
|
141
|
+
className="absolute inset-0 bg-black z-[100] flex items-center justify-center transition-all duration-100 origin-center"
|
|
142
|
+
style={{ transform: isOn ? 'scaleY(0)' : 'scaleY(1)', opacity: isOn ? 0 : 1 }}
|
|
143
|
+
/>
|
|
144
|
+
)}
|
|
139
145
|
|
|
140
146
|
{isOn && (
|
|
141
147
|
<>
|
|
@@ -143,18 +149,16 @@ const RetroTv = ({ className }: { className?: string }) => {
|
|
|
143
149
|
<div className="scanline-overlay" />
|
|
144
150
|
|
|
145
151
|
<div className="absolute inset-0 flex flex-col items-center justify-center z-10">
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
animate={{ scale: 1, opacity: 1 }}
|
|
149
|
-
className="text-white text-center"
|
|
152
|
+
<div
|
|
153
|
+
className="text-white text-center animate-tv-on px-4"
|
|
150
154
|
>
|
|
151
|
-
<h1 className="text-[6rem] sm:text-[10rem] font-bold tracking-tighter mix-blend-difference">
|
|
155
|
+
<h1 className="text-[4rem] xs:text-[6rem] sm:text-[10rem] font-bold tracking-tighter mix-blend-difference">
|
|
152
156
|
404
|
|
153
157
|
</h1>
|
|
154
|
-
<div className="px-4 py-2 bg-white text-black font-bold text-xl uppercase skew-x-[-12deg]">
|
|
158
|
+
<div className="px-3 sm:px-4 py-1 sm:py-2 bg-white text-black font-bold text-sm xs:text-base sm:text-xl uppercase skew-x-[-12deg] inline-block">
|
|
155
159
|
No Signal
|
|
156
160
|
</div>
|
|
157
|
-
</
|
|
161
|
+
</div>
|
|
158
162
|
</div>
|
|
159
163
|
|
|
160
164
|
<div className="absolute top-6 left-6 z-20 bg-green-500/80 text-black px-3 py-1 text-sm font-bold rounded-sm animate-pulse">
|
package/templates/SimplePage.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { cn } from "@/components/ui/cn";
|
|
6
6
|
|
|
@@ -12,30 +12,45 @@ const SimplePage = ({ className }: { className?: string }) => {
|
|
|
12
12
|
className
|
|
13
13
|
)}
|
|
14
14
|
>
|
|
15
|
+
<style jsx global>{`
|
|
16
|
+
@keyframes fadeInUp {
|
|
17
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
18
|
+
to { opacity: 1; transform: translateY(0); }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@keyframes scaleIn {
|
|
22
|
+
from { transform: scale(0.95); }
|
|
23
|
+
to { transform: scale(1); }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.animate-fade-in-up {
|
|
27
|
+
animation: fadeInUp 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
|
28
|
+
opacity: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.animate-scale-in {
|
|
32
|
+
animation: scaleIn 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
|
33
|
+
}
|
|
34
|
+
`}</style>
|
|
15
35
|
<div className="absolute inset-0 z-0 bg-[radial-gradient(circle_at_center,_transparent_0%,_rgba(0,0,0,0.02)_100%)] pointer-events-none" />
|
|
16
36
|
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
animate={{ opacity: 1, y: 0 }}
|
|
20
|
-
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
|
|
21
|
-
className="relative z-10 w-full max-w-[480px] text-center"
|
|
37
|
+
<div
|
|
38
|
+
className="relative z-10 w-full max-w-[480px] text-center animate-fade-in-up"
|
|
22
39
|
>
|
|
23
|
-
<div className="mb-12">
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
animate={{ scale: 1 }}
|
|
27
|
-
className="text-[120px] md:text-[160px] font-black tracking-tighter text-black dark:text-white leading-none select-none"
|
|
40
|
+
<div className="mb-8 sm:mb-12">
|
|
41
|
+
<h1
|
|
42
|
+
className="text-[100px] xs:text-[120px] md:text-[160px] font-black tracking-tighter text-black dark:text-white leading-none select-none animate-scale-in"
|
|
28
43
|
>
|
|
29
44
|
404
|
|
30
|
-
</
|
|
31
|
-
<div className="h-px w-24 bg-black/5 dark:bg-white/5 mx-auto mt-4" />
|
|
45
|
+
</h1>
|
|
46
|
+
<div className="h-px w-16 sm:w-24 bg-black/5 dark:bg-white/5 mx-auto mt-4" />
|
|
32
47
|
</div>
|
|
33
48
|
|
|
34
|
-
<div className="space-y-6">
|
|
35
|
-
<h2 className="text-2xl font-semibold text-black dark:text-white tracking-tight">
|
|
49
|
+
<div className="space-y-4 sm:space-y-6 px-4">
|
|
50
|
+
<h2 className="text-xl sm:text-2xl font-semibold text-black dark:text-white tracking-tight">
|
|
36
51
|
Something went sideways.
|
|
37
52
|
</h2>
|
|
38
|
-
<p className="text-gray-500 dark:text-gray-400 text-lg leading-relaxed max-w-sm mx-auto font-medium">
|
|
53
|
+
<p className="text-gray-500 dark:text-gray-400 text-base sm:text-lg leading-relaxed max-w-sm mx-auto font-medium">
|
|
39
54
|
The page you requested is currently unavailable.
|
|
40
55
|
It may have been moved or doesn't exist.
|
|
41
56
|
</p>
|
|
@@ -60,7 +75,7 @@ const SimplePage = ({ className }: { className?: string }) => {
|
|
|
60
75
|
<span>Uptime 99.9%</span>
|
|
61
76
|
</div>
|
|
62
77
|
</div>
|
|
63
|
-
</
|
|
78
|
+
</div>
|
|
64
79
|
</div>
|
|
65
80
|
);
|
|
66
81
|
};
|
package/templates/Snow.tsx
CHANGED
|
@@ -2,14 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import { cn } from "@/components/ui/cn";
|
|
7
7
|
|
|
8
8
|
const Snow = ({ className }: { className?: string }) => {
|
|
9
9
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
10
10
|
const [isHovered, setIsHovered] = useState(false);
|
|
11
|
+
const [mounted, setMounted] = useState(false);
|
|
11
12
|
|
|
12
13
|
useEffect(() => {
|
|
14
|
+
setMounted(true);
|
|
15
|
+
}, []);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!mounted) return;
|
|
13
19
|
const canvas = canvasRef.current;
|
|
14
20
|
if (!canvas) return;
|
|
15
21
|
const ctx = canvas.getContext("2d");
|
|
@@ -68,12 +74,14 @@ const Snow = ({ className }: { className?: string }) => {
|
|
|
68
74
|
window.removeEventListener("resize", resize);
|
|
69
75
|
cancelAnimationFrame(animationFrame);
|
|
70
76
|
};
|
|
71
|
-
}, []);
|
|
77
|
+
}, [mounted]);
|
|
78
|
+
|
|
79
|
+
if (!mounted) return null;
|
|
72
80
|
|
|
73
81
|
return (
|
|
74
82
|
<div
|
|
75
83
|
className={cn(
|
|
76
|
-
"min-h-screen flex flex-col items-center justify-center overflow-hidden bg-gradient-to-b from-[#b7d1e5] via-[#e8f2f6] to-white relative",
|
|
84
|
+
"min-h-screen w-full flex flex-col items-center justify-center overflow-hidden bg-gradient-to-b from-[#b7d1e5] via-[#e8f2f6] to-white relative",
|
|
77
85
|
className
|
|
78
86
|
)}
|
|
79
87
|
>
|
|
@@ -81,15 +89,42 @@ const Snow = ({ className }: { className?: string }) => {
|
|
|
81
89
|
|
|
82
90
|
<div className="absolute inset-0 z-0 bg-[radial-gradient(circle_at_center,_transparent_0%,_rgba(255,255,255,0.4)_100%)]" />
|
|
83
91
|
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
<style jsx global>{`
|
|
93
|
+
@keyframes fadeInUp {
|
|
94
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
95
|
+
to { opacity: 1; transform: translateY(0); }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.animate-fade-in-up {
|
|
99
|
+
animation: fadeInUp 0.8s ease-out forwards;
|
|
100
|
+
opacity: 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.hover-404:hover .text-404 {
|
|
104
|
+
transform: scale(1.05);
|
|
105
|
+
opacity: 0.3;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.hover-404:hover .decoration-404 {
|
|
109
|
+
transform: translate(5px, -5px) rotate(10deg);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.text-404 {
|
|
113
|
+
transition: transform 0.3s ease, opacity 0.3s ease;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.decoration-404 {
|
|
117
|
+
transition: transform 0.3s ease;
|
|
118
|
+
}
|
|
119
|
+
`}</style>
|
|
120
|
+
|
|
121
|
+
<main
|
|
122
|
+
className="z-20 text-center px-4 animate-fade-in-up"
|
|
88
123
|
>
|
|
89
|
-
<h1 className="text-4xl md:text-7xl font-bold text-[#5d7399] mb-4 tracking-tight">
|
|
124
|
+
<h1 className="text-3xl xs:text-4xl md:text-7xl font-bold text-[#5d7399] mb-4 tracking-tight">
|
|
90
125
|
Frozen in Time.
|
|
91
126
|
</h1>
|
|
92
|
-
<p className="text-[#5d7399]/70 text-lg md:text-2xl mb-12 max-w-2xl mx-auto font-medium">
|
|
127
|
+
<p className="text-[#5d7399]/70 text-base xs:text-lg md:text-2xl mb-8 sm:mb-12 max-w-xs xs:max-w-lg md:max-w-2xl mx-auto font-medium px-4">
|
|
93
128
|
The page you are looking for has been buried under a heavy snowfall.
|
|
94
129
|
Let's get you somewhere warmer.
|
|
95
130
|
</p>
|
|
@@ -100,35 +135,33 @@ const Snow = ({ className }: { className?: string }) => {
|
|
|
100
135
|
>
|
|
101
136
|
Hitch a ride back home
|
|
102
137
|
</Link>
|
|
103
|
-
</
|
|
138
|
+
</main>
|
|
104
139
|
|
|
105
140
|
<div className="absolute bottom-0 w-full h-[30vh] z-10">
|
|
106
141
|
<svg viewBox="0 0 1440 320" className="absolute bottom-0 w-full h-full drop-shadow-[-20px_-20px_40px_rgba(255,255,255,0.5)]">
|
|
107
142
|
<path fill="#f8f9fa" d="M0,192L48,197.3C96,203,192,213,288,192C384,171,480,117,576,117.3C672,117,768,171,864,197.3C960,224,1056,224,1152,202.7C1248,181,1344,139,1392,117.3L1440,96L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z"></path>
|
|
108
143
|
</svg>
|
|
109
144
|
|
|
110
|
-
<
|
|
111
|
-
className="absolute bottom-[10%] left-1/2 -translate-x-1/2 z-20"
|
|
145
|
+
<div
|
|
146
|
+
className="absolute bottom-[10%] left-1/2 -translate-x-1/2 z-20 hover-404"
|
|
112
147
|
onMouseEnter={() => setIsHovered(true)}
|
|
113
148
|
onMouseLeave={() => setIsHovered(false)}
|
|
114
149
|
>
|
|
115
150
|
<div className="relative group cursor-pointer">
|
|
116
|
-
<
|
|
117
|
-
className="text-8xl md:text-[12rem] font-black text-[#6b85b2] opacity-20 select-none tracking-tighter"
|
|
118
|
-
animate={isHovered ? { scale: 1.05, opacity: 0.3 } : {}}
|
|
151
|
+
<h2
|
|
152
|
+
className="text-7xl xs:text-8xl md:text-[12rem] font-black text-[#6b85b2] opacity-20 select-none tracking-tighter text-404"
|
|
119
153
|
>
|
|
120
154
|
404
|
|
121
|
-
</
|
|
155
|
+
</h2>
|
|
122
156
|
|
|
123
|
-
<
|
|
124
|
-
className="absolute -right-12 -top-12 w-16 h-16 pointer-events-none"
|
|
125
|
-
animate={isHovered ? { rotate: [0, -20, 10, 0], x: [0, -5, 5, 0] } : {}}
|
|
157
|
+
<div
|
|
158
|
+
className="absolute -right-12 -top-12 w-16 h-16 pointer-events-none decoration-404"
|
|
126
159
|
>
|
|
127
160
|
<div className="w-1 h-20 bg-[#dd4040]/20 absolute left-1/2 -translate-x-1/2 top-0" />
|
|
128
161
|
<div className="w-10 h-8 bg-[#dd4040] absolute bottom-0 left-0 rounded-sm" />
|
|
129
|
-
</
|
|
162
|
+
</div>
|
|
130
163
|
</div>
|
|
131
|
-
</
|
|
164
|
+
</div>
|
|
132
165
|
</div>
|
|
133
166
|
|
|
134
167
|
<div className="absolute top-10 right-10 flex gap-4 opacity-20">
|