372 lines
9.6 KiB
Plaintext
372 lines
9.6 KiB
Plaintext
---
|
|
// 404.astro - Custom 404 error page
|
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
import Header from '../components/Header.astro';
|
|
import Footer from '../components/Footer.astro';
|
|
import Terminal from '../components/Terminal.astro';
|
|
|
|
// Terminal commands for the 404 page
|
|
const terminalCommands = [
|
|
{
|
|
prompt: "[system@argobox]$ ",
|
|
command: "find /var/www/laforceit -name \"requested-page\"",
|
|
output: ["find: No matches found"]
|
|
},
|
|
{
|
|
prompt: "[system@argobox]$ ",
|
|
command: "grep -r \"requested-page\" /var/www/laforceit",
|
|
output: ["No matches found in site content"]
|
|
},
|
|
{
|
|
prompt: "[system@argobox]$ ",
|
|
command: "echo $?",
|
|
output: ["1"]
|
|
},
|
|
{
|
|
prompt: "[system@argobox]$ ",
|
|
command: "suggest_pages",
|
|
output: [
|
|
"Running site diagnostics...",
|
|
"Suggested pages:",
|
|
" - <a href='/'>Home</a>",
|
|
" - <a href='/blog'>Blog</a>",
|
|
" - <a href='/resources'>Resources</a>",
|
|
" - <a href='/projects'>Projects</a>"
|
|
]
|
|
},
|
|
{
|
|
prompt: "[system@argobox]$ ",
|
|
command: "return --code=404",
|
|
}
|
|
];
|
|
|
|
// Random tech error messages
|
|
const errorMessages = [
|
|
"Connection terminated unexpectedly.",
|
|
"Resource allocation failed: Page not found.",
|
|
"Route resolution error: Destination unreachable.",
|
|
"404: The requested URL does not exist on this server.",
|
|
"Network path not found: Check your request and try again."
|
|
];
|
|
|
|
// Get a random error message
|
|
const randomError = errorMessages[Math.floor(Math.random() * errorMessages.length)];
|
|
---
|
|
|
|
<BaseLayout title="404 - Page Not Found | LaForceIT" description="The requested page was not found on the LaForceIT tech blog.">
|
|
<Header slot="header" />
|
|
|
|
<main class="error-container">
|
|
<div class="error-content">
|
|
<div class="error-code">
|
|
<span class="error-digit">4</span>
|
|
<div class="error-digit-middle">
|
|
<div class="error-spinner"></div>
|
|
<span>0</span>
|
|
</div>
|
|
<span class="error-digit">4</span>
|
|
</div>
|
|
|
|
<h1 class="error-title">Page Not Found</h1>
|
|
<p class="error-message">{randomError}</p>
|
|
|
|
<div class="error-actions">
|
|
<a href="/" class="primary-button">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
|
|
<polyline points="9 22 9 12 15 12 15 22"></polyline>
|
|
</svg>
|
|
<span>Return Home</span>
|
|
</a>
|
|
<a href="/blog" class="secondary-button">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
|
<polyline points="15 3 21 3 21 9"></polyline>
|
|
<line x1="10" y1="14" x2="21" y2="3"></line>
|
|
</svg>
|
|
<span>Browse Articles</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="error-terminal">
|
|
<Terminal commands={terminalCommands} title="system-error-trace" />
|
|
</div>
|
|
|
|
<div class="error-bg"></div>
|
|
<div class="glitch-effect"></div>
|
|
</main>
|
|
|
|
<Footer slot="footer" />
|
|
</BaseLayout>
|
|
|
|
<style>
|
|
.error-container {
|
|
min-height: 70vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 2rem;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.error-bg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-image:
|
|
radial-gradient(circle at 20% 35%, rgba(239, 68, 68, 0.05) 0%, transparent 50%),
|
|
radial-gradient(circle at 75% 15%, rgba(6, 182, 212, 0.05) 0%, transparent 45%),
|
|
radial-gradient(circle at 85% 70%, rgba(139, 92, 246, 0.05) 0%, transparent 40%);
|
|
z-index: -1;
|
|
}
|
|
|
|
.error-bg::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-image:
|
|
linear-gradient(rgba(226, 232, 240, 0.03) 1px, transparent 1px),
|
|
linear-gradient(90deg, rgba(226, 232, 240, 0.03) 1px, transparent 1px);
|
|
background-size: 30px 30px;
|
|
}
|
|
|
|
.error-content {
|
|
max-width: 600px;
|
|
text-align: center;
|
|
margin-bottom: 3rem;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.error-code {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 8rem;
|
|
font-weight: 800;
|
|
margin-bottom: 2rem;
|
|
line-height: 1;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.error-digit {
|
|
background: linear-gradient(135deg, var(--accent-primary), var(--accent-tertiary));
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
text-shadow: 0 5px 15px rgba(6, 182, 212, 0.3);
|
|
}
|
|
|
|
.error-digit-middle {
|
|
position: relative;
|
|
width: 100px;
|
|
height: 130px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: var(--accent-secondary);
|
|
}
|
|
|
|
.error-spinner {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
border: 4px solid rgba(59, 130, 246, 0.2);
|
|
border-top: 4px solid var(--accent-secondary);
|
|
border-radius: 50%;
|
|
animation: spin 2s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
|
|
.error-title {
|
|
font-size: 2.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.error-message {
|
|
color: var(--text-secondary);
|
|
font-size: 1.1rem;
|
|
margin-bottom: 2rem;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.error-actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
justify-content: center;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.primary-button {
|
|
padding: 0.8rem 1.5rem;
|
|
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
|
color: var(--bg-primary);
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
border: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
box-shadow: 0 4px 15px rgba(6, 182, 212, 0.3);
|
|
}
|
|
|
|
.primary-button:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 8px 20px rgba(6, 182, 212, 0.4);
|
|
}
|
|
|
|
.secondary-button {
|
|
padding: 0.8rem 1.5rem;
|
|
background: rgba(226, 232, 240, 0.1);
|
|
color: var(--text-primary);
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.secondary-button:hover {
|
|
background: rgba(226, 232, 240, 0.2);
|
|
border-color: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.error-terminal {
|
|
width: 100%;
|
|
max-width: 700px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.glitch-effect {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(45deg,
|
|
rgba(255, 0, 0, 0) 45%,
|
|
rgba(255, 0, 0, 0.03) 50%,
|
|
rgba(255, 0, 0, 0) 55%
|
|
);
|
|
background-size: 200% 200%;
|
|
pointer-events: none;
|
|
animation: glitch-scan 4s ease-in-out infinite;
|
|
z-index: 2;
|
|
mix-blend-mode: overlay;
|
|
}
|
|
|
|
@keyframes glitch-scan {
|
|
0%, 100% {
|
|
background-position: 0% 0%;
|
|
opacity: 0;
|
|
}
|
|
25%, 75% {
|
|
opacity: 0;
|
|
}
|
|
50% {
|
|
background-position: 100% 100%;
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.error-code {
|
|
font-size: 5rem;
|
|
}
|
|
|
|
.error-title {
|
|
font-size: 2rem;
|
|
}
|
|
|
|
.error-digit-middle {
|
|
width: 70px;
|
|
height: 90px;
|
|
}
|
|
|
|
.error-actions {
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
// Add some randomized glitch effects to the 404 page
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const errorContainer = document.querySelector('.error-container');
|
|
const errorDigit = document.querySelectorAll('.error-digit');
|
|
|
|
// Random glitch effect for the error digits
|
|
function glitchEffect() {
|
|
const randomDigit = errorDigit[Math.floor(Math.random() * errorDigit.length)];
|
|
|
|
randomDigit.style.opacity = '0.8';
|
|
randomDigit.style.transform = `translateX(${Math.random() * 5 - 2.5}px)`;
|
|
|
|
setTimeout(() => {
|
|
randomDigit.style.opacity = '1';
|
|
randomDigit.style.transform = 'translateX(0)';
|
|
}, 100);
|
|
}
|
|
|
|
// Create data corruption effect in background
|
|
function createCorruptionEffect() {
|
|
const corruptionLine = document.createElement('div');
|
|
corruptionLine.classList.add('corruption-line');
|
|
|
|
// Random positioning and styling
|
|
const top = Math.random() * 100;
|
|
const width = Math.random() * 100;
|
|
const duration = Math.random() * 2 + 0.5;
|
|
|
|
corruptionLine.style.cssText = `
|
|
position: absolute;
|
|
top: ${top}%;
|
|
left: 0;
|
|
height: 1px;
|
|
width: ${width}%;
|
|
background: rgba(6, 182, 212, 0.4);
|
|
z-index: 0;
|
|
transform: translateX(-100%);
|
|
animation: slideRight ${duration}s forwards ease-out;
|
|
`;
|
|
|
|
errorContainer.appendChild(corruptionLine);
|
|
|
|
// Remove after animation is complete
|
|
setTimeout(() => {
|
|
corruptionLine.remove();
|
|
}, duration * 1000);
|
|
}
|
|
|
|
// Set intervals for effects
|
|
setInterval(glitchEffect, 3000);
|
|
setInterval(createCorruptionEffect, 2000);
|
|
|
|
// Add keyframe animation dynamically
|
|
const style = document.createElement('style');
|
|
style.innerHTML = `
|
|
@keyframes slideRight {
|
|
0% { transform: translateX(-100%); }
|
|
100% { transform: translateX(100vw); }
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
});
|
|
</script> |