feat(design): comprehensive redesign — top-tier portfolio UX

Größeres Redesign, das die Seite spürbar besser macht. Behält das
Magenta/Grün-Dark-Thing, poliert aber alles drumherum.

Neue Komponenten:
- hero-banner: full-bleed Hero mit AI-generiertem Hintergrund (grok-imagine-image,
  1280×720, Magenta/Grün-Akzente), Terminal-Boot-Animation mit Tipp-Effekt,
  Rotating-Role-Animation, animiertes Grid-Overlay.
- command-palette: �K / Ctrl+K öffnet ein durchsuchbares Modal mit Navigation,
  Projekt-Suche, Aktionen (Gitea/w-make.com/Admin) und Easter Eggs. Tastatur
  ↑↓/Enter/Esc, gruppiert nach Typ, mit Vorschau-Hints.
- custom-cursor: Canvas-basierter Cursor mit Trail für Desktop, 14 Punkte,
  Farbwechsel Magenta↔Grün, Hover-State für interaktive Elemente. Touch-
  Devices behalten den Default-Cursor.
- scroll-progress: Top-Bar mit Magenta→Grün-Gradient.
- tilt-card: 3D-Hover mit Mouse-Tracking (CSS-Variablen --rx/--ry/--mx/--my).
- stack-icon: 13 handgezeichnete inline SVGs (TypeScript, Node, Python, Rust,
  SQLite, Tailwind, React, Docker, Gitea, Next, Nix, Hermes, Shell, Self-Host).
  Kein CDN, kein Hydration, currentColor-aware.
- project-filter: tag-basierter Filter für Projekt-Liste, Status-Tone-Tags
  (live/warm/muted) plus Kategorie-Tags, useTransition für sanfte Updates.

Pages-Update:
- Home (/): neuer Hero-Banner, Featured-Grid mit Tilt-Cards und KI-generierten
  Thumbnails (hermes.jpg, casino-bot.jpg, polymarket-trader.jpg), darunter
  filterbare Projekt-Liste, Bio + Links Sidebar.
- Projects: filterbar nach Kategorie und Status.
- Project-Detail: Hero-Image (für 3 Projekte), Stack-Pills mit SVG-Icons,
  bessere Sektionierung (~/stack, ~/notes).
- About: Stack-Visualisierung mit 13 Einträgen in einem Grid.
- OpenGraph-Image pro Projekt (Next.js native, 1200×630): eldov-Logo,
  Projekt-Slug in Magenta, Status-Badge, Kategorie-Badge.

Build-Hash-Support:
- NEXT_PUBLIC_BUILD_HASH + NEXT_PUBLIC_BUILD_DATE werden via Docker ARG in
  die Footer geschrieben ("build abc1234 · 2026-08-31"), deploy-vps.sh
  ermittelt Commit-Hash automatisch aus git und gibt ihn weiter.

