404lab 2.0.1 → 2.0.2
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 +1 -0
- package/package.json +3 -3
- package/templates/AmongUs.tsx +213 -119
- package/templates/BlueGlitch.tsx +190 -100
- package/templates/GeeksforGeeks.tsx +125 -37
- package/templates/Google.tsx +97 -29
- package/templates/MacOs.tsx +116 -212
- package/templates/ModernPage.tsx +73 -11
- package/templates/Particles.tsx +173 -67
- package/templates/Poet.tsx +139 -54
- package/templates/RetroTv.tsx +182 -130
- package/templates/SimplePage.tsx +60 -16
- package/templates/Snow.tsx +113 -179
- package/templates/StoneAge.tsx +91 -23
- package/templates/StrangerThings.tsx +79 -193
- package/templates/Terminal404.tsx +124 -242
- package/templates/Vercel.tsx +127 -0
|
@@ -1,268 +1,150 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
6
|
+
import { cn } from "@/components/ui/cn";
|
|
5
7
|
|
|
6
|
-
const Terminal404 = () => {
|
|
7
|
-
const
|
|
8
|
-
const [
|
|
9
|
-
const [
|
|
8
|
+
const Terminal404 = ({ className }: { className?: string }) => {
|
|
9
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
10
|
+
const [displayText, setDisplayText] = useState("");
|
|
11
|
+
const [isDecrypted, setIsDecrypted] = useState(false);
|
|
10
12
|
|
|
11
13
|
useEffect(() => {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
+
const canvas = canvasRef.current;
|
|
15
|
+
if (!canvas) return;
|
|
16
|
+
const ctx = canvas.getContext("2d");
|
|
17
|
+
if (!ctx) return;
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
i++;
|
|
18
|
-
if (i > message.length) {
|
|
19
|
-
clearInterval(interval);
|
|
20
|
-
setTimeout(() => setCommandVisible(true), 500);
|
|
21
|
-
}
|
|
22
|
-
}, 50);
|
|
23
|
-
|
|
24
|
-
return () => clearInterval(interval);
|
|
25
|
-
}, []);
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
const blink = setInterval(() => {
|
|
29
|
-
setCursorBlink((prev) => !prev);
|
|
30
|
-
}, 530);
|
|
31
|
-
return () => clearInterval(blink);
|
|
32
|
-
}, []);
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<main className="min-h-screen w-full bg-black p-8 font-mono overflow-hidden relative">
|
|
36
|
-
<div className="absolute inset-0 pointer-events-none">
|
|
37
|
-
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-black opacity-20"></div>
|
|
38
|
-
<div className="absolute inset-0 scanlines"></div>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<style jsx>{`
|
|
42
|
-
@keyframes glitch {
|
|
43
|
-
0% {
|
|
44
|
-
clip-path: inset(40% 0 61% 0);
|
|
45
|
-
transform: translate(0);
|
|
46
|
-
}
|
|
47
|
-
20% {
|
|
48
|
-
clip-path: inset(92% 0 1% 0);
|
|
49
|
-
transform: translate(-2px, 2px);
|
|
50
|
-
}
|
|
51
|
-
40% {
|
|
52
|
-
clip-path: inset(43% 0 1% 0);
|
|
53
|
-
transform: translate(-2px, -2px);
|
|
54
|
-
}
|
|
55
|
-
60% {
|
|
56
|
-
clip-path: inset(25% 0 58% 0);
|
|
57
|
-
transform: translate(2px, 2px);
|
|
58
|
-
}
|
|
59
|
-
80% {
|
|
60
|
-
clip-path: inset(54% 0 7% 0);
|
|
61
|
-
transform: translate(2px, -2px);
|
|
62
|
-
}
|
|
63
|
-
100% {
|
|
64
|
-
clip-path: inset(58% 0 43% 0);
|
|
65
|
-
transform: translate(0);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@keyframes flicker {
|
|
70
|
-
0%,
|
|
71
|
-
19%,
|
|
72
|
-
21%,
|
|
73
|
-
23%,
|
|
74
|
-
25%,
|
|
75
|
-
54%,
|
|
76
|
-
56%,
|
|
77
|
-
100% {
|
|
78
|
-
opacity: 1;
|
|
79
|
-
text-shadow:
|
|
80
|
-
0 0 10px rgba(31, 240, 66, 0.8),
|
|
81
|
-
0 0 20px rgba(31, 240, 66, 0.6),
|
|
82
|
-
0 0 30px rgba(31, 240, 66, 0.4);
|
|
83
|
-
}
|
|
84
|
-
20%,
|
|
85
|
-
24%,
|
|
86
|
-
55% {
|
|
87
|
-
opacity: 0.8;
|
|
88
|
-
text-shadow:
|
|
89
|
-
0 0 5px rgba(31, 240, 66, 0.4),
|
|
90
|
-
0 0 10px rgba(31, 240, 66, 0.2);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
@keyframes fadeInUp {
|
|
95
|
-
from {
|
|
96
|
-
opacity: 0;
|
|
97
|
-
transform: translateY(10px);
|
|
98
|
-
}
|
|
99
|
-
to {
|
|
100
|
-
opacity: 1;
|
|
101
|
-
transform: translateY(0);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
@keyframes pulse-glow {
|
|
106
|
-
0%,
|
|
107
|
-
100% {
|
|
108
|
-
text-shadow:
|
|
109
|
-
0 0 10px rgba(31, 240, 66, 0.8),
|
|
110
|
-
0 0 20px rgba(31, 240, 66, 0.5),
|
|
111
|
-
0 0 30px rgba(31, 240, 66, 0.3);
|
|
112
|
-
}
|
|
113
|
-
50% {
|
|
114
|
-
text-shadow:
|
|
115
|
-
0 0 15px rgba(31, 240, 66, 1),
|
|
116
|
-
0 0 30px rgba(31, 240, 66, 0.7),
|
|
117
|
-
0 0 45px rgba(31, 240, 66, 0.4);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
@keyframes typewriter {
|
|
122
|
-
from {
|
|
123
|
-
width: 0;
|
|
124
|
-
}
|
|
125
|
-
to {
|
|
126
|
-
width: 100%;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.scanlines {
|
|
131
|
-
background: repeating-linear-gradient(
|
|
132
|
-
0deg,
|
|
133
|
-
rgba(0, 0, 0, 0.15),
|
|
134
|
-
rgba(0, 0, 0, 0.15) 1px,
|
|
135
|
-
transparent 1px,
|
|
136
|
-
transparent 2px
|
|
137
|
-
);
|
|
138
|
-
pointer-events: none;
|
|
139
|
-
animation: scanlines 8s linear infinite;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@keyframes scanlines {
|
|
143
|
-
0% {
|
|
144
|
-
transform: translateY(0);
|
|
145
|
-
}
|
|
146
|
-
100% {
|
|
147
|
-
transform: translateY(10px);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
19
|
+
canvas.width = window.innerWidth;
|
|
20
|
+
canvas.height = window.innerHeight;
|
|
150
21
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
text-shadow:
|
|
156
|
-
0 0 10px rgba(31, 240, 66, 0.8),
|
|
157
|
-
0 0 20px rgba(31, 240, 66, 0.5),
|
|
158
|
-
0 0 30px rgba(31, 240, 66, 0.3);
|
|
159
|
-
animation: flicker 4s infinite;
|
|
160
|
-
}
|
|
22
|
+
const characters = "0123456789ABCDEFHIJKLMNOPQRSTUVWXYZ";
|
|
23
|
+
const fontSize = 16;
|
|
24
|
+
const columns = canvas.width / fontSize;
|
|
25
|
+
const drops: number[] = [];
|
|
161
26
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
height: 1.4em;
|
|
166
|
-
background: #1ff042;
|
|
167
|
-
margin-left: 4px;
|
|
168
|
-
box-shadow:
|
|
169
|
-
0 0 10px rgba(31, 240, 66, 0.8),
|
|
170
|
-
0 0 20px rgba(31, 240, 66, 0.5);
|
|
171
|
-
animation: pulse-glow 1.5s ease-in-out infinite;
|
|
172
|
-
}
|
|
27
|
+
for (let i = 0; i < columns; i++) {
|
|
28
|
+
drops[i] = 1;
|
|
29
|
+
}
|
|
173
30
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
31
|
+
const draw = () => {
|
|
32
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
|
|
33
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
177
34
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
line-height: 1.7;
|
|
181
|
-
animation: fadeInUp 0.6s ease-out forwards;
|
|
182
|
-
opacity: 0;
|
|
183
|
-
}
|
|
35
|
+
ctx.fillStyle = "#0F0";
|
|
36
|
+
ctx.font = fontSize + "px monospace";
|
|
184
37
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
.command-line:nth-child(2) {
|
|
189
|
-
animation-delay: 0.3s;
|
|
190
|
-
}
|
|
191
|
-
.command-line:nth-child(3) {
|
|
192
|
-
animation-delay: 0.6s;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.link-button {
|
|
196
|
-
display: inline-block;
|
|
197
|
-
margin-top: 2rem;
|
|
198
|
-
padding: 1rem 2rem;
|
|
199
|
-
border: 2px solid #1ff042;
|
|
200
|
-
color: #1ff042;
|
|
201
|
-
background: rgba(31, 240, 66, 0.05);
|
|
202
|
-
text-decoration: none;
|
|
203
|
-
font-size: 1.15rem;
|
|
204
|
-
font-weight: 600;
|
|
205
|
-
letter-spacing: 0.12em;
|
|
206
|
-
transition: all 200ms ease;
|
|
207
|
-
animation: fadeInUp 0.6s ease-out 0.9s forwards;
|
|
208
|
-
opacity: 0;
|
|
209
|
-
cursor: pointer;
|
|
210
|
-
}
|
|
38
|
+
for (let i = 0; i < drops.length; i++) {
|
|
39
|
+
const text = characters.charAt(Math.floor(Math.random() * characters.length));
|
|
40
|
+
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
|
|
211
41
|
|
|
212
|
-
.
|
|
213
|
-
|
|
214
|
-
box-shadow: 0 0 20px rgba(31, 240, 66, 0.6);
|
|
215
|
-
text-shadow:
|
|
216
|
-
0 0 10px rgba(31, 240, 66, 0.8),
|
|
217
|
-
0 0 20px rgba(31, 240, 66, 0.6);
|
|
218
|
-
transform: translateY(-2px);
|
|
42
|
+
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
|
|
43
|
+
drops[i] = 0;
|
|
219
44
|
}
|
|
45
|
+
drops[i]++;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const interval = setInterval(draw, 33);
|
|
50
|
+
const handleResize = () => {
|
|
51
|
+
canvas.width = window.innerWidth;
|
|
52
|
+
canvas.height = window.innerHeight;
|
|
53
|
+
};
|
|
54
|
+
window.addEventListener("resize", handleResize);
|
|
55
|
+
|
|
56
|
+
return () => {
|
|
57
|
+
clearInterval(interval);
|
|
58
|
+
window.removeEventListener("resize", handleResize);
|
|
59
|
+
};
|
|
60
|
+
}, []);
|
|
220
61
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
<
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const target = "404 // ACCESS DENIED";
|
|
64
|
+
let iterations = 0;
|
|
65
|
+
|
|
66
|
+
const interval = setInterval(() => {
|
|
67
|
+
setDisplayText(prev =>
|
|
68
|
+
target.split("").map((char, index) => {
|
|
69
|
+
if (index < iterations) return target[index];
|
|
70
|
+
return "0123456789ABCDEF"[Math.floor(Math.random() * 16)];
|
|
71
|
+
}).join("")
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
if (iterations >= target.length) {
|
|
75
|
+
clearInterval(interval);
|
|
76
|
+
setIsDecrypted(true);
|
|
77
|
+
}
|
|
78
|
+
iterations += 1/3;
|
|
79
|
+
}, 30);
|
|
235
80
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
<div className="command-line mb-4 text-xs sm:text-sm">
|
|
239
|
-
<span className="text-green-400">$</span> searching through
|
|
240
|
-
dimensional rift...
|
|
241
|
-
</div>
|
|
81
|
+
return () => clearInterval(interval);
|
|
82
|
+
}, []);
|
|
242
83
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
className={cn(
|
|
87
|
+
"min-h-screen bg-black flex flex-col items-center justify-center p-8 overflow-hidden font-mono relative",
|
|
88
|
+
className
|
|
89
|
+
)}
|
|
90
|
+
>
|
|
91
|
+
<canvas
|
|
92
|
+
ref={canvasRef}
|
|
93
|
+
className="absolute inset-0 z-0 opacity-20 pointer-events-none"
|
|
94
|
+
/>
|
|
95
|
+
|
|
96
|
+
<div className="absolute inset-0 z-1 pointer-events-none bg-[radial-gradient(circle_at_center,_transparent_0%,_rgba(0,0,0,0.8)_100%)]" />
|
|
97
|
+
|
|
98
|
+
<motion.div
|
|
99
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
100
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
101
|
+
className="z-10 w-full max-w-4xl bg-black/40 backdrop-blur-sm border border-[#0f0]/20 p-8 sm:p-12 rounded-lg shadow-[0_0_50px_rgba(0,255,0,0.1)] relative overflow-hidden group"
|
|
102
|
+
>
|
|
103
|
+
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[#0f0]/40 to-transparent" />
|
|
104
|
+
|
|
105
|
+
<div className="flex items-center gap-2 mb-8 text-[#0f0]/60 text-xs sm:text-sm tracking-widest uppercase">
|
|
106
|
+
<div className="w-2 h-2 bg-[#0f0] rounded-full animate-pulse" />
|
|
107
|
+
System Status: Breach Detected
|
|
108
|
+
</div>
|
|
247
109
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
110
|
+
<h1 className="text-3xl sm:text-6xl font-bold text-[#0f0] mb-6 tracking-tighter drop-shadow-[0_0_15px_rgba(0,255,0,0.5)] min-h-[1.2em]">
|
|
111
|
+
{displayText}
|
|
112
|
+
</h1>
|
|
113
|
+
|
|
114
|
+
<p className="text-[#0f0]/80 text-lg sm:text-xl md:text-2xl mb-12 max-w-2xl leading-relaxed">
|
|
115
|
+
The node you are attempting to ping is non-responsive.
|
|
116
|
+
The packets have been lost in the digital aether.
|
|
117
|
+
</p>
|
|
118
|
+
|
|
119
|
+
<div className="flex flex-col sm:flex-row gap-6">
|
|
120
|
+
<Link
|
|
121
|
+
href="/"
|
|
122
|
+
className="px-8 py-4 bg-[#0f0] text-black font-black uppercase tracking-tighter hover:bg-[#00cc00] transition-colors flex items-center justify-center gap-2 group/btn active:scale-95"
|
|
123
|
+
>
|
|
124
|
+
Terminal Home
|
|
125
|
+
<span className="group-hover/btn:translate-x-1 transition-transform">_</span>
|
|
126
|
+
</Link>
|
|
127
|
+
<button className="px-8 py-4 border border-[#0f0]/40 text-[#0f0] font-bold uppercase tracking-widest hover:bg-[#0f0]/5 transition-colors">
|
|
128
|
+
Brute Force Recovery
|
|
129
|
+
</button>
|
|
130
|
+
</div>
|
|
252
131
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
132
|
+
<div className="mt-12 pt-8 border-t border-[#0f0]/10 grid grid-cols-2 md:grid-cols-4 gap-4 text-[10px] text-[#0f0]/40 font-bold uppercase tracking-wider">
|
|
133
|
+
<div>IP: 127.0.0.1</div>
|
|
134
|
+
<div>Port: 404</div>
|
|
135
|
+
<div>Hash: MD5(VOID)</div>
|
|
136
|
+
<div>Sig: 0xDEADBEEF</div>
|
|
258
137
|
</div>
|
|
259
138
|
|
|
260
|
-
<
|
|
261
|
-
|
|
262
|
-
|
|
139
|
+
<div className="absolute bottom-0 left-0 w-full h-[1px] bg-gradient-to-r from-transparent via-[#0f0]/20 to-transparent" />
|
|
140
|
+
</motion.div>
|
|
141
|
+
|
|
142
|
+
<div className="absolute bottom-6 right-6 text-[#0f0]/20 text-sm italic pointer-events-none">
|
|
143
|
+
root@void:/# _
|
|
263
144
|
</div>
|
|
264
|
-
</
|
|
145
|
+
</div>
|
|
265
146
|
);
|
|
266
147
|
};
|
|
267
148
|
|
|
268
149
|
export default Terminal404;
|
|
150
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { motion } from "framer-motion";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { cn } from "@/components/ui/cn";
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
7
|
+
|
|
8
|
+
const allLogs = [
|
|
9
|
+
"Compiling page /404...",
|
|
10
|
+
"Analyzing dependencies...",
|
|
11
|
+
"Error: Module not found",
|
|
12
|
+
"Deployment failed [404]"
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const Vercel = ({ className }: { className?: string }) => {
|
|
16
|
+
const [logs, setLogs] = useState<{ text: string, time: string }[]>([]);
|
|
17
|
+
const [mounted, setMounted] = useState(false);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
setMounted(true);
|
|
21
|
+
let i = 0;
|
|
22
|
+
const interval = setInterval(() => {
|
|
23
|
+
if (i < allLogs.length) {
|
|
24
|
+
const time = new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
25
|
+
setLogs(prev => [...prev, { text: allLogs[i], time }]);
|
|
26
|
+
i++;
|
|
27
|
+
} else {
|
|
28
|
+
clearInterval(interval);
|
|
29
|
+
}
|
|
30
|
+
}, 1000);
|
|
31
|
+
return () => clearInterval(interval);
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
className={cn(
|
|
37
|
+
"min-h-screen bg-black text-white flex flex-col items-center justify-center p-8 overflow-hidden font-sans relative",
|
|
38
|
+
className
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
<div className="absolute inset-0 z-0 opacity-20 [background-image:radial-gradient(#333_1px,transparent_1px)] [background-size:40px_40px]" />
|
|
42
|
+
|
|
43
|
+
<div className="relative z-10 w-full max-w-2xl flex flex-col items-center">
|
|
44
|
+
<motion.div
|
|
45
|
+
initial={{ opacity: 0, scale: 0.8 }}
|
|
46
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
47
|
+
transition={{ duration: 0.5 }}
|
|
48
|
+
className="mb-16"
|
|
49
|
+
>
|
|
50
|
+
<svg width="80" height="80" viewBox="0 0 75 65" fill="none">
|
|
51
|
+
<path d="M37.5 0L75 65H0L37.5 0Z" fill="white" />
|
|
52
|
+
</svg>
|
|
53
|
+
</motion.div>
|
|
54
|
+
|
|
55
|
+
<div className="text-center mb-16">
|
|
56
|
+
<motion.h1
|
|
57
|
+
initial={{ opacity: 0, y: 10 }}
|
|
58
|
+
animate={{ opacity: 1, y: 0 }}
|
|
59
|
+
className="text-8xl sm:text-9xl font-bold tracking-tighter mb-4"
|
|
60
|
+
>
|
|
61
|
+
404
|
|
62
|
+
</motion.h1>
|
|
63
|
+
<motion.p
|
|
64
|
+
initial={{ opacity: 0 }}
|
|
65
|
+
animate={{ opacity: 1 }}
|
|
66
|
+
transition={{ delay: 0.2 }}
|
|
67
|
+
className="text-gray-400 text-lg sm:text-xl font-medium"
|
|
68
|
+
>
|
|
69
|
+
This deployment could not be found.
|
|
70
|
+
</motion.p>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div className="w-full bg-[#111] border border-white/10 rounded-lg p-6 font-mono text-sm mb-12 shadow-2xl">
|
|
74
|
+
<div className="flex gap-2 mb-4 border-b border-white/5 pb-4">
|
|
75
|
+
<div className="w-3 h-3 rounded-full bg-red-500" />
|
|
76
|
+
<div className="w-3 h-3 rounded-full bg-[#333]" />
|
|
77
|
+
<div className="w-3 h-3 rounded-full bg-[#333]" />
|
|
78
|
+
</div>
|
|
79
|
+
<div className="space-y-2">
|
|
80
|
+
{logs.map((log, i) => (
|
|
81
|
+
<motion.div
|
|
82
|
+
key={i}
|
|
83
|
+
initial={{ opacity: 0, x: -5 }}
|
|
84
|
+
animate={{ opacity: 1, x: 0 }}
|
|
85
|
+
className={cn(
|
|
86
|
+
"flex gap-4",
|
|
87
|
+
log.text.includes("Error") || log.text.includes("failed") ? "text-red-400" : "text-gray-400"
|
|
88
|
+
)}
|
|
89
|
+
>
|
|
90
|
+
<span className="text-gray-600">[{log.time}]</span>
|
|
91
|
+
<span>{log.text}</span>
|
|
92
|
+
</motion.div>
|
|
93
|
+
))}
|
|
94
|
+
<motion.span
|
|
95
|
+
animate={{ opacity: [1, 0] }}
|
|
96
|
+
transition={{ repeat: Infinity, duration: 0.8 }}
|
|
97
|
+
className="inline-block w-2 h-4 bg-white/40 ml-1"
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div className="flex flex-col sm:flex-row gap-4 w-full">
|
|
103
|
+
<Link
|
|
104
|
+
href="/"
|
|
105
|
+
className="flex-1 bg-white text-black font-bold py-4 rounded-md text-center hover:bg-gray-200 transition-colors active:scale-95 shadow-lg shadow-white/5"
|
|
106
|
+
>
|
|
107
|
+
View Documentation
|
|
108
|
+
</Link>
|
|
109
|
+
<button className="flex-1 border border-white/10 text-white font-bold py-4 rounded-md hover:bg-white/5 transition-colors active:scale-95">
|
|
110
|
+
Check Status
|
|
111
|
+
</button>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div className="mt-20 flex gap-8 text-[10px] text-gray-600 font-bold uppercase tracking-widest">
|
|
115
|
+
<div className="flex items-center gap-2">
|
|
116
|
+
<div className="w-1.5 h-1.5 rounded-full bg-red-500 animate-pulse" />
|
|
117
|
+
Vercel System
|
|
118
|
+
</div>
|
|
119
|
+
<div>Region: SFO1</div>
|
|
120
|
+
<div>ID: 404-VOID</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export default Vercel;
|