form
Some checks failed
Build & Deploy Mintel Blog / build-and-deploy (push) Failing after 58s

This commit is contained in:
2026-01-30 17:48:13 +01:00
parent 1f57bae339
commit 8c1a7f6b5a
23 changed files with 1709 additions and 651 deletions

View File

@@ -2,7 +2,9 @@
import * as React from 'react';
import { FormState } from '../types';
import { Zap, AlertCircle, Minus, Plus } from 'lucide-react';
import { Zap, AlertCircle, Minus, Plus, Settings2, BarChart3 } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { Reveal } from '../../Reveal';
interface ContentStepProps {
state: FormState;
@@ -10,74 +12,167 @@ interface ContentStepProps {
}
export function ContentStep({ state, updateState }: ContentStepProps) {
return (
<div className="space-y-12">
<div className="flex items-center justify-between p-10 bg-white border border-slate-100 rounded-[3rem]">
<div className="max-w-[70%]">
<h4 className="text-2xl font-bold text-slate-900">Inhalte selbst verwalten (CMS)</h4>
<p className="text-lg text-slate-500 mt-2">Möchten Sie Datensätze (z.B. Blogartikel, Produkte) selbst über eine einfache Oberfläche pflegen?</p>
</div>
<button
type="button"
onClick={() => updateState({ cmsSetup: !state.cmsSetup })}
className={`w-20 h-11 rounded-full transition-colors relative focus:outline-none ${state.cmsSetup ? 'bg-slate-900' : 'bg-slate-200'}`}
>
<div className={`absolute top-1.5 left-1.5 w-8 h-8 bg-white rounded-full transition-transform ${state.cmsSetup ? 'translate-x-9' : ''}`} />
</button>
</div>
const toggleDontKnow = (id: string) => {
const current = state.dontKnows || [];
if (current.includes(id)) {
updateState({ dontKnows: current.filter(i => i !== id) });
} else {
updateState({ dontKnows: [...current, id] });
}
};
<div className="p-10 bg-slate-50 rounded-[3rem] border border-slate-100 space-y-6">
<p className="text-lg font-bold text-slate-900">Wie oft ändern sich Ihre Inhalte?</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[
{ id: 'low', label: 'Selten', desc: 'Wenige Male im Jahr.' },
{ id: 'medium', label: 'Regelmäßig', desc: 'Monatliche Updates.' },
{ id: 'high', label: 'Häufig', desc: 'Wöchentlich oder täglich.' },
].map(opt => (
<button
key={opt.id}
return (
<div className="space-y-16">
<Reveal width="100%" delay={0.1}>
<div className="flex flex-col md:flex-row items-center justify-between p-10 bg-white border border-slate-100 rounded-[3rem] shadow-sm gap-8">
<div className="max-w-2xl space-y-4">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-slate-50 rounded-2xl flex items-center justify-center text-slate-900 shadow-inner">
<Settings2 size={24} />
</div>
<h4 className="text-2xl font-bold text-slate-900">Inhalte selbst verwalten (CMS)</h4>
</div>
<p className="text-lg text-slate-500 leading-relaxed">Möchten Sie Datensätze (z.B. Blogartikel, Produkte) selbst über eine einfache Oberfläche pflegen?</p>
</div>
<div className="flex flex-col items-center md:items-end gap-6">
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
type="button"
onClick={() => updateState({ expectedAdjustments: opt.id })}
className={`p-6 rounded-2xl border-2 text-left transition-all focus:outline-none ${
state.expectedAdjustments === opt.id ? 'border-slate-900 bg-slate-900 text-white' : 'border-slate-200 bg-white hover:border-slate-400'
onClick={() => toggleDontKnow('cms')}
className={`px-6 py-3 rounded-full text-sm font-bold transition-all shadow-sm ${
state.dontKnows?.includes('cms') ? 'bg-slate-900 text-white' : 'bg-slate-100 text-slate-500 hover:bg-slate-200'
}`}
>
<p className="font-bold text-lg">{opt.label}</p>
<p className={`text-sm mt-1 ${state.expectedAdjustments === opt.id ? 'text-slate-200' : 'text-slate-500'}`}>{opt.desc}</p>
Ich weiß es nicht
</motion.button>
<button
type="button"
onClick={() => updateState({ cmsSetup: !state.cmsSetup })}
className={`w-24 h-12 rounded-full transition-all duration-500 relative focus:outline-none shadow-inner ${state.cmsSetup ? 'bg-slate-900' : 'bg-slate-200'}`}
>
<motion.div
animate={{ x: state.cmsSetup ? 48 : 0 }}
transition={{ type: "spring", stiffness: 500, damping: 30 }}
className="absolute top-1.5 left-1.5 w-9 h-9 bg-white rounded-full shadow-lg"
/>
</button>
))}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mt-8">
<div className="p-8 bg-white rounded-[2rem] border border-slate-100 space-y-3">
<div className="flex items-center gap-3 text-slate-900 font-bold text-sm uppercase tracking-wider">
<Zap size={18} /> Vorteil CMS
</div>
<p className="text-sm text-slate-500 leading-relaxed">
Volle Kontrolle über Ihre Inhalte und keine laufenden Kosten für kleine Textänderungen oder neue Blog-Beiträge.
</p>
</div>
<div className="p-8 bg-white rounded-[2rem] border border-slate-100 space-y-3">
<div className="flex items-center gap-3 text-slate-900 font-bold text-sm uppercase tracking-wider">
<AlertCircle size={18} /> Fokus Design
</div>
<p className="text-sm text-slate-500 leading-relaxed">
Ohne CMS bleibt die technische Komplexität geringer und das Design ist maximal geschützt vor ungewollten Änderungen.
</p>
</div>
</div>
</div>
</Reveal>
<div className="flex flex-col gap-6 p-10 bg-white border border-slate-100 rounded-[3rem]">
<div>
<h4 className="text-2xl font-bold text-slate-900">Inhalte einpflegen</h4>
<p className="text-lg text-slate-500 mt-2 leading-relaxed">Für wie viele Datensätze soll ich die initiale Befüllung übernehmen?</p>
<Reveal width="100%" delay={0.2}>
<div className="p-10 bg-slate-50 rounded-[3rem] border border-slate-100 space-y-10">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center text-slate-900 shadow-sm">
<BarChart3 size={24} />
</div>
<p className="text-xl font-bold text-slate-900">Wie oft ändern sich Ihre Inhalte?</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[
{ id: 'low', label: 'Selten', desc: 'Wenige Male im Jahr.' },
{ id: 'medium', label: 'Regelmäßig', desc: 'Monatliche Updates.' },
{ id: 'high', label: 'Häufig', desc: 'Wöchentlich oder täglich.' },
].map((opt, index) => (
<motion.button
key={opt.id}
whileHover={{ y: -5, boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)' }}
whileTap={{ scale: 0.98 }}
type="button"
onClick={() => updateState({ expectedAdjustments: opt.id })}
className={`p-6 rounded-[2rem] border-2 text-left transition-all duration-300 focus:outline-none ${
state.expectedAdjustments === opt.id ? 'border-slate-900 bg-slate-900 text-white shadow-xl' : 'border-slate-200 bg-white hover:border-slate-400'
}`}
>
<p className={`font-bold text-lg ${state.expectedAdjustments === opt.id ? 'text-white' : 'text-slate-900'}`}>{opt.label}</p>
<p className={`text-sm mt-2 leading-relaxed ${state.expectedAdjustments === opt.id ? 'text-slate-200' : 'text-slate-500'}`}>{opt.desc}</p>
</motion.button>
))}
</div>
<AnimatePresence>
{state.expectedAdjustments === 'high' && !state.cmsSetup && (
<motion.div
initial={{ opacity: 0, height: 0, y: 20 }}
animate={{ opacity: 1, height: 'auto', y: 0 }}
exit={{ opacity: 0, height: 0, y: 20 }}
className="p-8 bg-amber-50 rounded-[2.5rem] border border-amber-100 flex gap-6 items-start shadow-sm"
>
<div className="w-12 h-12 bg-white rounded-xl flex items-center justify-center text-amber-600 shadow-sm shrink-0">
<AlertCircle size={24} />
</div>
<div className="space-y-2">
<p className="text-amber-900 text-xl font-bold">Empfehlung: CMS nutzen</p>
<p className="text-amber-800 text-base leading-relaxed max-w-3xl">
Bei täglichen oder wöchentlichen Änderungen sparen Sie mit einem CMS langfristig viel Geld, da Sie keine externen Entwickler für Inhalts-Updates benötigen.
</p>
</div>
</motion.div>
)}
</AnimatePresence>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
<div className="p-8 bg-white rounded-[2.5rem] border border-slate-100 space-y-4 shadow-sm">
<div className="flex items-center gap-3 text-slate-900 font-bold text-sm uppercase tracking-[0.2em]">
<Zap size={18} /> Vorteil CMS
</div>
<p className="text-base text-slate-500 leading-relaxed">
Volle Kontrolle über Ihre Inhalte und keine laufenden Kosten für kleine Textänderungen oder neue Blog-Beiträge.
</p>
</div>
<div className="p-8 bg-white rounded-[2.5rem] border border-slate-100 space-y-4 shadow-sm">
<div className="flex items-center gap-3 text-slate-900 font-bold text-sm uppercase tracking-[0.2em]">
<AlertCircle size={18} /> Fokus Design
</div>
<p className="text-base text-slate-500 leading-relaxed">
Ohne CMS bleibt die technische Komplexität geringer und das Design ist maximal geschützt vor ungewollten Änderungen.
</p>
</div>
</div>
</div>
<div className="flex items-center gap-12 mt-2">
<button type="button" onClick={() => updateState({ newDatasets: Math.max(0, state.newDatasets - 1) })} className="w-16 h-16 rounded-full bg-slate-50 border border-slate-100 flex items-center justify-center hover:border-slate-900 transition-colors focus:outline-none"><Minus size={28} /></button>
<span className="text-5xl font-bold w-16 text-center">{state.newDatasets}</span>
<button type="button" onClick={() => updateState({ newDatasets: state.newDatasets + 1 })} className="w-16 h-16 rounded-full bg-slate-50 border border-slate-100 flex items-center justify-center hover:border-slate-900 transition-colors focus:outline-none"><Plus size={28} /></button>
</Reveal>
<Reveal width="100%" delay={0.3}>
<div className="flex flex-col gap-8 p-10 bg-white border border-slate-100 rounded-[3rem] shadow-sm">
<div className="space-y-2">
<h4 className="text-2xl font-bold text-slate-900">Inhalte einpflegen</h4>
<p className="text-lg text-slate-500 leading-relaxed">Für wie viele Datensätze soll ich die initiale Befüllung übernehmen?</p>
</div>
<div className="flex items-center gap-12 py-2">
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
type="button"
onClick={() => updateState({ newDatasets: Math.max(0, state.newDatasets - 1) })}
className="w-16 h-16 rounded-full bg-slate-50 border border-slate-100 flex items-center justify-center hover:border-slate-900 transition-colors focus:outline-none shadow-sm"
>
<Minus size={28} />
</motion.button>
<AnimatePresence mode="wait">
<motion.span
key={state.newDatasets}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
className="text-7xl font-bold w-20 text-center tabular-nums"
>
{state.newDatasets}
</motion.span>
</AnimatePresence>
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
type="button"
onClick={() => updateState({ newDatasets: state.newDatasets + 1 })}
className="w-16 h-16 rounded-full bg-slate-50 border border-slate-100 flex items-center justify-center hover:border-slate-900 transition-colors focus:outline-none shadow-sm"
>
<Plus size={28} />
</motion.button>
</div>
</div>
</div>
</Reveal>
</div>
);
}