Theme v2:
- Tiefere Palette (--bg #0a0a10, --bg-deep #050508), --fg-dim für Hierarchie.
- Neue Komponenten-Klassen: tilt-card, stack-pill, tag, hero-bg, hero-banner,
  scroll-progress, cursor-blink, type-in, glow-text.
- ASCII-Box-Hover-Effekt mit Akzent-Border.

Public-Bilder unter public/img/{hero,projects}/ — KI-generiert via xAI
grok-imagine-image (Token aus .hermes-state/credentials/xai.json), alle
im Marken-Stil (Magenta/Grün/dunkel). 4 Bilder, ~960 KB total.

Sonstiges:
- Header mit ⌘K-Hint, sticky+blur.
- Footer mit Build-Hash, externen Links, Datenschutz-Badge.
- About-Page mit Stack-Grid.
This commit is contained in:
Jan Wagner
2026-08-31 20:58:48 +02:00
parent 9ceead6ab6
commit 6cdd8438ae
24 changed files with 1460 additions and 177 deletions
+63 -27
View File
@@ -5,8 +5,15 @@ import { getDict } from "@/i18n/dictionaries";
import { LanguageSwitcher } from "./language-switcher";
import { MobileNav } from "./mobile-nav";
import { site } from "@/content/site";
import { CommandPalette } from "./command-palette";
export function SiteHeader({ locale }: { locale: Locale }) {
export function SiteHeader({
locale,
projects,
}: {
locale: Locale;
projects: Array<{ slug: string; summary: string; category: string; status: string }>;
}) {
const dict = getDict(locale);
const nav = [
{ href: publicPath(locale, "about"), label: dict.nav.about },
@@ -15,34 +22,63 @@ export function SiteHeader({ locale }: { locale: Locale }) {
];
return (
<header className="border-b border-hairline bg-[var(--bg-deep)]">
<div className="mx-auto flex max-w-5xl items-center justify-between px-4 py-4">
<Link href={publicPath(locale, "home")} className="flex items-center gap-2 font-mono text-sm">
<span className="text-accent">$</span>
<span className="text-[var(--fg)]">{site.handle}</span>
<span className="text-muted">@eldov.win</span>
</Link>
<nav className="hidden gap-6 md:flex" aria-label="primary">
{nav.map((n) => (
<Link
key={n.href}
href={n.href}
className="font-mono text-sm text-[var(--fg)] transition-colors hover:text-accent"
<>
<header className="sticky top-0 z-40 border-b border-hairline bg-[color-mix(in_oklab,var(--bg-deep)_85%,transparent)] backdrop-blur-md">
<div className="mx-auto flex max-w-[var(--max-w)] items-center justify-between gap-3 px-4 py-3 md:px-6">
<Link href={publicPath(locale, "home")} className="group flex items-center gap-2.5 font-mono text-sm" data-cursor="hover">
<span className="inline-flex h-6 w-6 items-center justify-center rounded-sm border border-accent text-[11px] font-bold text-accent transition-colors group-hover:bg-accent group-hover:text-[var(--bg-deep)]">e</span>
<span className="text-[var(--fg)]">{site.handle}</span>
<span className="hidden text-muted md:inline">@eldov.win</span>
</Link>
<div className="flex items-center gap-1 md:gap-4">
<nav className="hidden gap-1 md:flex" aria-label="primary">
{nav.map((n) => (
<Link
key={n.href}
href={n.href}
className="rounded px-3 py-1.5 font-mono text-sm text-[var(--fg-dim)] transition-colors hover:bg-[color-mix(in_oklab,var(--accent)_8%,transparent)] hover:text-accent"
data-cursor="hover"
>
{n.label}
</Link>
))}
</nav>
<div className="hidden md:block">
<LanguageSwitcher currentLocale={locale} />
</div>
<button
type="button"
aria-label="Command palette öffnen"
data-cursor="hover"
onClick={() => {
window.dispatchEvent(new KeyboardEvent("keydown", { key: "k", metaKey: true }));
}}
className="flex items-center gap-1.5 rounded border border-hairline bg-[color-mix(in_oklab,var(--panel)_50%,transparent)] px-2.5 py-1.5 font-mono text-xs text-muted transition-colors hover:border-accent hover:text-[var(--fg)]"
>
{n.label}
</Link>
))}
<LanguageSwitcher currentLocale={locale} />
</nav>
<MobileNav locale={locale} items={nav} menuLabel={dict.nav.menu} switchLabel={dict.actions.languageSwitch} />
</div>
{locale === defaultLocale ? (
<div className="border-t border-hairline bg-[var(--bg-deep)]">
<div className="mx-auto max-w-5xl px-4 py-1 font-mono text-xs text-muted">
<span className="text-accent">note:</span> geschäftliche Anfragen bitte an w-make.com.
<span className="font-mono text-base leading-none"></span>
<span>K</span>
</button>
<MobileNav locale={locale} items={nav} menuLabel={dict.nav.menu} switchLabel={dict.actions.languageSwitch} />
</div>
</div>
) : null}
</header>
{locale === defaultLocale ? (
<div className="border-t border-hairline-2 bg-[var(--bg-deep)]">
<div className="mx-auto max-w-[var(--max-w)] px-4 py-1 font-mono text-[11px] text-muted md:px-6">
<span className="text-accent">note:</span>{" "}
geschäftliche Anfragen bitte an{" "}
<a
href="https://w-make.com"
rel="noopener noreferrer"
className="text-[var(--fg-dim)] underline decoration-dotted underline-offset-2 hover:text-accent"
>
w-make.com
</a>
.
</div>
</div>
) : null}
</header>
<CommandPalette locale={locale} projects={projects} />
</>
);
}