jamulix-homepage/README.md
dschlueter 74b8d18991 Deploy: index.html wieder als Symlink auf landingpage/index.html
nginx folgt dem Link und liefert die Landingpage direkt unter
https://jamulix.de/ aus. Weiterleitungsseite webroot/index.html entfernt,
README angepasst.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:07:24 +02:00

6.4 KiB

jamulix.de — Landing Page

Next.js 16 Landing Page für jamulix.de, statisch exportiert und unter /landingpage/ deployed.


Tech Stack

  • Next.js 16.2 mit output: 'export' (statischer Export, kein Node.js-Server nötig)
  • React 19, TypeScript
  • Tailwind CSS v4 + shadcn/ui-Komponenten
  • Framer Motion für Animationen
  • next-themes für Dark/Light Mode

Projektstruktur

app/
  layout.tsx          # Root Layout, Fonts, Theme-Init-Script
  page.tsx            # Hauptseite (alle Sections zusammengesetzt)
  globals.css         # CSS-Variablen (OKLCH), Tailwind, Fly.io-Farbschema, Timeline-Animationen
  impressum/          # Impressum-Seite
  datenschutz/        # Datenschutzerklärung
  not-found.tsx       # 404-Seite
  401/ 403/ 500/ 502/ 503/ 504/   # weitere Fehlerseiten
components/
  hero.tsx            # Hero-Section mit Gradient-Überschrift
  about-section.tsx   # Motivation, Jamulix-Gesetze, Timeline
  timeline-holo.tsx   # Hologramm-Illustrationen zur Timeline (SVG)
  projects-section.tsx
  focus-section.tsx
  philosophy-section.tsx
  footer.tsx          # Footer mit E-Mail (obfuskiert) und Forgejo-Link
  header.tsx          # Navigation + Theme-Toggle
  programmer-graphic.tsx  # Foto (statischer Import wegen basePath)
  error-page.tsx      # Gemeinsames Layout der Fehlerseiten
  theme-toggle.tsx
  ui/                 # shadcn/ui-Basiskomponenten
public/
  Programmierer.png   # Foto (statischer Import in programmer-graphic.tsx)

Lokale Entwicklung

npm install
npm run dev

Aufruf im Browser:

Port 3000 muss in der Firewall offen sein: sudo ufw allow 3000/tcp


Build

npm run build

Erzeugt out/, benennt es in landingpage/ um. Dieses Verzeichnis wird deployed.


Persönliche Daten (Impressum / Datenschutz)

Werden nicht im Repository gespeichert, sondern zur Build-Zeit aus .env.local gelesen.

cp .env.local.example .env.local
# .env.local mit echten Daten befüllen

Variablen: OWNER_NAME, OWNER_STREET, OWNER_ZIP_CITY, OWNER_EMAIL, HOSTER_NAME, HOSTER_STREET, HOSTER_ZIP, HOSTER_CITY, HOSTER_COUNTRY

.env.local ist per .gitignore ausgeschlossen.

Die E-Mail im Footer (footer.tsx) wird als Prop von app/page.tsx übergeben:

<Footer email={process.env.OWNER_EMAIL} />

Deployment

Production (jamulix.de)

