Feature: Eigene 404-Seite im Landingpage-Stil
app/not-found.tsx erzeugt landingpage/404.html (Terminal-Look mit angefragtem Pfad). Die Deploy-Skripte kopieren sie zusätzlich in den Webroot, damit sie auch außerhalb von /landingpage/ greift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
99c6c9516c
commit
ea2bcfbd27
4 changed files with 153 additions and 0 deletions
127
app/not-found.tsx
Normal file
127
app/not-found.tsx
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { ArrowLeft, FolderGit2 } from 'lucide-react'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { RequestedPath } from '@/components/requested-path'
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: '404 – Seite nicht gefunden | Jamulix',
|
||||||
|
description: 'Diese Seite ist vom Lochkartenstapel gefallen.',
|
||||||
|
robots: { index: false, follow: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<main className="relative min-h-screen flex flex-col overflow-hidden">
|
||||||
|
{/* Fly.io-style gradient mesh background (dark mode only) */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-mesh hidden dark:block" />
|
||||||
|
|
||||||
|
{/* Subtle grid overlay */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 opacity-[0.02] dark:opacity-[0.04]"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `
|
||||||
|
linear-gradient(to right, currentColor 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, currentColor 1px, transparent 1px)
|
||||||
|
`,
|
||||||
|
backgroundSize: '60px 60px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Logo */}
|
||||||
|
<div className="relative max-w-6xl w-full mx-auto px-6 lg:px-8">
|
||||||
|
<div className="flex items-center h-16 lg:h-20">
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="font-mono text-lg tracking-tight text-foreground hover:text-accent transition-colors"
|
||||||
|
>
|
||||||
|
Jamulix
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative flex-1 flex items-center">
|
||||||
|
<div className="max-w-6xl w-full mx-auto px-6 lg:px-8 py-12 lg:py-20">
|
||||||
|
<div className="grid lg:grid-cols-12 gap-12 lg:gap-16 items-center">
|
||||||
|
{/* Text Content */}
|
||||||
|
<div className="lg:col-span-6 space-y-8">
|
||||||
|
<div>
|
||||||
|
<span className="inline-block font-mono text-xs tracking-wider text-accent uppercase mb-4">
|
||||||
|
Fehler 404 · Seite nicht gefunden
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<p
|
||||||
|
aria-hidden="true"
|
||||||
|
className="font-serif font-bold text-8xl sm:text-9xl leading-none tracking-tighter text-foreground/90 dark:bg-gradient-to-r dark:from-cyan-400 dark:to-violet-400 dark:bg-clip-text dark:text-transparent"
|
||||||
|
>
|
||||||
|
404
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h1 className="mt-6 font-serif text-3xl sm:text-4xl lg:text-5xl leading-[1.1] tracking-tight text-balance">
|
||||||
|
Diese Seite ist vom Lochkartenstapel gefallen.
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-lg text-muted-foreground leading-relaxed max-w-xl">
|
||||||
|
Seit 50 Jahren Code – und trotzdem verlegt man gelegentlich
|
||||||
|
etwas. Die gesuchte Seite existiert nicht, nicht mehr oder
|
||||||
|
noch nicht. Vielleicht war auch nur ein übereifriges{' '}
|
||||||
|
<code className="font-mono text-sm text-accent">rm -rf</code>{' '}
|
||||||
|
am Werk.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4">
|
||||||
|
<Button asChild size="lg" className="group">
|
||||||
|
<Link href="/">
|
||||||
|
<ArrowLeft className="mr-2 size-4 transition-transform group-hover:-translate-x-0.5" />
|
||||||
|
cd ~ — Zur Startseite
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button asChild variant="outline" size="lg" className="group">
|
||||||
|
<Link href="/#projekte">
|
||||||
|
<FolderGit2 className="mr-2 size-4" />
|
||||||
|
Projekte ansehen
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Terminal */}
|
||||||
|
<div className="lg:col-span-6">
|
||||||
|
<div className="rounded-lg border border-border bg-card shadow-xl dark:shadow-[0_0_40px_oklch(0.70_0.22_280/0.3)] overflow-hidden">
|
||||||
|
<div className="flex items-center gap-2 px-4 py-3 border-b border-border bg-muted/50">
|
||||||
|
<span className="size-3 rounded-full bg-red-500/80" />
|
||||||
|
<span className="size-3 rounded-full bg-yellow-500/80" />
|
||||||
|
<span className="size-3 rounded-full bg-green-500/80" />
|
||||||
|
<span className="ml-3 font-mono text-xs text-muted-foreground">
|
||||||
|
jamulix@jamulix.de: ~
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pre className="p-5 sm:p-6 font-mono text-xs sm:text-sm leading-relaxed whitespace-pre-wrap text-card-foreground">
|
||||||
|
<span className="text-accent">$</span> cd <RequestedPath />{'\n'}
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
bash: cd: <RequestedPath />: Datei oder Verzeichnis nicht gefunden
|
||||||
|
</span>{'\n'}
|
||||||
|
<span className="text-accent">$</span> find / -name "seite" 2>/dev/null{'\n'}
|
||||||
|
<span className="text-accent">$</span> cat seite.f{'\n'}
|
||||||
|
<span className="text-muted-foreground">C GESTANZT 1976 – STAPEL LEIDER RUNTERGEFALLEN</span>{'\n'}
|
||||||
|
<span className="text-cyan-600 dark:text-cyan-400"> GO TO 404</span>{'\n'}
|
||||||
|
<span className="text-accent">$</span> sudo !!{'\n'}
|
||||||
|
<span className="text-destructive dark:text-red-400">
|
||||||
|
jamulix ist nicht in der sudoers-Datei. Dieser Vorfall wird gemeldet.
|
||||||
|
</span>{'\n'}
|
||||||
|
<span className="text-accent">$</span>{' '}
|
||||||
|
<span className="inline-block w-2 h-4 align-middle bg-foreground animate-pulse" />
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="mt-4 font-mono text-xs text-muted-foreground text-center lg:text-left">
|
||||||
|
Tipp: Auch nach 50 Jahren hilft <span className="text-accent">ls</span> meistens weiter.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
19
components/requested-path.tsx
Normal file
19
components/requested-path.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
// Shows the requested URL path; falls back to a placeholder without JS
|
||||||
|
export function RequestedPath() {
|
||||||
|
const [path, setPath] = useState('/gesuchte-seite')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const raw = window.location.pathname
|
||||||
|
try {
|
||||||
|
setPath(decodeURI(raw))
|
||||||
|
} catch {
|
||||||
|
setPath(raw) // malformed percent-encoding
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <span className="break-all">{path}</span>
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,10 @@ echo "Setze symbolischen Link: index.html → landingpage/index.html"
|
||||||
sudo rm -f /var/www/html/index.html
|
sudo rm -f /var/www/html/index.html
|
||||||
sudo ln -s landingpage/index.html /var/www/html/index.html
|
sudo ln -s landingpage/index.html /var/www/html/index.html
|
||||||
|
|
||||||
|
echo "Kopiere 404-Seite: landingpage/404.html → 404.html"
|
||||||
|
sudo cp landingpage/404.html /var/www/html/404.html
|
||||||
|
sudo chown www-data:www-data /var/www/html/404.html
|
||||||
|
|
||||||
sudo chown -R www-data:www-data /var/www/html/landingpage/
|
sudo chown -R www-data:www-data /var/www/html/landingpage/
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
|
|
@ -30,5 +30,8 @@ rsync -av --delete -e "ssh -S $SSH_SOCKET" landingpage/ "$REMOTE_USER@$REMOTE_HO
|
||||||
echo "Setze symbolischen Link: index.html → landingpage/index.html"
|
echo "Setze symbolischen Link: index.html → landingpage/index.html"
|
||||||
ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "rm -f '$REMOTE_DIR/index.html' && ln -s landingpage/index.html '$REMOTE_DIR/index.html'"
|
ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "rm -f '$REMOTE_DIR/index.html' && ln -s landingpage/index.html '$REMOTE_DIR/index.html'"
|
||||||
|
|
||||||
|
echo "Kopiere 404-Seite: landingpage/404.html → 404.html"
|
||||||
|
ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "cp '$REMOTE_DIR/landingpage/404.html' '$REMOTE_DIR/404.html'"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Deployment abgeschlossen: https://jamulix.de"
|
echo "Deployment abgeschlossen: https://jamulix.de"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue