AI Studio Änderungen integriert

This commit is contained in:
Daniel Heße 2026-07-20 12:40:35 +02:00
parent b7b773a1d3
commit 67f4421e59
8 changed files with 105 additions and 14 deletions

0
bun.lock Normal file
View file

0
data/database.json Normal file
View file

View file

@ -46,6 +46,23 @@ async function initDatabase(): Promise<AuthorData> {
parsed.clara = defaultAuthorData.clara; parsed.clara = defaultAuthorData.clara;
modified = true; modified = true;
} }
// Ensure customSection fields exist for all profiles
if (parsed.scifi && parsed.scifi.customSectionTitle === undefined) {
parsed.scifi.customSectionTitle = defaultAuthorData.scifi.customSectionTitle;
parsed.scifi.customSectionContent = defaultAuthorData.scifi.customSectionContent;
modified = true;
}
if (parsed.erotica && parsed.erotica.customSectionTitle === undefined) {
parsed.erotica.customSectionTitle = defaultAuthorData.erotica.customSectionTitle;
parsed.erotica.customSectionContent = defaultAuthorData.erotica.customSectionContent;
modified = true;
}
if (parsed.clara && parsed.clara.customSectionTitle === undefined) {
parsed.clara.customSectionTitle = defaultAuthorData.clara.customSectionTitle;
parsed.clara.customSectionContent = defaultAuthorData.clara.customSectionContent;
modified = true;
}
if (modified) { if (modified) {
await fs.writeFile(DATA_FILE, JSON.stringify(parsed, null, 2), "utf-8"); await fs.writeFile(DATA_FILE, JSON.stringify(parsed, null, 2), "utf-8");

View file

@ -563,7 +563,7 @@ export default function AdminPanel({ onLogout }: AdminPanelProps) {
/> />
</div> </div>
<div className="space-y-1 md:col-span-2"> <div className="space-y-1 md:col-span-2">
<label className="text-xs font-mono text-slate-4000 uppercase text-slate-400">Über Mich / Biografie</label> <label className="text-xs font-mono text-slate-400 uppercase">Über Mich / Biografie</label>
<textarea <textarea
rows={8} rows={8}
value={profile.bio} value={profile.bio}
@ -571,6 +571,40 @@ export default function AdminPanel({ onLogout }: AdminPanelProps) {
className="w-full px-3 py-2 bg-slate-950 border border-slate-800 rounded-xl text-white outline-none focus:border-indigo-500 text-sm font-sans" className="w-full px-3 py-2 bg-slate-950 border border-slate-800 rounded-xl text-white outline-none focus:border-indigo-500 text-sm font-sans"
/> />
</div> </div>
{/* Custom Highlight Section */}
<div className="md:col-span-2 border-t border-slate-800/80 pt-6 mt-2 space-y-4">
<div>
<h4 className="text-sm font-bold text-white flex items-center gap-2">
<Sparkles className="w-4 h-4 text-cyan-400" />
<span>Zusätzlicher Textabschnitt (unten auf der Seite)</span>
</h4>
<p className="text-xs text-slate-500">Ein frei gestaltbarer Infobereich, der am Ende des Portfolios (nach dem Bücherregal) dargestellt wird. Ideal für Termine, Lesungen, Newsletter-Aufrufe oder persönliche Grüße. Leer lassen, um den Bereich auszublenden.</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-1 md:col-span-2">
<label className="text-xs font-mono text-slate-400 uppercase">Abschnitts-Titel</label>
<input
type="text"
value={profile.customSectionTitle || ""}
onChange={(e) => updateProfileField("customSectionTitle", e.target.value)}
placeholder="z.B. Lesungen, Kontakt oder Newsletter"
className="w-full px-3 py-2 bg-slate-950 border border-slate-800 rounded-xl text-white outline-none focus:border-indigo-500 text-sm"
/>
</div>
<div className="space-y-1 md:col-span-2">
<label className="text-xs font-mono text-slate-400 uppercase">Abschnitts-Inhalt (Text)</label>
<textarea
rows={4}
value={profile.customSectionContent || ""}
onChange={(e) => updateProfileField("customSectionContent", e.target.value)}
placeholder="Ihr individueller Textabschnitt..."
className="w-full px-3 py-2 bg-slate-950 border border-slate-800 rounded-xl text-white outline-none focus:border-indigo-500 text-sm font-sans"
/>
</div>
</div>
</div>
</div> </div>
</div> </div>
)} )}

View file

