upgrade to different layout
This commit is contained in:
@@ -1,8 +1,417 @@
|
||||
---
|
||||
import Hero from '../components/Hero.astro';
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
---
|
||||
|
||||
<BaseLayout title="Not Found" description="404 Error — this page was not found">
|
||||
<Hero title="Page Not Found" tagline="Not found" />
|
||||
</BaseLayout>
|
||||
<Layout title="404 - Page Not Found">
|
||||
<div class="relative flex flex-col items-center justify-center min-h-[80vh] py-20 text-center px-4 overflow-hidden">
|
||||
<!-- Animated background elements -->
|
||||
<div class="absolute inset-0 overflow-hidden">
|
||||
<div class="absolute -top-20 -left-20 w-64 h-64 bg-zinc-100 dark:bg-zinc-800/50 rounded-full blur-3xl opacity-50 animate-blob"></div>
|
||||
<div class="absolute top-1/2 right-1/4 w-96 h-96 bg-zinc-200 dark:bg-zinc-800/30 rounded-full blur-3xl opacity-30 animate-blob animation-delay-2000"></div>
|
||||
<div class="absolute bottom-20 left-1/3 w-72 h-72 bg-zinc-100 dark:bg-zinc-800/40 rounded-full blur-3xl opacity-40 animate-blob animation-delay-4000"></div>
|
||||
</div>
|
||||
|
||||
<!-- Main content with animation -->
|
||||
<div class="relative z-10 max-w-xl mx-auto">
|
||||
<div class="glitch-wrapper">
|
||||
<h1 class="glitch text-9xl sm:text-[12rem] font-bold text-zinc-900 dark:text-zinc-100 leading-none" data-text="404">404</h1>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-6 text-2xl sm:text-3xl font-bold text-zinc-800 dark:text-zinc-200">Page Not Found</h2>
|
||||
|
||||
<p class="mt-6 text-zinc-600 dark:text-zinc-400 max-w-md mx-auto text-lg">
|
||||
The page you're looking for does not exist.
|
||||
</p>
|
||||
|
||||
<div class="mt-10 flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<a
|
||||
href="/"
|
||||
class="group relative inline-flex items-center gap-2 px-6 py-3 rounded-lg bg-zinc-900 text-zinc-100 hover:bg-zinc-800 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200 transition-all duration-300 overflow-hidden shadow-lg hover:shadow-xl"
|
||||
>
|
||||
<span class="absolute inset-0 bg-gradient-to-r from-zinc-700 to-zinc-900 dark:from-zinc-300 dark:to-zinc-100 opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-0"></span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 relative z-10">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
|
||||
</svg>
|
||||
<span class="font-medium relative z-10">Return Home</span>
|
||||
</a>
|
||||
|
||||
<button
|
||||
id="back-button"
|
||||
class="group inline-flex items-center gap-2 px-6 py-3 rounded-lg border border-zinc-300 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-all duration-300 shadow-sm hover:shadow-md"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 transition-transform duration-300 group-hover:-translate-x-1">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
|
||||
</svg>
|
||||
<span class="font-medium">Go Back</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Random fun fact -->
|
||||
<div class="mt-16 p-6 bg-zinc-50 dark:bg-zinc-800/50 rounded-xl shadow-sm max-w-md mx-auto backdrop-blur-sm border border-zinc-100 dark:border-zinc-700/50">
|
||||
<h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">Did you know?</h3>
|
||||
<p class="mt-2 text-zinc-700 dark:text-zinc-300 text-sm" id="fun-fact">
|
||||
The 404 error code originated when CERN's web server displayed room 404 (their server room) as the error message when a file wasn't found.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
// Go back functionality
|
||||
document.getElementById('back-button')?.addEventListener('click', () => {
|
||||
window.history.back();
|
||||
});
|
||||
|
||||
// Array of fun 404 facts
|
||||
const funFacts = [
|
||||
"The 404 error code originated when CERN's web server displayed room 404 (their server room) as the error message when a file wasn't found.",
|
||||
"In internet slang, '404' has become shorthand for something that's missing or someone who's clueless.",
|
||||
"Some websites turn their 404 pages into games, like Google's Pac-Man 404 page that once existed.",
|
||||
"The first web server was a NeXT computer used by Tim Berners-Lee at CERN, where the 404 error was born.",
|
||||
"Many companies use creative 404 pages as a way to showcase their brand personality and humor.",
|
||||
"The HTTP 1.0 specification from 1996 officially defined the 404 error as 'Not Found'.",
|
||||
"Studies show that well-designed 404 pages can reduce bounce rates by up to 30%.",
|
||||
"The most common cause of 404 errors is mistyped URLs."
|
||||
];
|
||||
|
||||
// Display a random fun fact
|
||||
const funFactElement = document.getElementById('fun-fact');
|
||||
if (funFactElement) {
|
||||
const randomFact = funFacts[Math.floor(Math.random() * funFacts.length)];
|
||||
funFactElement.textContent = randomFact;
|
||||
}
|
||||
|
||||
// Handle SPA transitions for 404 page
|
||||
function setupSPATransitions() {
|
||||
// Handle all internal links for SPA transitions
|
||||
document.querySelectorAll('a[href^="/"]').forEach(link => {
|
||||
// Skip links that are anchor links, external links, or already processed
|
||||
if (link.getAttribute('href').includes('#') ||
|
||||
link.getAttribute('target') === '_blank' ||
|
||||
link.hasAttribute('data-spa-handled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark as handled to avoid duplicate listeners
|
||||
link.setAttribute('data-spa-handled', 'true');
|
||||
|
||||
link.addEventListener('click', (e) => {
|
||||
// Don't handle if modifier keys are pressed (for opening in new tab, etc.)
|
||||
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
const targetHref = link.getAttribute('href');
|
||||
|
||||
// Trigger page transition animation
|
||||
const pageTransition = document.getElementById('page-transition');
|
||||
if (pageTransition) {
|
||||
pageTransition.classList.remove('opacity-0');
|
||||
pageTransition.classList.add('opacity-100');
|
||||
|
||||
// Navigate after transition effect
|
||||
setTimeout(() => {
|
||||
window.location.href = targetHref;
|
||||
}, 300);
|
||||
} else {
|
||||
// Fallback if transition element doesn't exist
|
||||
window.location.href = targetHref;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Re-initialize back button after SPA navigation
|
||||
const backButton = document.getElementById('back-button');
|
||||
if (backButton) {
|
||||
backButton.addEventListener('click', () => {
|
||||
window.history.back();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on first load
|
||||
document.addEventListener('DOMContentLoaded', setupSPATransitions);
|
||||
|
||||
// Re-initialize when content changes via Astro's view transitions
|
||||
document.addEventListener('astro:page-load', setupSPATransitions);
|
||||
|
||||
// For compatibility with custom transition system
|
||||
document.addEventListener('page-transition-complete', setupSPATransitions);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Animation for floating blobs */
|
||||
@keyframes blob {
|
||||
0% {
|
||||
transform: translate(0px, 0px) scale(1);
|
||||
}
|
||||
33% {
|
||||
transform: translate(30px, -50px) scale(1.1);
|
||||
}
|
||||
66% {
|
||||
transform: translate(-20px, 20px) scale(0.9);
|
||||
}
|
||||
100% {
|
||||
transform: translate(0px, 0px) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-blob {
|
||||
animation: blob 7s infinite;
|
||||
}
|
||||
|
||||
.animation-delay-2000 {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.animation-delay-4000 {
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
/* Glitch effect for 404 text */
|
||||
.glitch-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.glitch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
animation: glitch-skew 1s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
.glitch::before,
|
||||
.glitch::after {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.glitch::before {
|
||||
left: 2px;
|
||||
text-shadow: -2px 0 #ff00c1;
|
||||
clip: rect(44px, 450px, 56px, 0);
|
||||
animation: glitch-anim 5s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
.glitch::after {
|
||||
left: -2px;
|
||||
text-shadow: -2px 0 #00fff9, 2px 2px #ff00c1;
|
||||
animation: glitch-anim2 1s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
@keyframes glitch-anim {
|
||||
0% {
|
||||
clip: rect(31px, 9999px, 94px, 0);
|
||||
transform: skew(0.85deg);
|
||||
}
|
||||
5% {
|
||||
clip: rect(70px, 9999px, 71px, 0);
|
||||
transform: skew(0.17deg);
|
||||
}
|
||||
10% {
|
||||
clip: rect(9px, 9999px, 85px, 0);
|
||||
transform: skew(0.4deg);
|
||||
}
|
||||
15% {
|
||||
clip: rect(47px, 9999px, 18px, 0);
|
||||
transform: skew(0.22deg);
|
||||
}
|
||||
20% {
|
||||
clip: rect(7px, 9999px, 78px, 0);
|
||||
transform: skew(0.96deg);
|
||||
}
|
||||
25% {
|
||||
clip: rect(53px, 9999px, 54px, 0);
|
||||
transform: skew(0.05deg);
|
||||
}
|
||||
30% {
|
||||
clip: rect(84px, 9999px, 52px, 0);
|
||||
transform: skew(0.94deg);
|
||||
}
|
||||
35% {
|
||||
clip: rect(46px, 9999px, 7px, 0);
|
||||
transform: skew(0.01deg);
|
||||
}
|
||||
40% {
|
||||
clip: rect(2px, 9999px, 66px, 0);
|
||||
transform: skew(0.66deg);
|
||||
}
|
||||
45% {
|
||||
clip: rect(34px, 9999px, 33px, 0);
|
||||
transform: skew(0.52deg);
|
||||
}
|
||||
50% {
|
||||
clip: rect(80px, 9999px, 73px, 0);
|
||||
transform: skew(0.9deg);
|
||||
}
|
||||
55% {
|
||||
clip: rect(8px, 9999px, 81px, 0);
|
||||
transform: skew(0.3deg);
|
||||
}
|
||||
60% {
|
||||
clip: rect(10px, 9999px, 86px, 0);
|
||||
transform: skew(0.85deg);
|
||||
}
|
||||
65% {
|
||||
clip: rect(36px, 9999px, 25px, 0);
|
||||
transform: skew(0.28deg);
|
||||
}
|
||||
70% {
|
||||
clip: rect(75px, 9999px, 31px, 0);
|
||||
transform: skew(0.46deg);
|
||||
}
|
||||
75% {
|
||||
clip: rect(46px, 9999px, 87px, 0);
|
||||
transform: skew(0.44deg);
|
||||
}
|
||||
80% {
|
||||
clip: rect(19px, 9999px, 40px, 0);
|
||||
transform: skew(0.07deg);
|
||||
}
|
||||
85% {
|
||||
clip: rect(85px, 9999px, 88px, 0);
|
||||
transform: skew(0.71deg);
|
||||
}
|
||||
90% {
|
||||
clip: rect(1px, 9999px, 89px, 0);
|
||||
transform: skew(0.76deg);
|
||||
}
|
||||
95% {
|
||||
clip: rect(44px, 9999px, 25px, 0);
|
||||
transform: skew(0.58deg);
|
||||
}
|
||||
100% {
|
||||
clip: rect(31px, 9999px, 26px, 0);
|
||||
transform: skew(0.6deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glitch-anim2 {
|
||||
0% {
|
||||
clip: rect(65px, 9999px, 65px, 0);
|
||||
transform: skew(0.16deg);
|
||||
}
|
||||
5% {
|
||||
clip: rect(8px, 9999px, 42px, 0);
|
||||
transform: skew(0.65deg);
|
||||
}
|
||||
10% {
|
||||
clip: rect(64px, 9999px, 30px, 0);
|
||||
transform: skew(0.42deg);
|
||||
}
|
||||
15% {
|
||||
clip: rect(29px, 9999px, 49px, 0);
|
||||
transform: skew(0.05deg);
|
||||
}
|
||||
20% {
|
||||
clip: rect(25px, 9999px, 56px, 0);
|
||||
transform: skew(0.09deg);
|
||||
}
|
||||
25% {
|
||||
clip: rect(76px, 9999px, 98px, 0);
|
||||
transform: skew(0.79deg);
|
||||
}
|
||||
30% {
|
||||
clip: rect(72px, 9999px, 3px, 0);
|
||||
transform: skew(0.12deg);
|
||||
}
|
||||
35% {
|
||||
clip: rect(20px, 9999px, 60px, 0);
|
||||
transform: skew(0.09deg);
|
||||
}
|
||||
40% {
|
||||
clip: rect(61px, 9999px, 47px, 0);
|
||||
transform: skew(0.45deg);
|
||||
}
|
||||
45% {
|
||||
clip: rect(29px, 9999px, 69px, 0);
|
||||
transform: skew(0.09deg);
|
||||
}
|
||||
50% {
|
||||
clip: rect(82px, 9999px, 96px, 0);
|
||||
transform: skew(0.05deg);
|
||||
}
|
||||
55% {
|
||||
clip: rect(33px, 9999px, 91px, 0);
|
||||
transform: skew(0.16deg);
|
||||
}
|
||||
60% {
|
||||
clip: rect(56px, 9999px, 23px, 0);
|
||||
transform: skew(0.01deg);
|
||||
}
|
||||
65% {
|
||||
clip: rect(46px, 9999px, 21px, 0);
|
||||
transform: skew(0.89deg);
|
||||
}
|
||||
70% {
|
||||
clip: rect(50px, 9999px, 1px, 0);
|
||||
transform: skew(0.85deg);
|
||||
}
|
||||
75% {
|
||||
clip: rect(82px, 9999px, 33px, 0);
|
||||
transform: skew(0.87deg);
|
||||
}
|
||||
80% {
|
||||
clip: rect(94px, 9999px, 46px, 0);
|
||||
transform: skew(0.64deg);
|
||||
}
|
||||
85% {
|
||||
clip: rect(48px, 9999px, 95px, 0);
|
||||
transform: skew(0.43deg);
|
||||
}
|
||||
90% {
|
||||
clip: rect(60px, 9999px, 10px, 0);
|
||||
transform: skew(0.29deg);
|
||||
}
|
||||
95% {
|
||||
clip: rect(85px, 9999px, 62px, 0);
|
||||
transform: skew(0.66deg);
|
||||
}
|
||||
100% {
|
||||
clip: rect(61px, 9999px, 58px, 0);
|
||||
transform: skew(0.74deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glitch-skew {
|
||||
0% {
|
||||
transform: skew(-1deg);
|
||||
}
|
||||
10% {
|
||||
transform: skew(0deg);
|
||||
}
|
||||
20% {
|
||||
transform: skew(0.5deg);
|
||||
}
|
||||
30% {
|
||||
transform: skew(-0.5deg);
|
||||
}
|
||||
40% {
|
||||
transform: skew(0.2deg);
|
||||
}
|
||||
50% {
|
||||
transform: skew(0deg);
|
||||
}
|
||||
60% {
|
||||
transform: skew(-0.5deg);
|
||||
}
|
||||
70% {
|
||||
transform: skew(0.8deg);
|
||||
}
|
||||
80% {
|
||||
transform: skew(-0.2deg);
|
||||
}
|
||||
90% {
|
||||
transform: skew(0.5deg);
|
||||
}
|
||||
100% {
|
||||
transform: skew(0deg);
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user