diff --git a/README.md b/README.md index 151b592..2a5fecf 100644 --- a/README.md +++ b/README.md @@ -20,18 +20,22 @@ Next.js 16 Landing Page für [jamulix.de](https://jamulix.de), statisch exportie app/ layout.tsx # Root Layout, Fonts, Theme-Init-Script page.tsx # Hauptseite (alle Sections zusammengesetzt) - globals.css # CSS-Variablen (OKLCH), Tailwind, Fly.io-Farbschema + 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 + 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/ @@ -98,6 +102,9 @@ Die E-Mail im Footer (`footer.tsx`) wird als Prop von `app/page.tsx` übergeben: - Ö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) +- Setzt Symlinks `__next.*.txt` → `landingpage/__next.*.txt` (Next.js lädt unter `/` die + RSC-Segmente ohne basePath; ohne die Links gibt es 404 im Netzwerk-Tab) - Kopiert die Fehlerseiten `landingpage/.html` in den Webroot ### Localhost (zum Testen) @@ -108,6 +115,7 @@ Die E-Mail im Footer (`footer.tsx`) wird als Prop von `app/page.tsx` übergeben: - rsync nach `/var/www/html/landingpage/` - Symlink: `/var/www/html/index.html` → `landingpage/index.html` +- Symlinks: `/var/www/html/__next.*.txt` → `landingpage/__next.*.txt` - Kopiert die Fehlerseiten in den Webroot - `sudo chown -R www-data:www-data` @@ -134,20 +142,19 @@ Gemeinsames Layout: `components/error-page.tsx`. Der Build erzeugt `/.html`. Alle Asset-Pfade sind absolut (`/landingpage/_next/…`), daher funktionieren die Kopien im Webroot genauso. -Damit Apache sie ausliefert, braucht die vHost-Konfiguration (nicht Teil -dieses Repos) z. B.: +Der nginx-`server`-Block für jamulix.de (nicht Teil dieses Repos) enthält dafür: -```apache -ErrorDocument 401 /401.html -ErrorDocument 403 /403.html -ErrorDocument 404 /404.html -ErrorDocument 500 /500.html -ErrorDocument 502 /502.html -ErrorDocument 503 /503.html -ErrorDocument 504 /504.html +```nginx +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; ``` -- `ErrorDocument 401` muss ein lokaler Pfad sein, keine vollständige URL. +- 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. --- @@ -165,6 +172,23 @@ ErrorDocument 504 /504.html 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--…`), 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 diff --git a/app/globals.css b/app/globals.css index 8be0836..ae1081f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -130,3 +130,17 @@ .dark ::selection { background: oklch(0.70 0.22 280 / 0.5); } + +/* ===== Timeline-Illustrationen (components/timeline-holo.tsx) ===== */ +@keyframes tl-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } } +@keyframes tl-spin { to { transform: rotate(360deg); } } +@keyframes tl-pulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } } +@keyframes tl-flow { to { stroke-dashoffset: -16; } } +@keyframes tl-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } } +@keyframes tl-flicker { 0%, 100% { opacity: 1; } 3% { opacity: 0.82; } 5% { opacity: 1; } 51% { opacity: 0.93; } 53% { opacity: 1; } } +.tl-art .tl-blink { animation: tl-blink 1.1s steps(1) infinite; } +.tl-art .tl-spin { transform-box: fill-box; transform-origin: center; animation: tl-spin 8s linear infinite; } +.tl-art .tl-pulse { animation: tl-pulse 2.4s ease-in-out infinite; } +.tl-art .tl-flow { stroke-dasharray: 4 4; animation: tl-flow 1s linear infinite; } +.tl-art .tl-bob { animation: tl-bob 4s ease-in-out infinite; } +.tl-art .tl-flicker { animation: tl-flicker 5s linear infinite; } diff --git a/app/layout.tsx b/app/layout.tsx index 2712b67..c8dff94 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,5 @@ import type { Metadata, Viewport } from 'next' import { Inter, Plus_Jakarta_Sans, JetBrains_Mono } from 'next/font/google' -import { Analytics } from '@vercel/analytics/next' import './globals.css' const inter = Inter({ @@ -90,7 +89,6 @@ export default function RootLayout({ {children} - {process.env.NODE_ENV === 'production' && } ) diff --git a/components/about-section.tsx b/components/about-section.tsx index af52888..64ed6e3 100644 --- a/components/about-section.tsx +++ b/components/about-section.tsx @@ -1,55 +1,64 @@ 'use client' import { motion } from 'framer-motion' +import { TimelineHolo, type TimelineArtId } from './timeline-holo' -const timeline = [ +const timeline: { era: string; title: string; description: string; tech: string[]; art: TimelineArtId }[] = [ { era: '1976', title: 'Der Anfang', description: 'Erste Programme in Fortran IV. Lochkarten, Großrechner, Batch-Verarbeitung. Erste Programmierkurse im Rahmen des VWL-Studiums. Die Grundlagen des algorithmischen Denkens.', tech: ['Fortran IV'], + art: 'lochkarte', }, { era: '1984', title: 'Der erste PC', description: 'Erste Programme in Basic, C und Pascal auf dem Personal Computer unter DOS. Datenbanken, Textverarbeitung, Spiele.', tech: ['Lotus 1-2-3', 'dBASE', 'QBasic', 'Turbo Pascal', 'Norton Commander', 'WordPerfect'], + art: 'pc', }, { era: '1986', title: 'Systemnahe Programmierung', description: 'C und 68000-Assembler auf dem Atari ST. Direkte Hardware-Ansteuerung, Interrupt-Routinen, Speicherverwaltung von Hand. Pseudo-Multitasking. DFÜ mit Akustikkoppler. Maiboxen, FidoNet, MausNet.', tech: ['C', '68000 ASM', 'GFA Basic', 'TOS'], + art: 'atari', }, { era: '1990', title: 'Unix an der Universität', description: 'AIX, HP-UX, BSD. Die Philosophie kleiner, zusammenarbeitender Programme. Shell-Scripting als Werkzeug. Internet. Sysop-Aufgaben im Uni-Rechenzentrum.', tech: ['Unix', 'Shell', 'vi', 'Gopher'], + art: 'unix', }, { era: '1992', title: 'Linux entdeckt', description: 'Slackware auf 40 Disketten, Debian, SUSE Linux ... Der Beginn einer dauerhaften Begeisterung für offene Systeme und Selbstbestimmung. C, C++, Pascal, Modula, Perl, Shell-Skript. Internet per Modem. Pentesting, Hacking.', tech: ['Linux', 'GNU Tools', 'X11'], + art: 'linux', }, { era: '1995 ff.', title: 'World Wide Web', description: 'Permanenter privater Internet-Zugang kommerzieller Anbieter und erste eigene Domain: linix.de. World Wide Web. Eigene Webseiten in HTML und JavaScript programmiert.', tech: ['WWW', 'Netscape', 'HTML', 'Java', 'JavaScript', 'Modem'], + art: 'www', }, { era: '2000er', title: 'Professionelle Entwicklung', description: 'Verschiedene Sprachen, verschiedene Domänen. Server-Administration, Automatisierung, Web-Entwicklung. Systemadministration, Networking. — Alles unter Linux.', tech: ['Perl', 'PHP', 'Bash', 'Python', 'Go', 'Proxmox', 'Docker/Podman'], + art: 'server', }, { era: '2022', title: 'KI-Fokus', description: 'Seit Ende 2022 intensive Beschäftigung mit KI-Tools und KI-Programmierung. LLMs als Arbeitswerkzeug und Forschungsgegenstand.', tech: ['Python', 'Rust', 'LLMs', 'ML'], + art: 'ki', }, ] @@ -227,7 +236,7 @@ export function AboutSection() { {/* Content */} -
+
{item.era}

{item.title}

@@ -247,8 +256,10 @@ export function AboutSection() {
- {/* Spacer for alternating layout */} - {index % 2 !== 0 &&
} + {/* Illustration on the opposite side */} +
+ +
))}
diff --git a/components/timeline-holo.tsx b/components/timeline-holo.tsx new file mode 100644 index 0000000..05e6504 --- /dev/null +++ b/components/timeline-holo.tsx @@ -0,0 +1,931 @@ +// Timeline-Illustrationen: Hologramm-Szenen im Stil des Hero-Bilds +// (dunkler Raum, Neon-Deckenlicht, Glas-Panels, Projektor auf dem Tisch). +// Bewusst themenunabhängig dunkel – wie ein Foto. + +export type TimelineArtId = + | 'lochkarte' + | 'pc' + | 'atari' + | 'unix' + | 'linux' + | 'www' + | 'server' + | 'ki' + +const MONO = { fontFamily: 'var(--font-jetbrains-mono), ui-monospace, monospace', whiteSpace: 'pre' } as const + +const CY = '#5ff3ff' +const CY_TXT = '#a8fbff' +const CY_DIM = '#4fc3d4' +const MAG = '#ff4fd8' +const SCREEN_DARK = '#062a33' +const SCREEN_LIGHT = '#d9fbff' + +type U = (name: string) => string + +function holo(u: U) { + return { + stroke: CY, + fill: 'none', + strokeWidth: 1.1, + strokeLinecap: 'round' as const, + strokeLinejoin: 'round' as const, + filter: `url(#${u('glow')})`, + } +} + +function T({ + x, + y, + size = 6, + color = CY_TXT, + anchor, + className, + children, +}: { + x: number + y: number + size?: number + color?: string + anchor?: 'start' | 'middle' | 'end' + className?: string + children: React.ReactNode +}) { + return ( + + {children} + + ) +} + +/* === Gemeinsame Bausteine: Raum, Projektor, Glas-Panel === */ + +function Defs({ u }: { u: U }) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +const BOKEH: [number, number, number, string, number][] = [ + [26, 70, 12, '#ff7a3d', 0.35], + [46, 128, 7, '#ff3d6e', 0.3], + [18, 186, 9, '#7a5cff', 0.25], + [374, 84, 11, '#3dd6ff', 0.3], + [356, 150, 6, '#ff7a3d', 0.22], + [388, 200, 8, MAG, 0.2], +] + +function Backdrop({ u }: { u: U }) { + const rays = [-240, -120, 0, 100, 200, 300, 400, 520, 640] + return ( + <> + + + {/* Rack-Silhouetten an der Rückwand */} + {[8, 36, 348, 376].map((x) => ( + + ))} + {BOKEH.map(([x, y, r, c, o], i) => ( + + ))} + + {/* Decke in Perspektive mit Neon-Leisten */} + + {rays.map((x) => ( + + ))} + + + + + + + + + + + {/* Tisch */} + + + {[-200, -60, 80, 200, 320, 460, 600].map((x) => ( + + ))} + + + + ) +} + +function Overlay({ u, caption }: { u: U; caption: string }) { + return ( + <> + + + + + {caption} + + + ) +} + +function Emitter({ u, cx, w = 100, top = 30 }: { u: U; cx: number; w?: number; top?: number }) { + return ( + + + + + + ) +} + +function GlassPanel({ + u, + x, + y, + w, + h, + tilt, + title, + lines = [], + size = 5.6, + children, +}: { + u: U + x: number + y: number + w: number + h: number + tilt: number + title: string + lines?: string[] + size?: number + children?: React.ReactNode +}) { + return ( + + + + {[6, 12, 18].map((cx) => ( + + ))} + + {title} + + {lines.map((line, i) => ( + + {line} + + ))} + {children} + + + ) +} + +/* === 1976: Lochkarte === */ + +const CARD_TEXT = 'C JAMULIX 1976 FORTRAN IV'.padEnd(28, ' ') + +// Zeilenindex: 0 = Zone 12, 1 = Zone 11, 2 = Ziffer 0, 3..11 = Ziffern 1..9 +function hollerith(ch: string): number[] { + if (ch >= '0' && ch <= '9') return [2 + Number(ch)] + const c = ch.charCodeAt(0) - 65 + if (c >= 0 && c < 9) return [0, 3 + c] + if (c >= 9 && c < 18) return [1, 3 + c - 9] + if (c >= 18 && c < 26) return [2, 4 + c - 18] + return [] +} + +function Lochkarte({ u }: { u: U }) { + return ( + <> + + + + + + + + {CARD_TEXT.split('').map((ch, i) => { + const x = 14 + i * 7.2 + const holes = hollerith(ch) + return ( + + + {ch} + + {Array.from({ length: 12 }, (_, r) => { + const y = 17 + r * 7.3 + return holes.includes(r) ? ( + + ) : ( + + ) + })} + + ) + })} + + + + {/* Bandspulen */} + + + {[322, 362].map((cx, i) => ( + + + + + + ))} + + + + + + ) +} + +/* === 1984: PC === */ + +function Pc({ u }: { u: U }) { + return ( + <> + + + + + + C:\>dir /w + + + TP.EXE DBASE.EXE + + + 123.COM NC.EXE + + + WP.EXE QBASIC.EXE + + + C:\> + + + + + + + + + {Array.from({ length: 3 }, (_, r) => + Array.from({ length: 14 }, (_, i) => ( + + )), + )} + + + + {['A', 'B', 'C'].map((c, i) => ( + + {c} + + ))} + {[ + ['Miete', '450', '450'], + ['Disks', '89', '178'], + ['Modem', '398', '398'], + ['RAM', '640', '0'], + ['Summe', '1577', '1026'], + ].map((row, r) => ( + + {row.map((v, i) => ( + + {v} + + ))} + + + ))} + + + + + + {/* 5,25"-Diskette */} + + + + + + + + + + ) +} + +/* === 1986: Atari ST === */ + +function Atari({ u }: { u: U }) { + return ( + <> + + + + + + + Desk File View Options + + + + move.l d0,(a1)+ + + + dbra d7,loop + + + trap #1 + + + {[160, 171, 182].map((x) => ( + + + + + ))} + + OK + + + + {Array.from({ length: 10 }, (_, i) => ( + + ))} + {Array.from({ length: 3 }, (_, r) => + Array.from({ length: 15 }, (_, i) => ( + + )), + )} + + 520ST + + + + + + {/* Akustikkoppler */} + {[0, 0.4, 0.8].map((d, i) => ( + + ))} + + + + + + + + 300 BAUD + + + + ) +} + +/* === 1990: Unix === */ + +function Unix({ u }: { u: U }) { + const tools = ['grep', 'sort', 'uniq', 'wc'] + return ( + <> + + + + + + + {tools.map((t, i) => { + const y = 52 + i * 44 + return ( + + + + {t} + + {i < tools.length - 1 && ( + <> + + + | + + + )} + + ) + })} + + + Do one thing and do it well. + + + ) +} + +/* === 1992: Linux === */ + +function Disk({ i, label }: { i: number; label?: boolean }) { + return ( + + + + + + {label && ( + <> + + SLACKWARE + + + disk a1 / 40 + + + + )} + + ) +} + +function Linux({ u }: { u: U }) { + return ( + <> + + + {[0, 1, 2, 3, 4].map((i) => ( + + ))} + + + + + + + + + 40 × 1,44 MB · Kernel 0.99 + + + + {/* Tux, „echt“ auf dem Tisch */} + + + + + + + + + + + + + + + + + + ) +} + +/* === 1995: WWW === */ + +const CHIRP = Array.from({ length: 110 }, (_, i) => { + const t = i / 109 + const x = 244 + i * 1.25 + const y = 212 + Math.sin(i * (0.25 + t * 0.9)) * (3 + 7 * t) + return `${x.toFixed(1)},${y.toFixed(1)}` +}).join(' ') + +function Www({ u }: { u: U }) { + const cx = 128 + const cy = 128 + const r = 74 + const nodes: [number, number][] = [ + [96, 92], + [160, 84], + [178, 150], + [110, 176], + [134, 128], + ] + return ( + <> + + + + {[0, 1.5, 3, 4.5].map((d) => ( + + + + ))} + {[-0.75, -0.4, 0, 0.4, 0.75].map((lat) => { + const y = cy + lat * r + const w = Math.sqrt(1 - lat * lat) * r + return + })} + + + + + {nodes.map(([x, y], i) => ( + + ))} + + + + + + + http://www.linix.de/ + + + {[48, 55, 62, 69].map((y, i) => ( + + ))} + + <a href="links.html"> + + + + + UNDER CONSTRUCTION + + + Besucher: + + + + 000042 + + + + + + ATDT … 28.8k CONNECT + + + ) +} + +/* === 2000er: Server === */ + +function IsoBox({ cx, y0, s, label }: { cx: number; y0: number; s: number; label: string }) { + return ( + + + + + + {label} + + + ) +} + +function Server({ u }: { u: U }) { + return ( + <> + + + + + {Array.from({ length: 7 }, (_, i) => { + const y = 48 + i * 25.5 + return ( + + + + + + + ) + })} + + + + + + + + + + + + + + ) +} + +/* === 2022: KI === */ + +const BRAIN_NODES: [number, number][] = [ + [78, 112], [96, 84], [122, 72], [150, 62], [176, 72], [200, 86], [214, 112], [204, 140], [178, 146], + [150, 156], [118, 152], [92, 138], [110, 108], [140, 96], [168, 108], [132, 130], [160, 132], [188, 120], +] +const BRAIN_EDGES: [number, number][] = [] +BRAIN_NODES.forEach(([x1, y1], i) => + BRAIN_NODES.forEach(([x2, y2], j) => { + if (j > i && Math.hypot(x2 - x1, y2 - y1) < 38) BRAIN_EDGES.push([i, j]) + }), +) + +function Ki({ u }: { u: U }) { + const probs: [string, number][] = [ + ['Linux', 0.71], + ['Code', 0.17], + ['Kaffee', 0.08], + ['Windows', 0.01], + ] + return ( + <> + + + {/* Großhirn */} + + {/* Kleinhirn und Hirnstamm */} + + + + {/* Furchen */} + + + + + + + + + {BRAIN_EDGES.map(([a, b]) => ( + + ))} + {BRAIN_NODES.map(([x, y], i) => ( + + ))} + + + + + + + > Je schlauer, desto + + {probs.map(([word, p], i) => { + const y = 44 + i * 24 + return ( + + + {word} + + + {p.toFixed(2)} + + + + + ) + })} + + temperature 0.7 · top_p 0.9 + + + + ) +} + +const SCENES: Record React.JSX.Element }> = { + lochkarte: { + caption: 'FIG.01 // 1976 // LOCHKARTE · HOLLERITH-CODE', + alt: 'Hologramm einer Lochkarte mit gestanzter Zeile „C JAMULIX 1976 FORTRAN IV“, daneben ein Fortran-Listing und Bandspulen', + Scene: Lochkarte, + }, + pc: { + caption: 'FIG.02 // 1984 // PC UNTER DOS', + alt: 'Hologramm eines PCs mit DOS-Prompt, daneben schwebende Panels mit Lotus-Tabelle und dBASE', + Scene: Pc, + }, + atari: { + caption: 'FIG.03 // 1986 // ATARI ST · 68000 · DFÜ', + alt: 'Hologramm eines Atari ST mit GEM-Desktop und Bomben-Dialog, 68000-Assembler-Panel und Akustikkoppler', + Scene: Atari, + }, + unix: { + caption: 'FIG.04 // 1990 // UNIX-SHELL UND PIPES', + alt: 'Schwebendes Terminal mit Unix-Shell-Befehlen und eine Pipeline aus grep, sort, uniq und wc als Hologramm', + Scene: Unix, + }, + linux: { + caption: 'FIG.05 // 1992 // SLACKWARE AUF 40 DISKETTEN', + alt: 'Hologramm gefächerter Slackware-Disketten mit Installationsfortschritt, daneben der Linux-Pinguin Tux auf dem Tisch', + Scene: Linux, + }, + www: { + caption: 'FIG.06 // 1995 // WORLD WIDE WEB', + alt: 'Rotierender Hologramm-Globus mit Hyperlinks, Browser-Panel von linix.de mit Besucherzähler und Modem-Signal', + Scene: Www, + }, + server: { + caption: 'FIG.07 // 2000ER // RACK · CONTAINER · AUTOMATISIERUNG', + alt: 'Hologramm eines Server-Racks mit blinkenden LEDs, verbunden mit Containern, daneben ein SSH-Panel', + Scene: Server, + }, + ki: { + caption: 'FIG.08 // 2022 // SPRACHMODELL · NÄCHSTES TOKEN', + alt: 'Gehirn aus Netzwerkknoten als Hologramm; ein Panel zeigt „Linux“ mit 71 Prozent als nächstes Token nach „Je schlauer, desto“', + Scene: Ki, + }, +} + +export function TimelineHolo({ id, className = '' }: { id: TimelineArtId; className?: string }) { + const { caption, alt, Scene } = SCENES[id] + const u: U = (name) => `holo-${id}-${name}` + return ( +
+ + + + + + +
+ ) +} diff --git a/deploy_to_localhost.sh b/deploy_to_localhost.sh index b9f023d..3e5b755 100755 --- a/deploy_to_localhost.sh +++ b/deploy_to_localhost.sh @@ -18,6 +18,13 @@ echo "Setze symbolischen Link: index.html → landingpage/index.html" sudo rm -f /var/www/html/index.html sudo ln -s landingpage/index.html /var/www/html/index.html +# Next.js lädt unter / die RSC-Segmente ohne basePath (/__next.*.txt) — ebenfalls verlinken +echo "Setze symbolische Links: __next.*.txt → landingpage/__next.*.txt" +sudo rm -f /var/www/html/__next.*.txt +for f in landingpage/__next.*.txt; do + sudo ln -s "$f" "/var/www/html/$(basename "$f")" +done + echo "Kopiere Fehlerseiten: landingpage/.html → .html" for c in $ERROR_PAGES; do sudo cp "landingpage/$c.html" "/var/www/html/$c.html" diff --git a/deploy_to_production.sh b/deploy_to_production.sh index e6ea84a..a7038b1 100755 --- a/deploy_to_production.sh +++ b/deploy_to_production.sh @@ -31,6 +31,10 @@ rsync -av --delete -e "ssh -S $SSH_SOCKET" landingpage/ "$REMOTE_USER@$REMOTE_HO 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'" +# Next.js lädt unter / die RSC-Segmente ohne basePath (/__next.*.txt) — ebenfalls verlinken +echo "Setze symbolische Links: __next.*.txt → landingpage/__next.*.txt" +ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "cd '$REMOTE_DIR' && rm -f __next.*.txt && for f in landingpage/__next.*.txt; do ln -s \$f \$(basename \$f); done" + echo "Kopiere Fehlerseiten: landingpage/.html → .html" ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "for c in $ERROR_PAGES; do cp '$REMOTE_DIR'/landingpage/\$c.html '$REMOTE_DIR'/\$c.html; done"