@ -79,7 +79,7 @@ export default function ClaraPortfolio({ data }: ClaraPortfolioProps) {
<div className="md:col-span-8 space-y-6"> <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"> <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]" /> <Feather className="w-6 h-6 text-[#8FA797]" />
<span>Normal ist das, was heilt.</span> <span>Das Atmen zwischen den Zeilen</span>
</h2> </h2>
<div className="prose prose-invert prose-stone max-w-none text-stone-350 text-stone-300 leading-relaxed font-sans space-y-4"> <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> <p className="whitespace-pre-wrap italic">{data.bio}</p>
@ -90,21 +90,21 @@ export default function ClaraPortfolio({ data }: ClaraPortfolioProps) {
<Leaf className="w-5 h-5 text-[#8FA797]" /> <Leaf className="w-5 h-5 text-[#8FA797]" />
<div> <div>
<div className="text-stone-500 uppercase tracking-wider text-[10px]">Genre</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 className="text-stone-200 font-semibold">Lyrik & Essays</div>
</div> </div>
</div> </div>
<div className="p-3 bg-stone-900/50 border border-stone-900 rounded-xl flex items-center gap-3"> <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]" /> <Sparkles className="w-5 h-5 text-[#B59EB1]" />
<div> <div>
<div className="text-stone-500 uppercase tracking-wider text-[10px]">Ästhetik</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 className="text-stone-200 font-semibold">Malve & Salbei</div>
</div> </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"> <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]" /> <Feather className="w-5 h-5 text-[#8FA797]" />
<div> <div>
<div className="text-stone-500 uppercase tracking-wider text-[10px]">Fokus</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 className="text-stone-200 font-semibold">Naturkontemplation</div>
</div> </div>
</div> </div>
</div> </div>
@ -198,6 +198,22 @@ export default function ClaraPortfolio({ data }: ClaraPortfolioProps) {
</div> </div>
</section> </section>
{/* Customizable Custom Section */}
{data.customSectionContent && data.customSectionContent.trim() !== "" && (
<section id="garten-notiz" className="space-y-6 pt-8 border-t border-[#4A5D50]/20">
<div className="bg-gradient-to-br from-[#4A5D50]/10 to-stone-900/40 p-8 rounded-2xl border border-[#4A5D50]/30 max-w-3xl mx-auto text-center space-y-4">
{data.customSectionTitle && (
<h3 className="text-xl md:text-2xl font-serif text-stone-100">
{data.customSectionTitle}
</h3>
)}
<p className="text-stone-300 text-sm md:text-base leading-relaxed italic whitespace-pre-wrap">
{data.customSectionContent}
</p>
</div>
</section>
)}
</main> </main>
{/* Book details modular modal */} {/* Book details modular modal */}

View file

@ -79,7 +79,7 @@ export default function EroticaPortfolio({ data }: EroticaPortfolioProps) {
<div className="md:col-span-8 space-y-6"> <div className="md:col-span-8 space-y-6">
<h2 className="text-2xl md:text-3xl font-serif text-amber-100 flex items-center gap-3"> <h2 className="text-2xl md:text-3xl font-serif text-amber-100 flex items-center gap-3">
<Sparkles className="w-6 h-6 text-orange-400" /> <Sparkles className="w-6 h-6 text-orange-400" />
<span>Zwischen Spielzeugautos und der Stille der Nacht...</span> <span>Das Geheimnis hinter der Feder</span>
</h2> </h2>
<div className="prose prose-invert prose-stone max-w-none text-neutral-300 leading-relaxed font-sans space-y-4"> <div className="prose prose-invert prose-stone max-w-none text-neutral-300 leading-relaxed font-sans space-y-4">
<p className="whitespace-pre-wrap italic">{data.bio}</p> <p className="whitespace-pre-wrap italic">{data.bio}</p>
@ -90,21 +90,21 @@ export default function EroticaPortfolio({ data }: EroticaPortfolioProps) {
<Heart className="w-5 h-5 text-orange-450 text-orange-400 fill-orange-400/10" /> <Heart className="w-5 h-5 text-orange-450 text-orange-400 fill-orange-400/10" />
<div> <div>
<div className="text-neutral-500 uppercase tracking-wider text-[10px]">Genre</div> <div className="text-neutral-500 uppercase tracking-wider text-[10px]">Genre</div>
<div className="text-neutral-200 font-semibold">Spicy Romance & Slice of Life</div> <div className="text-neutral-200 font-semibold">Sinnliche Romance</div>
</div> </div>
</div> </div>
<div className="p-3 bg-neutral-900/50 border border-neutral-900 rounded-xl flex items-center gap-3"> <div className="p-3 bg-neutral-900/50 border border-neutral-900 rounded-xl flex items-center gap-3">
<Sparkles className="w-5 h-5 text-amber-400" /> <Sparkles className="w-5 h-5 text-amber-400" />
<div> <div>
<div className="text-neutral-500 uppercase tracking-wider text-[10px]">Ästhetik</div> <div className="text-neutral-500 uppercase tracking-wider text-[10px]">Tonalität</div>
<div className="text-neutral-200 font-semibold">Hautnah, cozy & ungefiltert</div> <div className="text-neutral-200 font-semibold">Elegant & Knisternd</div>
</div> </div>
</div> </div>
<div className="p-3 bg-neutral-900/50 border border-neutral-900 rounded-xl flex items-center gap-3 col-span-2 md:col-span-1"> <div className="p-3 bg-neutral-900/50 border border-neutral-900 rounded-xl flex items-center gap-3 col-span-2 md:col-span-1">
<Key className="w-5 h-5 text-orange-300" /> <Key className="w-5 h-5 text-orange-300" />
<div> <div>
<div className="text-neutral-500 uppercase tracking-wider text-[10px]">Fokus</div> <div className="text-neutral-500 uppercase tracking-wider text-[10px]">Identität</div>
<div className="text-neutral-200 font-semibold">Bedingungsloses Vertrauen & Intime Facetten</div> <div className="text-neutral-200 font-semibold">Diskret / Pseudonym</div>
</div> </div>
</div> </div>
</div> </div>
@ -198,6 +198,22 @@ export default function EroticaPortfolio({ data }: EroticaPortfolioProps) {
</div> </div>
</section> </section>
{/* Customizable Custom Section */}
{data.customSectionContent && data.customSectionContent.trim() !== "" && (
<section id="exklusiv-notiz" className="space-y-6 pt-8 border-t border-orange-950/20">
<div className="bg-gradient-to-br from-orange-950/20 to-neutral-900/40 p-8 rounded-2xl border border-orange-950/40 max-w-3xl mx-auto text-center space-y-4">
{data.customSectionTitle && (
<h3 className="text-xl md:text-2xl font-serif text-amber-100">
{data.customSectionTitle}
</h3>
)}
<p className="text-neutral-300 text-sm md:text-base leading-relaxed italic whitespace-pre-wrap">
{data.customSectionContent}
</p>
</div>
</section>
)}
</main> </main>
{/* Book details modular modal */} {/* Book details modular modal */}

View file

@ -46,7 +46,9 @@ export const defaultAuthorData: AuthorData = {
spotifyPlaylistId: "37i9dQZF1DX4g8Gs5YmN17", spotifyPlaylistId: "37i9dQZF1DX4g8Gs5YmN17",
genres: ["Science-Fantasy", "Cyberpunk", "Abyssal"] genres: ["Science-Fantasy", "Cyberpunk", "Abyssal"]
} }
] ],
customSectionTitle: "Vorträge & Messen",
customSectionContent: "Besuchen Sie mich auf der nächsten Buchmesse am Stand für spekulative Phantastik. Ich freue mich auf den intergalaktischen Austausch mit meinen Leserinnen und Lesern!"
}, },
erotica: { erotica: {
name: "M. S. Velvet", name: "M. S. Velvet",
@ -93,7 +95,9 @@ export const defaultAuthorData: AuthorData = {
spotifyPlaylistId: "37i9dQZF1DX2U76YeeG0Ug", spotifyPlaylistId: "37i9dQZF1DX2U76YeeG0Ug",
genres: ["Sinnlicher Thriller", "BDSM-Touch", "Maskerade"] genres: ["Sinnlicher Thriller", "BDSM-Touch", "Maskerade"]
} }
] ],
customSectionTitle: "Sinnliche Lesungen & Salon-Abende",
customSectionContent: "Tragen Sie sich in meinen privaten Briefverteiler ein, um exklusive Einladungen zu meinen intimen Salon-Lesungen in Berlin und Wien zu erhalten. Die Plätze sind streng limitiert."
}, },
clara: { clara: {
name: "Clara Finch", name: "Clara Finch",
@ -140,6 +144,8 @@ export const defaultAuthorData: AuthorData = {
spotifyPlaylistId: "37i9dQZF1DWZqd5YICuS9g", spotifyPlaylistId: "37i9dQZF1DWZqd5YICuS9g",
genres: ["Prosa", "Natur-Essays", "Minimalismus"] genres: ["Prosa", "Natur-Essays", "Minimalismus"]
} }
] ],
customSectionTitle: "Die Philosophie des Mooses",
customSectionContent: "Auf meinen geführten Waldspaziergängen und Schreib-Retreats lade ich Sie ein, die Stille des Waldes neu zu erfahren und Ihre Gedanken auf das Papier fließen zu lassen. Schreiben Sie mir gern für Termine und Buchungsanfragen."
} }
}; };

View file

@ -26,6 +26,8 @@ export interface AuthorProfile {
heroSubtitle: string; heroSubtitle: string;
projects: Project[]; projects: Project[];
books: Book[]; books: Book[];
customSectionTitle?: string;
customSectionContent?: string;
} }
export interface AuthorData { export interface AuthorData {