'use client' import { useState, useEffect, useRef } from 'react' interface HeroContent { site_name: string site_tagline: string eyebrow_text: string headline1: string headline2: string subtext1: string subtext2: string cta1_text: string; cta1_href: string cta2_text: string; cta2_href: string bg_image_path: string | null } interface Badge { id: string; text: string; reihenfolge: number } const inp: React.CSSProperties = { width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid var(--border-color)', background: 'var(--bg)', color: 'var(--text-primary)', fontSize: '14px', boxSizing: 'border-box', } const lbl: React.CSSProperties = { fontSize: '11px', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '1px', color: 'var(--text-muted)', display: 'block', marginBottom: '6px', } const section: React.CSSProperties = { background: 'var(--surface)', border: '1px solid var(--border-color)', borderLeft: '3px solid var(--accent)', borderRadius: '8px', padding: '20px', } // ← Standardwerte an eigenes Projekt anpassen const DEFAULTS: HeroContent = { site_name: 'Musterfirma', site_tagline: '', eyebrow_text: 'Ihr Slogan hier', headline1: 'Wir lieben Qualität.', headline2: 'Ihre Kunden auch.', subtext1: '', subtext2: '', cta1_text: 'Jetzt anfragen', cta1_href: '#kontakt', cta2_text: 'Unsere Leistungen', cta2_href: '#leistungen', bg_image_path: null, } export function HeroVerwaltung() { const [content, setContent] = useState(DEFAULTS) const [badges, setBadges] = useState([]) const [newBadge, setNewBadge] = useState('') const [saving, setSaving] = useState(false) const [saved, setSaved] = useState(false) const [loading, setLoading] = useState(true) const [uploading, setUploading] = useState(false) const [bgPreview, setBgPreview] = useState(null) const fileRef = useRef(null) const logoRef = useRef(null) const faviconRef = useRef(null) const [logoPath, setLogoPath] = useState(null) const [faviconPath, setFaviconPath] = useState(null) const [uploadingLogo, setUploadingLogo] = useState(false) const [uploadingFavicon, setUploadingFavicon] = useState(false) const supabaseUrl = (process.env.NEXT_PUBLIC_SUPABASE_URL ?? '').replace(/\/$/, '') useEffect(() => { fetch('/api/admin/hero').then(r => r.json()).then(({ content: c, badges: b }) => { if (c) { setContent({ ...DEFAULTS, ...c }) if (c.logo_path) setLogoPath(c.logo_path) if (c.favicon_path) setFaviconPath(c.favicon_path) } setBadges(b ?? []) setLoading(false) }) }, []) const bgUrl = content.bg_image_path ? `${supabaseUrl}/storage/v1/object/public/hero-bilder/${content.bg_image_path}` : null async function handleSave(e: React.FormEvent) { e.preventDefault() setSaving(true) await fetch('/api/admin/hero', { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(content), }) setSaving(false); setSaved(true); setTimeout(() => setSaved(false), 2000) } async function uploadBg(file: File) { setUploading(true) setBgPreview(URL.createObjectURL(file)) const fd = new FormData() fd.append('file', file) const res = await fetch('/api/admin/hero/bild', { method: 'POST', body: fd }) const json = await res.json() if (res.ok) setContent(p => ({ ...p, bg_image_path: json.path })) setUploading(false) if (fileRef.current) fileRef.current.value = '' } async function deleteBg() { await fetch('/api/admin/hero/bild', { method: 'DELETE' }) setContent(p => ({ ...p, bg_image_path: null })) setBgPreview(null) } async function uploadLogo(file: File) { setUploadingLogo(true) const fd = new FormData(); fd.append('file', file) const res = await fetch('/api/admin/hero/logo', { method: 'POST', body: fd }) const json = await res.json() if (res.ok) setLogoPath(json.path) setUploadingLogo(false) if (logoRef.current) logoRef.current.value = '' } async function deleteLogo() { await fetch('/api/admin/hero/logo', { method: 'DELETE' }) setLogoPath(null) } async function uploadFavicon(file: File) { setUploadingFavicon(true) const fd = new FormData(); fd.append('file', file) const res = await fetch('/api/admin/hero/favicon', { method: 'POST', body: fd }) const json = await res.json() if (res.ok) setFaviconPath(json.path) setUploadingFavicon(false) if (faviconRef.current) faviconRef.current.value = '' } async function deleteFavicon() { await fetch('/api/admin/hero/favicon', { method: 'DELETE' }) setFaviconPath(null) } async function addBadge() { if (!newBadge.trim()) return const res = await fetch('/api/admin/hero/badges', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: newBadge.trim(), reihenfolge: badges.length }), }) const { badge } = await res.json() setBadges(prev => [...prev, badge]); setNewBadge('') } async function deleteBadge(id: string) { await fetch(`/api/admin/hero/badges/${id}`, { method: 'DELETE' }) setBadges(prev => prev.filter(b => b.id !== id)) } if (loading) return

Lade…

return (
{/* Linke Spalte: Texte */}

Navbar (Logo)

setContent(p => ({ ...p, site_name: e.target.value }))} placeholder="z. B. Musterfirma" />
setContent(p => ({ ...p, site_tagline: e.target.value }))} placeholder="z. B. Ihr Dienstleister aus der Region" />

Überschriften

setContent(p => ({ ...p, eyebrow_text: e.target.value }))} placeholder="z. B. Ihr Slogan hier" />
setContent(p => ({ ...p, headline1: e.target.value }))} placeholder="z. B. Wir lieben Qualität." />
setContent(p => ({ ...p, headline2: e.target.value }))} placeholder="z. B. Ihre Kunden auch." />

Fließtexte