3.8 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
impressum/ # Impressum-Seite
datenschutz/ # Datenschutzerklärung
components/
hero.tsx # Hero-Section mit Gradient-Überschrift
about-section.tsx
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)
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:
- Lokal: http://localhost:3000/landingpage
- Netzwerk: http://192.168.179.124:3000/landingpage (Handy im WLAN)
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
Localhost (zum Testen)
./deploy_to_localhost.sh
- rsync nach
/var/www/html/landingpage/ - Symlink:
/var/www/html/index.html→landingpage/index.html 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.
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.
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.