AI Studio Änderungen integriert
This commit is contained in:
parent
b7b773a1d3
commit
67f4421e59
8 changed files with 105 additions and 14 deletions
0
bun.lock
Normal file
0
bun.lock
Normal file
0
data/database.json
Normal file
0
data/database.json
Normal file
17
server.ts
17
server.ts
|
|
@ -47,6 +47,23 @@ async function initDatabase(): Promise<AuthorData> {
|
|||
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) {
|
||||
await fs.writeFile(DATA_FILE, JSON.stringify(parsed, null, 2), "utf-8");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ export default function AdminPanel({ onLogout }: AdminPanelProps) {
|
|||
/>
|
||||
</div>
|
||||
<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
|
||||
rows={8}
|
||||
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"
|
||||
/>
|
||||
</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>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export default function ClaraPortfolio({ data }: ClaraPortfolioProps) {
|
|||
<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>
|
||||
<span>Das Atmen zwischen den Zeilen</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>
|
||||
|
|
@ -90,21 +90,21 @@ export default function ClaraPortfolio({ data }: ClaraPortfolioProps) {
|
|||
<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 className="text-stone-200 font-semibold">Lyrik & Essays</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 className="text-stone-200 font-semibold">Malve & Salbei</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 className="text-stone-200 font-semibold">Naturkontemplation</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -198,6 +198,22 @@ export default function ClaraPortfolio({ data }: ClaraPortfolioProps) {
|
|||
</div>
|
||||
</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>
|
||||
|
||||
{/* Book details modular modal */}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export default function EroticaPortfolio({ data }: EroticaPortfolioProps) {
|
|||
<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">
|
||||
<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>
|
||||
<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>
|
||||
|
|
@ -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" />
|
||||
<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 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" />
|
||||
<div>
|
||||
<div className="text-neutral-500 uppercase tracking-wider text-[10px]">Ästhetik</div>
|
||||
<div className="text-neutral-200 font-semibold">Hautnah, cozy & ungefiltert</div>
|
||||
<div className="text-neutral-500 uppercase tracking-wider text-[10px]">Tonalität</div>
|
||||
<div className="text-neutral-200 font-semibold">Elegant & Knisternd</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">
|
||||
<Key className="w-5 h-5 text-orange-300" />
|
||||
<div>
|
||||
<div className="text-neutral-500 uppercase tracking-wider text-[10px]">Fokus</div>
|
||||
<div className="text-neutral-200 font-semibold">Bedingungsloses Vertrauen & Intime Facetten</div>
|
||||
<div className="text-neutral-500 uppercase tracking-wider text-[10px]">Identität</div>
|
||||
<div className="text-neutral-200 font-semibold">Diskret / Pseudonym</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -198,6 +198,22 @@ export default function EroticaPortfolio({ data }: EroticaPortfolioProps) {
|
|||
</div>
|
||||
</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>
|
||||
|
||||
{/* Book details modular modal */}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@ export const defaultAuthorData: AuthorData = {
|
|||
spotifyPlaylistId: "37i9dQZF1DX4g8Gs5YmN17",
|
||||
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: {
|
||||
name: "M. S. Velvet",
|
||||
|
|
@ -93,7 +95,9 @@ export const defaultAuthorData: AuthorData = {
|
|||
spotifyPlaylistId: "37i9dQZF1DX2U76YeeG0Ug",
|
||||
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: {
|
||||
name: "Clara Finch",
|
||||
|
|
@ -140,6 +144,8 @@ export const defaultAuthorData: AuthorData = {
|
|||
spotifyPlaylistId: "37i9dQZF1DWZqd5YICuS9g",
|
||||
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."
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ export interface AuthorProfile {
|
|||
heroSubtitle: string;
|
||||
projects: Project[];
|
||||
books: Book[];
|
||||
customSectionTitle?: string;
|
||||
customSectionContent?: string;
|
||||
}
|
||||
|
||||
export interface AuthorData {
|
||||
|
|
|
|||
Loading…
Reference in a new issue