./deploy_to_production.sh
  • Baut die Seite (npm run build)
  • Öffnet eine SSH-Master-Verbindung (Passwort nur einmal eingeben)
  • rsync nach jamulix.de:/var/www/jamulix.de/html/landingpage/
  • Setzt Symlink: /var/www/jamulix.de/html/index.html → landingpage/index.html (nginx folgt dem Link und liefert die Landingpage direkt unter https://jamulix.de/ aus)
  • Kopiert die Fehlerseiten landingpage/<code>.html in den Webroot

Localhost (zum Testen)

./deploy_to_localhost.sh
  • rsync nach /var/www/html/landingpage/
  • Symlink: /var/www/html/index.html → landingpage/index.html
  • Kopiert die Fehlerseiten in den Webroot
  • sudo chown -R www-data:www-data

Warum /landingpage/ als Unterverzeichnis?

basePath: '/landingpage' in next.config.mjs erlaubt es, weitere Projekte unter jamulix.de/ zu betreiben ohne Konflikte. rsync mit --delete löscht nur Dateien innerhalb von landingpage/, nicht andere Verzeichnisse im Webroot.

Fehlerseiten

Code Quelle Thema
401 app/401/page.tsx Autorisierung erforderlich
403 app/403/page.tsx Zugriff verweigert
404 app/not-found.tsx Seite nicht gefunden
500 app/500/page.tsx Interner Serverfehler
502 app/502/page.tsx Bad Gateway
503 app/503/page.tsx Wartungsarbeiten
504 app/504/page.tsx Gateway Timeout

Gemeinsames Layout: components/error-page.tsx. Der Build erzeugt landingpage/<code>.html; die Deploy-Skripte kopieren sie zusätzlich nach <webroot>/<code>.html. Alle Asset-Pfade sind absolut (/landingpage/_next/…), daher funktionieren die Kopien im Webroot genauso.

Der nginx-server-Block für jamulix.de (nicht Teil dieses Repos) enthält dafür:

error_page 401 /401.html;
error_page 403 /403.html;
error_page 404 /404.html;
error_page 500 /500.html;
error_page 502 /502.html;
error_page 503 /503.html;
error_page 504 /504.html;
  • Ziel muss ein lokaler Pfad sein, keine vollständige URL (sonst wird daraus ein Redirect).
  • Die 401-Seite erscheint erst, wenn der Login-Dialog des Browsers abgebrochen wird.

Design

Fly.io-inspiriertes Farbschema (Variant A+B+C):

  • Dark Mode: Tiefes Navy (oklch(0.10 0.02 260)) + Violet-Akzent (oklch(0.65 0.22 280))
  • Light Mode: Warme Papiertöne + Violet-Akzent
  • Font: Plus Jakarta Sans (Headlines + Body), JetBrains Mono (Code)
  • Hero-Überschrift: Cyan→Violet Gradient im Dark Mode
  • Gradient Mesh im Hero-Hintergrund (nur Dark Mode)

Dark/Light Mode wird per localStorage gespeichert. Das Init-Script in app/layout.tsx verhindert Flash beim Laden.

Timeline-Illustrationen

components/timeline-holo.tsx enthält acht SVG-Szenen, je eine pro Timeline-Station (Lochkarte, PC, Atari ST, Unix, Linux, WWW, Server, KI). Stil angelehnt an das Hero-Foto: dunkler Raum, Magenta-Deckenlicht, Hologramm-Projektor mit Lichtkegel, schwebende Glas-Panels.

  • Zuordnung über das Feld art im timeline-Array in about-section.tsx; neue Szene = neuer TimelineArtId + Eintrag in SCENES.
  • Desktop: Grafik auf der dem Text gegenüberliegenden Seite; mobil darunter.
  • Die Szenen sind in beiden Themes dunkel (wie das Hero-Foto).
  • Reines SVG, keine Bilddateien. Filter-/Gradient-IDs sind pro Szene präfixiert (holo-<id>-…), da alle acht SVGs auf einer Seite stehen.
  • Animationen (tl-blink, tl-pulse, tl-flow, tl-flicker …) stehen in app/globals.css und werden bei prefers-reduced-motion abgeschaltet.
  • Die Lochkarte ist echter Hollerith-Code („C JAMULIX 1976 FORTRAN IV“).

Bilder

public/Programmierer.png muss als statischer Import eingebunden werden:

import programmiererImg from '../public/Programmierer.png'
// ...
<Image src={programmiererImg} ... />

Grund: next/image mit src="/Programmierer.png" (String) berücksichtigt basePath nicht korrekt bei statischem Export.