webstack-author/src/components/SciFiPortfolio.tsx

443 lines
24 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import Markdown from "react-markdown";
import { Book, Project, AuthorProfile } from "../types";
import { BookOpen, Star, HelpCircle, Award, Compass, ArrowRight, ExternalLink, Moon } from "lucide-react";
interface SciFiPortfolioProps {
data: AuthorProfile;
}
export default function SciFiPortfolio({ data }: SciFiPortfolioProps) {
const [selectedBook, setSelectedBook] = useState<Book | null>(null);
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
const accentColor = data.accentColor || "#06b6d4";
const secondaryColor = data.secondaryColor || "#a855f7";
const bgColor = data.backgroundColor || "#020617";
const cardBgColor = data.cardBgColor || "#0f172a";
const fontClass = data.fontFamily === "serif" ? "font-serif" : data.fontFamily === "mono" ? "font-mono" : "font-sans";
return (
<div
className={`min-h-screen text-slate-100 ${fontClass} selection:bg-cyan-500 selection:text-white overflow-x-hidden relative`}
style={{ backgroundColor: bgColor }}
>
{/* Hero Banner Background if present */}
{data.heroBannerUrl && (
<div className="absolute top-0 inset-x-0 h-96 overflow-hidden pointer-events-none -z-5 opacity-25">
<img src={data.heroBannerUrl} alt="" className="w-full h-full object-cover blur-sm" />
<div className="absolute inset-0 bg-gradient-to-b from-transparent to-slate-950" style={{ backgroundImage: `linear-gradient(to bottom, transparent, ${bgColor})` }} />
</div>
)}
{/* Decorative starry background with magical aura */}
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-indigo-950/40 via-transparent to-transparent -z-10 pointer-events-none" />
<div
className="absolute top-1/4 left-1/4 w-96 h-96 rounded-full blur-3xl pointer-events-none opacity-20"
style={{ backgroundColor: accentColor }}
/>
<div
className="absolute top-2/3 right-1/4 w-96 h-96 rounded-full blur-3xl pointer-events-none opacity-20"
style={{ backgroundColor: secondaryColor }}
/>
{/* Hero Section */}
<header className="relative py-24 px-4 max-w-7xl mx-auto border-b border-slate-800/80">
<div className="text-center max-w-4xl mx-auto">
{/* Subtle magical/futuristic accent */}
<div
className="inline-flex items-center gap-2 px-3.5 py-1 bg-slate-900/80 border rounded-full text-xs font-mono mb-6 tracking-widest uppercase shadow-sm"
style={{ borderColor: `${accentColor}40`, color: accentColor }}
>
<Star className="w-3.5 h-3.5 animate-pulse" style={{ color: accentColor }} />
<span>{data.badgeText || "Cyber-Mystisches Archive"}</span>
</div>
<h1 className="text-5xl md:text-7xl tracking-tight text-white mb-4 uppercase drop-shadow-md font-bold">
{data.heroTitle || data.name || "DANIEL HESSE"}
</h1>
<p className="font-mono text-xs md:text-sm tracking-widest uppercase mb-8" style={{ color: accentColor }}>
{data.heroSubtitle || "WELTENWANDLER & STERNENZEICHNER"}
</p>
<div
className="h-0.5 w-24 mx-auto rounded-full"
style={{ background: `linear-gradient(to right, ${accentColor}, ${secondaryColor})` }}
/>
{/* Quick Section Navigation */}
<nav className="mt-8 flex flex-wrap justify-center gap-3 text-xs font-mono">
<a
href="#ueber-mich"
className="px-4 py-2 rounded-full border border-slate-800 bg-slate-900/60 hover:border-cyan-400 hover:text-cyan-400 transition-all text-slate-300 uppercase tracking-wider"
>
🌌 {data.aboutTitle || "Über mich"}
</a>
<a
href="#projekte"
className="px-4 py-2 rounded-full border border-slate-800 bg-slate-900/60 hover:border-cyan-400 hover:text-cyan-400 transition-all text-slate-300 uppercase tracking-wider"
>
🛰️ {data.projectsTitle || "Aktuelle Projekte"}
</a>
<a
href="#buecherregal"
className="px-4 py-2 rounded-full border border-slate-800 bg-slate-900/60 hover:border-cyan-400 hover:text-cyan-400 transition-all text-slate-300 uppercase tracking-wider"
>
🪐 {data.booksTitle || "Bücherregal"}
</a>
</nav>
</div>
</header>
{/* Main Container */}
<main className="max-w-7xl mx-auto px-4 py-16 space-y-24">
{/* Section 1: Über mich */}
<section id="ueber-mich" className="grid grid-cols-1 md:grid-cols-12 gap-12 items-center">
<div className="md:col-span-4 flex justify-center">
<div className="relative group">
{/* Outer neon ring */}
<div
className="absolute -inset-1.5 rounded-2xl blur opacity-30 group-hover:opacity-70 transition duration-1000 group-hover:duration-200"
style={{ background: `linear-gradient(to right, ${accentColor}, ${secondaryColor})` }}
/>
<div className="relative w-64 h-64 md:w-80 md:h-80 rounded-2xl overflow-hidden border border-slate-800" style={{ backgroundColor: cardBgColor }}>
<img
src={data.avatarUrl || "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&q=80&w=400"}
alt={data.name}
className="w-full h-full object-cover grayscale brightness-90 contrast-110 group-hover:scale-105 group-hover:grayscale-0 transition-all duration-700"
referrerPolicy="no-referrer"
/>
</div>
</div>
</div>
<div className="md:col-span-8 space-y-6">
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
<Compass className="w-7 h-7" style={{ color: accentColor }} />
<span>{data.aboutTitle || "Über den Autor"}</span>
</h2>
<div className="prose prose-invert max-w-none text-slate-300 leading-relaxed space-y-4">
<p className="whitespace-pre-wrap">{data.bio}</p>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 pt-4 font-mono text-xs">
<div className="p-3 border rounded-lg flex items-center gap-3" style={{ backgroundColor: cardBgColor, borderColor: `${accentColor}20` }}>
<BookOpen className="w-5 h-5" style={{ color: secondaryColor }} />
<div>
<div className="text-slate-500 uppercase tracking-widest">Fokus</div>
<div className="text-white font-semibold">Sci-Fi & Fantasy</div>
</div>
</div>
<div className="p-3 border rounded-lg flex items-center gap-3" style={{ backgroundColor: cardBgColor, borderColor: `${accentColor}20` }}>
<Star className="w-5 h-5" style={{ color: accentColor }} />
<div>
<div className="text-slate-500 uppercase tracking-widest">Welten</div>
<div className="text-white font-semibold">Techno-Magie</div>
</div>
</div>
<div className="p-3 border rounded-lg flex items-center gap-3 col-span-2 md:col-span-1" style={{ backgroundColor: cardBgColor, borderColor: `${accentColor}20` }}>
<Award className="w-5 h-5" style={{ color: secondaryColor }} />
<div>
<div className="text-slate-500 uppercase tracking-widest">Stil</div>
<div className="text-white font-semibold">Episch & Atmosphärisch</div>
</div>
</div>
</div>
</div>
</section>
{/* Section 2: Aktuelle Projekte */}
<section id="projekte" className="space-y-8">
<div className="flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-slate-800 pb-4">
<div>
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
<Star className="w-7 h-7" style={{ color: accentColor }} />
<span>{data.projectsTitle || "Aktuelle Projekte"}</span>
</h2>
<p className="text-slate-400 text-sm mt-1">{data.projectsSubtitle || "Ein exklusiver Blick auf das, was sich gerade auf meinem Schreib-Amboss befindet."}</p>
</div>
<div className="text-xs font-mono px-3 py-1 rounded border" style={{ color: accentColor, backgroundColor: `${accentColor}10`, borderColor: `${accentColor}30` }}>
Laufendes Telemetrie-Tracking
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{data.projects.map((project) => (
<button
key={project.id}
onClick={() => setSelectedProject(project)}
className="p-6 border rounded-xl transition-all duration-300 flex flex-col text-left w-full justify-between group cursor-pointer hover:scale-[1.01] focus:outline-none shadow-lg"
style={{ backgroundColor: cardBgColor, borderColor: `${accentColor}25` }}
>
<div className="space-y-4 w-full">
<div className="flex items-center justify-between">
<span className="text-xs font-mono px-2.5 py-1 rounded border uppercase tracking-wider" style={{ color: accentColor, backgroundColor: `${accentColor}15`, borderColor: `${accentColor}30` }}>
{project.status || "In Arbeit"}
</span>
<span className="text-xs text-slate-400 font-mono">
Progression: {project.progress}%
</span>
</div>
<h3 className="text-xl font-bold text-white group-hover:text-cyan-300 transition-colors">
{project.title}
</h3>
<p className="text-slate-300 text-sm leading-relaxed line-clamp-3">
{project.description}
</p>
<p className="font-mono text-[11px] mt-2 group-hover:translate-x-1 transition-transform flex items-center gap-1" style={{ color: accentColor }}>
Details anzeigen <ArrowRight className="w-3 h-3" />
</p>
</div>
{/* Custom glowing progress bar */}
<div className="mt-6 space-y-1.5 w-full">
<div className="h-1.5 w-full bg-slate-950/80 rounded-full overflow-hidden border border-slate-800">
<div
className="h-full rounded-full transition-all duration-1000 ease-out shadow-sm"
style={{ width: `${project.progress}%`, background: `linear-gradient(to right, ${accentColor}, ${secondaryColor})` }}
/>
</div>
</div>
</button>
))}
</div>
</section>
{/* Section 3: Bücherregal */}
<section id="buecherregal" className="space-y-8">
<div className="border-b border-slate-800 pb-4">
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
<BookOpen className="w-7 h-7" style={{ color: secondaryColor }} />
<span>{data.booksTitle || "Das Bücherregal"}</span>
</h2>
<p className="text-slate-400 text-sm mt-1">{data.booksSubtitle || "Veröffentlichte Meilensteine. Klicken oder Tippen Sie auf ein Cover, um Geheimnisse zu enthüllen."}</p>
</div>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-6 justify-items-center">
{data.books.map((book) => (
<button
key={book.id}
onClick={() => setSelectedBook(book)}
className="group relative focus:outline-none text-left w-full max-w-[210px] aspect-[2/3] rounded-xl overflow-hidden border hover:border-cyan-400 transition-all duration-300 hover:shadow-xl cursor-pointer"
style={{ backgroundColor: cardBgColor, borderColor: `${accentColor}30` }}
>
<div className="absolute inset-0 bg-cyan-900/10 opacity-0 group-hover:opacity-100 transition-opacity z-10 pointer-events-none" />
<img
src={book.coverUrl || "https://images.unsplash.com/photo-1543002588-bfa74002ed7e?auto=format&fit=crop&q=80&w=300"}
alt={book.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500 z-0"
referrerPolicy="no-referrer"
/>
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-slate-950 via-slate-950/90 to-transparent p-4 opacity-80 group-hover:opacity-100 transition-all duration-350 z-20">
<p className="text-white text-xs font-bold truncate">{book.title}</p>
<p className="text-[10px] font-mono mt-0.5" style={{ color: accentColor }}>Details auslesen <ArrowRight className="inline-block w-2.5 h-2.5 ml-0.5" /></p>
</div>
</button>
))}
</div>
</section>
{/* Section 4: Custom Highlight Section if present */}
{(data.customSectionTitle || data.customSectionContent) && (
<section className="p-8 rounded-2xl border relative overflow-hidden" style={{ backgroundColor: cardBgColor, borderColor: `${accentColor}30` }}>
<div className="absolute top-0 right-0 p-3 opacity-10 font-mono text-xs uppercase" style={{ color: accentColor }}>
CUSTOM_INFO_MODULE
</div>
{data.customSectionTitle && (
<h2 className="text-2xl font-bold text-white mb-4 flex items-center gap-2">
<Star className="w-5 h-5" style={{ color: accentColor }} />
<span>{data.customSectionTitle}</span>
</h2>
)}
{data.customSectionContent && (
<div className="text-slate-300 text-sm leading-relaxed whitespace-pre-wrap">
{data.customSectionContent}
</div>
)}
</section>
)}
</main>
{/* Book details modular interface modal */}
{selectedBook && (
<div className="fixed inset-0 z-50 overflow-y-auto" role="dialog" aria-modal="true">
{/* Overlay background */}
<div
className="fixed inset-0 bg-slate-950/80 backdrop-blur-md transition-opacity"
onClick={() => setSelectedBook(null)}
/>
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<div className="relative transform overflow-hidden rounded-2xl bg-slate-900 border border-slate-800 text-left shadow-2xl transition-all sm:my-8 sm:w-full sm:max-w-4xl p-6 md:p-8 space-y-6">
{/* Close Button */}
<button
onClick={() => setSelectedBook(null)}
className="absolute top-4 right-4 text-slate-400 hover:text-white hover:bg-slate-800/80 px-2.5 py-1 rounded-md text-xs font-mono border border-slate-800 transition-all cursor-pointer"
>
SCHLIESSEN [ESC]
</button>
<div className="grid grid-cols-1 md:grid-cols-12 gap-8 pt-4">
{/* Book Cover */}
<div className="col-span-1 md:col-span-4 flex flex-col items-center">
<div className="rounded-xl overflow-hidden shadow-2xl border border-indigo-900/30 max-w-[260px] aspect-[2/3] w-full">
<img
src={selectedBook.coverUrl}
alt={selectedBook.title}
className="w-full h-full object-cover"
referrerPolicy="no-referrer"
/>
</div>
{selectedBook.buyLink && (
<a
href={selectedBook.buyLink}
target="_blank"
rel="noopener noreferrer"
className="mt-6 w-full max-w-[260px] py-3 text-center bg-gradient-to-r from-cyan-500 to-indigo-600 hover:from-cyan-400 hover:to-indigo-500 text-slate-950 font-bold font-sans rounded-xl flex items-center justify-center gap-2 transition-all hover:scale-[1.02] shadow-[0_4px_12px_rgba(6,182,212,0.3)] text-sm"
>
<span>Invasion starten (Kauf-Link)</span>
<ExternalLink className="w-4 h-4" />
</a>
)}
</div>
{/* Book Details */}
<div className="col-span-1 md:col-span-8 flex flex-col justify-between space-y-6">
<div className="space-y-4">
<div className="flex flex-wrap items-center gap-2">
<span className="text-xs font-mono text-cyan-400 bg-cyan-950/40 px-2.5 py-0.5 rounded border border-cyan-900/40">
Erschienen: {selectedBook.publishedYear}
</span>
{selectedBook.genres?.map((genre) => (
<span key={genre} className="text-[11px] font-mono text-purple-400 bg-purple-950/40 px-2.5 py-0.5 rounded border border-purple-900/40">
{genre}
</span>
))}
</div>
<h3 className="text-3xl font-extrabold text-white">
{selectedBook.title}
</h3>
{selectedBook.subtitle && (
<h4 className="text-sm font-mono text-indigo-400 uppercase tracking-wider">
{selectedBook.subtitle}
</h4>
)}
<div className="h-px bg-indigo-950" />
<div className="text-slate-300 text-sm leading-relaxed markdown-body [&_p]:mb-4 [&_p:last-child]:mb-0">
<Markdown>{selectedBook.description}</Markdown>
</div>
</div>
{/* Integrated Spotify web player playlist if available */}
{selectedBook.spotifyPlaylistId && selectedBook.spotifyPlaylistId.trim() !== "" && (
<div className="space-y-2">
<p className="text-xs font-mono text-indigo-400 flex items-center gap-2">
<Star className="w-3.5 h-3.5 animate-spin" />
<span>INTEGRIERTES ATMOSPHÄREN-SYSTEM (SPOTIFY PLAYLIST)</span>
</p>
<div className="rounded-xl overflow-hidden bg-slate-950 border border-slate-800">
<iframe
src={`https://open.spotify.com/embed/playlist/${selectedBook.spotifyPlaylistId}?utm_source=generator&theme=0`}
width="100%"
height="152"
frameBorder="0"
allowFullScreen={false}
allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"
loading="lazy"
className="bg-slate-950"
/>
</div>
</div>
)}
</div>
</div>
</div>
</div>
</div>
)}
{/* Project details modular modal */}
{selectedProject && (
<div className="fixed inset-0 z-50 overflow-y-auto" role="dialog" aria-modal="true">
{/* Overlay background */}
<div
className="fixed inset-0 bg-slate-950/80 backdrop-blur-md transition-opacity"
onClick={() => setSelectedProject(null)}
/>
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<div className="relative transform overflow-hidden rounded-2xl bg-slate-900 border border-slate-800 text-left shadow-2xl transition-all sm:my-8 sm:w-full sm:max-w-2xl p-6 md:p-8 space-y-6">
{/* Close Button */}
<button
onClick={() => setSelectedProject(null)}
className="absolute top-4 right-4 text-slate-400 hover:text-white hover:bg-slate-800/80 px-2.5 py-1 rounded-md text-xs font-mono border border-slate-800 transition-all cursor-pointer"
>
SCHLIESSEN [ESC]
</button>
<div className="space-y-6 pt-4">
<div className="flex flex-wrap items-center gap-2">
<span className="text-xs font-mono text-cyan-400 bg-cyan-950/40 px-2.5 py-0.5 rounded border border-cyan-900/40">
Status: {selectedProject.status || "In Arbeit"}
</span>
<span className="text-xs font-mono text-purple-400 bg-purple-950/40 px-2.5 py-0.5 rounded border border-purple-900/40">
Übertragung aktiv
</span>
</div>
<h3 className="text-3xl font-extrabold text-white">
{selectedProject.title}
</h3>
<div className="h-px bg-indigo-950" />
<div className="space-y-2">
<div className="flex justify-between items-center text-xs font-mono text-slate-400">
<span>ORGANISCHER FORTSCHRITT:</span>
<span className="text-cyan-400 font-bold">{selectedProject.progress}%</span>
</div>
<div className="h-2 w-full bg-slate-950 rounded-full overflow-hidden border border-slate-800">
<div
className="h-full bg-gradient-to-r from-cyan-400 via-indigo-500 to-purple-600 rounded-full transition-all duration-1000 ease-out shadow-[0_0_8px_rgba(34,211,238,0.4)]"
style={{ width: `${selectedProject.progress}%` }}
/>
</div>
</div>
<div className="bg-slate-950/60 p-5 rounded-xl border border-slate-800/60 relative overflow-hidden">
<div className="absolute top-0 right-0 p-2 text-slate-800 text-[10px] font-mono select-none">
SEC_REPORT_LOG
</div>
<h4 className="text-xs font-mono text-slate-500 uppercase tracking-widest mb-3">Projekt-Exzerpt & Fortschrittsnotizen</h4>
<div className="text-slate-300 text-sm leading-relaxed markdown-body [&_p]:mb-4 [&_p:last-child]:mb-0">
<Markdown>{selectedProject.description || "Für dieses Schreibprojekt wurden noch keine detaillierten Chiffren abgelegt."}</Markdown>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{/* Styled Footer */}
<footer className="border-t border-slate-800 py-12 px-4 text-center text-xs text-slate-500 font-mono" style={{ backgroundColor: bgColor }}>
<div className="max-w-7xl mx-auto space-y-4">
<p>© {new Date().getFullYear()} {data.name}. Alle Rechte vorbehalten.</p>
<p className="text-slate-500">{data.footerText || "Dokumentation, Fragmente und stellare Chiffren. Verschlüsselt mit moderner Node.JS Technologie."}</p>
</div>
</footer>
</div>
);
}