379 lines
20 KiB
TypeScript
379 lines
20 KiB
TypeScript
import { useState } from "react";
|
||
import { Book, Project, AuthorProfile } from "../types";
|
||
import { Leaf, Feather, Star, Sparkles, BookOpen, ExternalLink, ArrowRight } from "lucide-react";
|
||
|
||
interface ClaraPortfolioProps {
|
||
data: AuthorProfile;
|
||
}
|
||
|
||
export default function ClaraPortfolio({ data }: ClaraPortfolioProps) {
|
||
const [selectedBook, setSelectedBook] = useState<Book | null>(null);
|
||
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
||
|
||
return (
|
||
<div className="min-h-screen bg-stone-950 text-stone-200 font-sans selection:bg-[#B39EAF]/30 selection:text-white overflow-x-hidden relative">
|
||
{/* Delicate organic gradients - Sage (Salbei) and Mauve (Malve) */}
|
||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-[#4A5D50]/15 via-stone-950 to-stone-950 -z-10 pointer-events-none" />
|
||
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-[#8FA797]/5 rounded-full blur-3xl pointer-events-none" />
|
||
<div className="absolute bottom-1/3 right-1/3 w-96 h-96 bg-[#B59EB1]/5 rounded-full blur-3xl pointer-events-none" />
|
||
|
||
{/* Header / Hero */}
|
||
<header className="relative py-24 px-4 max-w-7xl mx-auto border-b border-[#4A5D50]/20">
|
||
<div className="text-center max-w-4xl mx-auto space-y-6">
|
||
<div className="inline-flex items-center gap-2 px-4 py-1.5 bg-[#4A5D50]/10 border border-[#8FA797]/20 rounded-full text-[#8FA797] text-xs tracking-wider mb-2">
|
||
<Leaf className="w-3.5 h-3.5 text-[#8FA797] animate-pulse" />
|
||
<span className="font-serif italic text-stone-300">Lyrik & Naturphilosophie</span>
|
||
</div>
|
||
|
||
<h1 className="text-4xl md:text-6xl font-serif tracking-widest text-stone-100 uppercase font-light drop-shadow-[0_2px_10px_rgba(143,167,151,0.1)]">
|
||
{data.heroTitle || "CLARA FINCH"}
|
||
</h1>
|
||
<p className="text-[#B59EB1] font-sans text-xs md:text-sm tracking-[0.4em] uppercase">
|
||
{data.heroSubtitle || "LYRIK, ESSAYS & NATURPHILOSOPHIE"}
|
||
</p>
|
||
<div className="h-[1px] w-36 bg-gradient-to-r from-transparent via-[#8FA797]/55 via-[#B59EB1]/50 to-transparent mx-auto mt-6" />
|
||
|
||
{/* Quick Section Navigation (Sage & Mauve Styled) */}
|
||
<nav className="mt-8 flex flex-wrap justify-center gap-3 text-xs font-sans">
|
||
<a
|
||
href="#ueber-mich"
|
||
className="px-4 py-2 rounded-full border border-[#4A5D50]/30 bg-[#4A5D50]/10 hover:border-[#8FA797] hover:text-[#8FA797] transition-all text-stone-300 uppercase tracking-wider"
|
||
>
|
||
🌿 Über mich
|
||
</a>
|
||
<a
|
||
href="#projekte"
|
||
className="px-4 py-2 rounded-full border border-[#4A5D50]/30 bg-[#4A5D50]/10 hover:border-[#8FA797] hover:text-[#8FA797] transition-all text-stone-300 uppercase tracking-wider"
|
||
>
|
||
✍️ Notizbücher
|
||
</a>
|
||
<a
|
||
href="#buecherregal"
|
||
className="px-4 py-2 rounded-full border border-[#4A5D50]/30 bg-[#4A5D50]/10 hover:border-[#8FA797] hover:text-[#8FA797] transition-all text-stone-300 uppercase tracking-wider"
|
||
>
|
||
📖 Gedruckte Werke
|
||
</a>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
{/* Main Grid */}
|
||
<main className="max-w-7xl mx-auto px-4 py-16 space-y-24">
|
||
|
||
{/* About writer */}
|
||
<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 soft natural glow */}
|
||
<div className="absolute -inset-1.5 bg-gradient-to-r from-[#8FA797] to-[#B59EB1] rounded-2xl blur opacity-20 group-hover:opacity-40 transition duration-1000 group-hover:duration-200"></div>
|
||
<div className="relative w-64 h-64 md:w-80 md:h-80 rounded-2xl overflow-hidden border border-[#4A5D50]/30 bg-stone-900">
|
||
<img
|
||
src={data.avatarUrl || "https://images.unsplash.com/photo-1544005313-94ddf0286df2?auto=format&fit=crop&q=80&w=400"}
|
||
alt={data.name}
|
||
className="w-full h-full object-cover grayscale brightness-95 group-hover:scale-105 group-hover:grayscale-0 transition-all duration-1000"
|
||
referrerPolicy="no-referrer"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="md:col-span-8 space-y-6">
|
||
<h2 className="text-2xl md:text-3xl font-serif text-stone-100 flex items-center gap-3">
|
||
<Feather className="w-6 h-6 text-[#8FA797]" />
|
||
<span>Normal ist das, was heilt.</span>
|
||
</h2>
|
||
<div className="prose prose-invert prose-stone max-w-none text-stone-350 text-stone-300 leading-relaxed font-sans space-y-4">
|
||
<p className="whitespace-pre-wrap italic">{data.bio}</p>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 pt-4 text-xs">
|
||
<div className="p-3 bg-stone-900/50 border border-stone-900 rounded-xl flex items-center gap-3">
|
||
<Leaf className="w-5 h-5 text-[#8FA797]" />
|
||
<div>
|
||
<div className="text-stone-500 uppercase tracking-wider text-[10px]">Genre</div>
|
||
<div className="text-stone-200 font-semibold">Deep Romance & Contemporary</div>
|
||
</div>
|
||
</div>
|
||
<div className="p-3 bg-stone-900/50 border border-stone-900 rounded-xl flex items-center gap-3">
|
||
<Sparkles className="w-5 h-5 text-[#B59EB1]" />
|
||
<div>
|
||
<div className="text-stone-500 uppercase tracking-wider text-[10px]">Ästhetik</div>
|
||
<div className="text-stone-200 font-semibold">Cozy, analog & geerdet</div>
|
||
</div>
|
||
</div>
|
||
<div className="p-3 bg-stone-900/50 border border-stone-900 rounded-xl flex items-center gap-3 col-span-2 md:col-span-1">
|
||
<Feather className="w-5 h-5 text-[#8FA797]" />
|
||
<div>
|
||
<div className="text-stone-500 uppercase tracking-wider text-[10px]">Fokus</div>
|
||
<div className="text-stone-200 font-semibold">Heilung, Akzeptanz & Safe Spaces</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Dynamic ongoing work writing progress */}
|
||
<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-[#4A5D50]/20 pb-4">
|
||
<div>
|
||
<h2 className="text-2xl md:text-3xl font-serif text-stone-100 flex items-center gap-3">
|
||
<Feather className="w-6 h-6 text-[#8FA797]" />
|
||
<span>Aus den Notizbüchern</span>
|
||
</h2>
|
||
<p className="text-stone-400 text-sm mt-1">Gedanken im Entwurf, Fragmente und Sammlungen, die bald das Licht der Welt erblicken.</p>
|
||
</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 bg-[#4A5D50]/5 border border-[#4A5D50]/20 hover:border-[#8FA797]/40 rounded-xl transition-all duration-300 flex flex-col text-left w-full justify-between group cursor-pointer hover:shadow-[0_0_20px_rgba(143,167,151,0.15)] focus:outline-none"
|
||
>
|
||
<div className="space-y-4 w-full">
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-[10px] uppercase font-sans text-[#8FA797] bg-[#4A5D50]/20 px-2.5 py-1 rounded border border-[#8FA797]/20 tracking-wider">
|
||
{project.status || "In Arbeit"}
|
||
</span>
|
||
<span className="text-xs text-stone-400 italic">
|
||
Reifegrad: {project.progress}%
|
||
</span>
|
||
</div>
|
||
<h3 className="text-lg font-serif text-stone-100 group-hover:text-[#B59EB1] transition-colors">
|
||
{project.title}
|
||
</h3>
|
||
<p className="text-stone-300 text-sm italic line-clamp-3">
|
||
{project.description}
|
||
</p>
|
||
<p className="text-[#8FA797] font-sans text-[11px] mt-2 group-hover:translate-x-1 transition-transform flex items-center gap-1 italic">
|
||
Details einsehen <ArrowRight className="w-3 h-3" />
|
||
</p>
|
||
</div>
|
||
{/* Sage & Mauve loading progress meter */}
|
||
<div className="mt-6 space-y-1.5 w-full">
|
||
<div className="h-1 w-full bg-stone-900 rounded-full overflow-hidden">
|
||
<div
|
||
className="h-full bg-gradient-to-r from-[#4A5D50] via-[#8FA797] to-[#B59EB1] rounded-full transition-all duration-1000 ease-out shadow-[0_0_8px_rgba(143,167,151,0.3)]"
|
||
style={{ width: `${project.progress}%` }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</button>
|
||
))}
|
||
</div>
|
||
</section>
|
||
|
||
{/* Bookshelf display */}
|
||
<section id="buecherregal" className="space-y-8">
|
||
<div className="border-b border-[#4A5D50]/20 pb-4">
|
||
<h2 className="text-2xl md:text-3xl font-serif text-stone-100 flex items-center gap-3">
|
||
<BookOpen className="w-6 h-6 text-[#8FA797]" />
|
||
<span>Gedruckte Werke</span>
|
||
</h2>
|
||
<p className="text-stone-400 text-sm mt-1">Erschlossene Wortlandschaften. Wählen Sie einen Band, um tiefer hineinzuhören.</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-lg overflow-hidden border border-stone-900 bg-stone-900 hover:border-[#8FA797]/50 transition-all duration-300 hover:shadow-[0_0_20px_rgba(143,167,151,0.15)] cursor-pointer"
|
||
>
|
||
<div className="absolute inset-0 bg-[#4A5D50]/10 opacity-0 group-hover:opacity-100 transition-opacity z-10 pointer-events-none" />
|
||
<img
|
||
src={book.coverUrl || "https://images.unsplash.com/photo-1501504905252-473c47e087f8?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-700 z-0"
|
||
referrerPolicy="no-referrer"
|
||
/>
|
||
|
||
{/* Readable, beautiful overlay on top of cover, slightly translucent, fully visible on hover */}
|
||
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-stone-950 via-stone-950/90 to-transparent p-4 opacity-80 group-hover:opacity-100 transition-all duration-350 z-20">
|
||
<p className="text-[#E6E0E5] text-xs font-serif truncate">{book.title}</p>
|
||
<p className="text-[#8FA797] text-[10px] font-sans mt-0.5 italic">Verweilen <ArrowRight className="inline-block w-2.5 h-2.5 ml-0.5" /></p>
|
||
</div>
|
||
</button>
|
||
))}
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
{/* Book details modular modal */}
|
||
{selectedBook && (
|
||
<div className="fixed inset-0 z-50 overflow-y-auto" role="dialog" aria-modal="true">
|
||
<div
|
||
className="fixed inset-0 bg-stone-950/85 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-stone-950 border border-stone-900 text-left shadow-2xl transition-all sm:my-8 sm:w-full sm:max-w-4xl p-6 md:p-8 space-y-6">
|
||
|
||
<button
|
||
onClick={() => setSelectedBook(null)}
|
||
className="absolute top-4 right-4 text-stone-400 hover:text-stone-100 hover:bg-[#4A5D50]/80 px-2.5 py-1 rounded-md text-xs font-sans border border-stone-800 transition-all cursor-pointer"
|
||
>
|
||
SCHLIEẞEN
|
||
</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-[#4A5D50]/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-[#8FA797] to-[#B59EB1] hover:from-[#9fbca9] hover:to-[#cbb5c7] text-stone-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(143,167,151,0.2)] text-sm"
|
||
>
|
||
<span>Werk erwerben</span>
|
||
<ExternalLink className="w-4 h-4" />
|
||
</a>
|
||
)}
|
||
</div>
|
||
|
||
{/* Details text area */}
|
||
<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-[10px] font-sans text-[#8FA797] bg-[#4A5D50]/20 px-2.5 py-0.5 rounded border border-[#8FA797]/30">
|
||
Erschienen: {selectedBook.publishedYear}
|
||
</span>
|
||
{selectedBook.genres?.map((genre) => (
|
||
<span key={genre} className="text-[10px] font-sans text-[#B59EB1] bg-[#B59EB1]/10 px-2.5 py-0.5 rounded border border-[#B59EB1]/20">
|
||
{genre}
|
||
</span>
|
||
))}
|
||
</div>
|
||
|
||
<h3 className="text-3xl font-serif text-stone-100">
|
||
{selectedBook.title}
|
||
</h3>
|
||
|
||
{selectedBook.subtitle && (
|
||
<h4 className="text-sm font-sans italic text-[#B59EB1]">
|
||
{selectedBook.subtitle}
|
||
</h4>
|
||
)}
|
||
|
||
<div className="h-[1px] bg-[#4A5D50]/30" />
|
||
|
||
<p className="text-stone-300 text-sm leading-relaxed whitespace-pre-wrap italic">
|
||
{selectedBook.description}
|
||
</p>
|
||
</div>
|
||
|
||
{/* Embedded Spotify player (Only if playlist is non-empty) */}
|
||
{selectedBook.spotifyPlaylistId && selectedBook.spotifyPlaylistId.trim() !== "" && (
|
||
<div className="space-y-2">
|
||
<p className="text-xs font-sans text-[#8FA797] flex items-center gap-2 italic">
|
||
<Leaf className="w-3.5 h-3.5 text-[#8FA797]" />
|
||
<span>Klanglandschaft (Begleitende Playlist)</span>
|
||
</p>
|
||
<div className="rounded-xl overflow-hidden bg-stone-900 border border-stone-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"
|
||
/>
|
||
</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">
|
||
<div
|
||
className="fixed inset-0 bg-stone-950/85 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-stone-950 border border-stone-900 text-left shadow-2xl transition-all sm:my-8 sm:w-full sm:max-w-2xl p-6 md:p-8 space-y-6">
|
||
|
||
<button
|
||
onClick={() => setSelectedProject(null)}
|
||
className="absolute top-4 right-4 text-stone-400 hover:text-stone-100 hover:bg-[#4A5D50]/80 px-2.5 py-1 rounded-md text-xs font-sans border border-stone-800 transition-all cursor-pointer"
|
||
>
|
||
SCHLIEẞEN
|
||
</button>
|
||
|
||
<div className="space-y-6 pt-4">
|
||
<div className="flex flex-wrap items-center gap-2">
|
||
<span className="text-[10px] font-sans text-[#8FA797] bg-[#4A5D50]/20 px-2.5 py-0.5 rounded border border-[#8FA797]/30">
|
||
Status: {selectedProject.status || "In Arbeit"}
|
||
</span>
|
||
<span className="text-[10px] font-sans text-[#B59EB1] bg-[#B59EB1]/10 px-2.5 py-0.5 rounded border border-[#B59EB1]/20">
|
||
Notizbucheintrag
|
||
</span>
|
||
</div>
|
||
|
||
<h3 className="text-3xl font-serif text-stone-100">
|
||
{selectedProject.title}
|
||
</h3>
|
||
|
||
<div className="h-[1px] bg-[#4A5D50]/30" />
|
||
|
||
<div className="space-y-2">
|
||
<div className="flex justify-between items-center text-xs font-sans text-stone-400">
|
||
<span>ENTWURF-FORTSCHRITT:</span>
|
||
<span className="text-[#8FA797] font-bold">{selectedProject.progress}%</span>
|
||
</div>
|
||
<div className="h-2 w-full bg-stone-900 rounded-full overflow-hidden border border-stone-800">
|
||
<div
|
||
className="h-full bg-gradient-to-r from-[#4A5D50] via-[#8FA797] to-[#B59EB1] rounded-full transition-all duration-1000 ease-out shadow-[0_0_8px_rgba(143,167,151,0.25)]"
|
||
style={{ width: `${selectedProject.progress}%` }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-[#4A5D50]/5 p-5 rounded-xl border border-[#4A5D50]/20 relative overflow-hidden">
|
||
<div className="absolute top-0 right-0 p-2 text-stone-700 text-[10px] font-mono select-none">
|
||
FRAGMENT_LOG_CLARA
|
||
</div>
|
||
<h4 className="text-xs font-sans text-[#8FA797] uppercase tracking-wider mb-3 italic">Konzeptuelle Notizen & Auszüge</h4>
|
||
<p className="text-stone-200 text-sm leading-relaxed whitespace-pre-wrap italic">
|
||
{selectedProject.description || "Für dieses Buchprojekt wurden noch keine lyrischen Gedanken freigegeben."}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Footer */}
|
||
<footer className="bg-stone-950 border-t border-[#4A5D50]/20 py-12 px-4 text-center text-xs text-stone-500 italic">
|
||
<div className="max-w-7xl mx-auto space-y-2">
|
||
<p>© {new Date().getFullYear()} {data.name}. Alle Rechte vorbehalten.</p>
|
||
<p className="text-stone-600">Betrachtungen, verwoben mit dem Rhythmus der wachsenden Natur.</p>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
);
|
||
}
|