{"CACHEDAT":"2026-04-14 05:11:11","SLUG":"v1-vgWpMoxmnh","MARKDOWN":"Erster Anlauf Komptenzmodell Builder mit / von Claude\n\n \n\nzu verfeinern:\n\n* Versatz (nicht bei 0° anfangen)\n* Entscheidung, ob Domains oder Goals die gleiche Größe haben sollen\n* Domain raus, Küchenstücke bis zum Kern\n* Outcomes nach Wahl als konzentrische Unterteilungen der Kuchenstücke\n * Entscheidung, ob unterschiedliche Größen oder zackiger Rand\n\n oder radiale Elemente in einem äußeren Ring\n* keine Unterteilungen, sondern mit Farbschattierungen arbeiten\n* Ausrichtung Beschriftung.\n\n→ eierlegende Wollmichsau machbar\n\n\n```javascript\nimport React, { useState } from 'react';\r\nimport { ChevronRight, Plus, Minus, Download } from 'lucide-react';\r\n\r\nexport default function CompetenceBuilder() {\r\n const [step, setStep] = useState(1);\r\n const [config, setConfig] = useState({\r\n numDomains: 4,\r\n domainArrangement: 'radial',\r\n domains: [\r\n { name: 'Domain 1', color: '#3498DB', goals: [] },\r\n { name: 'Domain 2', color: '#2ECC71', goals: [] },\r\n { name: 'Domain 3', color: '#F39C12', goals: [] },\r\n { name: 'Domain 4', color: '#E74C3C', goals: [] }\r\n ]\r\n });\r\n\r\n const updateDomainCount = (count) => {\r\n const colors = ['#3498DB', '#2ECC71', '#F39C12', '#E74C3C', '#9B59B6', '#1ABC9C', '#E67E22', '#34495E'];\r\n const newDomains = Array.from({ length: count }, (_, i) => \r\n config.domains[i] || { \r\n name: `Domain ${i + 1}`, \r\n color: colors[i % colors.length],\r\n goals: []\r\n }\r\n );\r\n setConfig({ ...config, numDomains: count, domains: newDomains });\r\n };\r\n\r\n const updateDomainName = (index, name) => {\r\n const newDomains = [...config.domains];\r\n newDomains[index].name = name;\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const updateDomainColor = (index, color) => {\r\n const newDomains = [...config.domains];\r\n newDomains[index].color = color;\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const addGoal = (domainIndex) => {\r\n const newDomains = [...config.domains];\r\n newDomains[domainIndex].goals.push({\r\n name: `Goal ${newDomains[domainIndex].goals.length + 1}`,\r\n outcomes: []\r\n });\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const updateGoalName = (domainIndex, goalIndex, name) => {\r\n const newDomains = [...config.domains];\r\n newDomains[domainIndex].goals[goalIndex].name = name;\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const removeGoal = (domainIndex, goalIndex) => {\r\n const newDomains = [...config.domains];\r\n newDomains[domainIndex].goals.splice(goalIndex, 1);\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const addOutcome = (domainIndex, goalIndex) => {\r\n const newDomains = [...config.domains];\r\n newDomains[domainIndex].goals[goalIndex].outcomes.push(\r\n `Outcome ${newDomains[domainIndex].goals[goalIndex].outcomes.length + 1}`\r\n );\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const updateOutcomeName = (domainIndex, goalIndex, outcomeIndex, name) => {\r\n const newDomains = [...config.domains];\r\n newDomains[domainIndex].goals[goalIndex].outcomes[outcomeIndex] = name;\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const removeOutcome = (domainIndex, goalIndex, outcomeIndex) => {\r\n const newDomains = [...config.domains];\r\n newDomains[domainIndex].goals[goalIndex].outcomes.splice(outcomeIndex, 1);\r\n setConfig({ ...config, domains: newDomains });\r\n };\r\n\r\n const generateVisualization = () => {\r\n setStep(4);\r\n };\r\n\r\n const downloadSVG = () => {\r\n const svgElement = document.getElementById('competence-visualization');\r\n if (!svgElement) return;\r\n \r\n const svgData = new XMLSerializer().serializeToString(svgElement);\r\n const blob = new Blob([svgData], { type: 'image/svg+xml' });\r\n const url = URL.createObjectURL(blob);\r\n const link = document.createElement('a');\r\n link.href = url;\r\n link.download = 'kompetenzmodell.svg';\r\n link.click();\r\n URL.revokeObjectURL(url);\r\n };\r\n\r\n const RadialVisualization = () => {\r\n const centerX = 500;\r\n const centerY = 500;\r\n const innerRadius = 80;\r\n const domainWidth = 120;\r\n const goalWidth = 100;\r\n const outcomeWidth = 80;\r\n \r\n const angleStep = (2 * Math.PI) / config.domains.length;\r\n\r\n return (\r\n \r\n );\r\n };\r\n\r\n const ConcentricVisualization = () => {\r\n const centerX = 500;\r\n const centerY = 500;\r\n const innerRadius = 80;\r\n const ringWidth = 100;\r\n \r\n return (\r\n \r\n );\r\n };\r\n\r\n const describeArc = (x, y, innerRadius, outerRadius, startAngle, endAngle) => {\r\n const innerStart = polarToCartesian(x, y, innerRadius, endAngle);\r\n const innerEnd = polarToCartesian(x, y, innerRadius, startAngle);\r\n const outerStart = polarToCartesian(x, y, outerRadius, endAngle);\r\n const outerEnd = polarToCartesian(x, y, outerRadius, startAngle);\r\n\r\n const largeArcFlag = endAngle - startAngle <= Math.PI ? \"0\" : \"1\";\r\n\r\n return [\r\n \"M\", outerStart.x, outerStart.y,\r\n \"A\", outerRadius, outerRadius, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y,\r\n \"L\", innerEnd.x, innerEnd.y,\r\n \"A\", innerRadius, innerRadius, 0, largeArcFlag, 1, innerStart.x, innerStart.y,\r\n \"Z\"\r\n ].join(\" \");\r\n };\r\n\r\n const polarToCartesian = (centerX, centerY, radius, angleInRadians) => {\r\n return {\r\n x: centerX + (radius * Math.cos(angleInRadians)),\r\n y: centerY + (radius * Math.sin(angleInRadians))\r\n };\r\n };\r\n\r\n return (\r\n
Noch keine Goals definiert
\r\n )}\r\nErster Anlauf Komptenzmodell Builder mit / von Claude
\nzu verfeinern:
\noder radiale Elemente in einem äußeren Ring
\n→ eierlegende Wollmichsau machbar
\nimport React, { useState } from 'react';
import { ChevronRight, Plus, Minus, Download } from 'lucide-react';
export default function CompetenceBuilder() {
const [step, setStep] = useState(1);
const [config, setConfig] = useState({
numDomains: 4,
domainArrangement: 'radial',
domains: [
{ name: 'Domain 1', color: '#3498DB', goals: [] },
{ name: 'Domain 2', color: '#2ECC71', goals: [] },
{ name: 'Domain 3', color: '#F39C12', goals: [] },
{ name: 'Domain 4', color: '#E74C3C', goals: [] }
]
});
const updateDomainCount = (count) => {
const colors = ['#3498DB', '#2ECC71', '#F39C12', '#E74C3C', '#9B59B6', '#1ABC9C', '#E67E22', '#34495E'];
const newDomains = Array.from({ length: count }, (_, i) =>
config.domains[i] || {
name: `Domain ${i + 1}`,
color: colors[i % colors.length],
goals: []
}
);
setConfig({ ...config, numDomains: count, domains: newDomains });
};
const updateDomainName = (index, name) => {
const newDomains = [...config.domains];
newDomains[index].name = name;
setConfig({ ...config, domains: newDomains });
};
const updateDomainColor = (index, color) => {
const newDomains = [...config.domains];
newDomains[index].color = color;
setConfig({ ...config, domains: newDomains });
};
const addGoal = (domainIndex) => {
const newDomains = [...config.domains];
newDomains[domainIndex].goals.push({
name: `Goal ${newDomains[domainIndex].goals.length + 1}`,
outcomes: []
});
setConfig({ ...config, domains: newDomains });
};
const updateGoalName = (domainIndex, goalIndex, name) => {
const newDomains = [...config.domains];
newDomains[domainIndex].goals[goalIndex].name = name;
setConfig({ ...config, domains: newDomains });
};
const removeGoal = (domainIndex, goalIndex) => {
const newDomains = [...config.domains];
newDomains[domainIndex].goals.splice(goalIndex, 1);
setConfig({ ...config, domains: newDomains });
};
const addOutcome = (domainIndex, goalIndex) => {
const newDomains = [...config.domains];
newDomains[domainIndex].goals[goalIndex].outcomes.push(
`Outcome ${newDomains[domainIndex].goals[goalIndex].outcomes.length + 1}`
);
setConfig({ ...config, domains: newDomains });
};
const updateOutcomeName = (domainIndex, goalIndex, outcomeIndex, name) => {
const newDomains = [...config.domains];
newDomains[domainIndex].goals[goalIndex].outcomes[outcomeIndex] = name;
setConfig({ ...config, domains: newDomains });
};
const removeOutcome = (domainIndex, goalIndex, outcomeIndex) => {
const newDomains = [...config.domains];
newDomains[domainIndex].goals[goalIndex].outcomes.splice(outcomeIndex, 1);
setConfig({ ...config, domains: newDomains });
};
const generateVisualization = () => {
setStep(4);
};
const downloadSVG = () => {
const svgElement = document.getElementById('competence-visualization');
if (!svgElement) return;
const svgData = new XMLSerializer().serializeToString(svgElement);
const blob = new Blob([svgData], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'kompetenzmodell.svg';
link.click();
URL.revokeObjectURL(url);
};
const RadialVisualization = () => {
const centerX = 500;
const centerY = 500;
const innerRadius = 80;
const domainWidth = 120;
const goalWidth = 100;
const outcomeWidth = 80;
const angleStep = (2 * Math.PI) / config.domains.length;
return (
<svg id="competence-visualization" width="1000" height="1000" viewBox="0 0 1000 1000">
{/* Center Circle */}
<circle cx={centerX} cy={centerY} r={innerRadius} fill="#f8f9fa" stroke="#dee2e6" strokeWidth="2" />
<text x={centerX} y={centerY} textAnchor="middle" dominantBaseline="middle" fontSize="16" fontWeight="bold" fill="#495057">
Kompetenz-
</text>
<text x={centerX} y={centerY + 20} textAnchor="middle" dominantBaseline="middle" fontSize="16" fontWeight="bold" fill="#495057">
modell
</text>
{config.domains.map((domain, domainIdx) => {
const startAngle = domainIdx * angleStep - Math.PI / 2;
const endAngle = (domainIdx + 1) * angleStep - Math.PI / 2;
const midAngle = (startAngle + endAngle) / 2;
// Domain arc
const domainInner = innerRadius;
const domainOuter = innerRadius + domainWidth;
const domainPath = describeArc(centerX, centerY, domainInner, domainOuter, startAngle, endAngle);
// Goals
const goalInner = domainOuter;
const goalOuter = domainOuter + goalWidth;
// Outcomes
const outcomeInner = goalOuter;
const outcomeOuter = goalOuter + outcomeWidth;
const totalGoals = domain.goals.length || 1;
const goalAngleStep = (endAngle - startAngle) / totalGoals;
return (
<g key={domainIdx}>
{/* Domain segment */}
<path d={domainPath} fill={domain.color} stroke="white" strokeWidth="3" opacity="0.8" />
{/* Domain label */}
<text
x={centerX + Math.cos(midAngle) * (domainInner + domainWidth / 2)}
y={centerY + Math.sin(midAngle) * (domainInner + domainWidth / 2)}
textAnchor="middle"
dominantBaseline="middle"
fontSize="14"
fontWeight="bold"
fill="white"
transform={`rotate(${(midAngle * 180 / Math.PI + 90)}, ${centerX + Math.cos(midAngle) * (domainInner + domainWidth / 2)}, ${centerY + Math.sin(midAngle) * (domainInner + domainWidth / 2)})`}
>
{domain.name}
</text>
{/* Goals */}
{domain.goals.length > 0 ? domain.goals.map((goal, goalIdx) => {
const goalStartAngle = startAngle + goalIdx * goalAngleStep;
const goalEndAngle = startAngle + (goalIdx + 1) * goalAngleStep;
const goalMidAngle = (goalStartAngle + goalEndAngle) / 2;
const goalPath = describeArc(centerX, centerY, goalInner, goalOuter, goalStartAngle, goalEndAngle);
const totalOutcomes = goal.outcomes.length || 1;
const outcomeAngleStep = (goalEndAngle - goalStartAngle) / totalOutcomes;
return (
<g key={goalIdx}>
<path d={goalPath} fill={domain.color} stroke="white" strokeWidth="2" opacity="0.6" />
<text
x={centerX + Math.cos(goalMidAngle) * (goalInner + goalWidth / 2)}
y={centerY + Math.sin(goalMidAngle) * (goalInner + goalWidth / 2)}
textAnchor="middle"
dominantBaseline="middle"
fontSize="11"
fill="white"
transform={`rotate(${(goalMidAngle * 180 / Math.PI + 90)}, ${centerX + Math.cos(goalMidAngle) * (goalInner + goalWidth / 2)}, ${centerY + Math.sin(goalMidAngle) * (goalInner + goalWidth / 2)})`}
>
{goal.name.length > 15 ? goal.name.substring(0, 15) + '...' : goal.name}
</text>
{/* Outcomes */}
{goal.outcomes.length > 0 && goal.outcomes.map((outcome, outcomeIdx) => {
const outcomeStartAngle = goalStartAngle + outcomeIdx * outcomeAngleStep;
const outcomeEndAngle = goalStartAngle + (outcomeIdx + 1) * outcomeAngleStep;
const outcomeMidAngle = (outcomeStartAngle + outcomeEndAngle) / 2;
const outcomePath = describeArc(centerX, centerY, outcomeInner, outcomeOuter, outcomeStartAngle, outcomeEndAngle);
return (
<g key={outcomeIdx}>
<path d={outcomePath} fill={domain.color} stroke="white" strokeWidth="2" opacity="0.4" />
<text
x={centerX + Math.cos(outcomeMidAngle) * (outcomeInner + outcomeWidth / 2)}
y={centerY + Math.sin(outcomeMidAngle) * (outcomeInner + outcomeWidth / 2)}
textAnchor="middle"
dominantBaseline="middle"
fontSize="9"
fill="white"
transform={`rotate(${(outcomeMidAngle * 180 / Math.PI + 90)}, ${centerX + Math.cos(outcomeMidAngle) * (outcomeInner + outcomeWidth / 2)}, ${centerY + Math.sin(outcomeMidAngle) * (outcomeInner + outcomeWidth / 2)})`}
>
{outcome.length > 12 ? outcome.substring(0, 12) + '...' : outcome}
</text>
</g>
);
})}
</g>
);
}) : (
<path d={describeArc(centerX, centerY, goalInner, outcomeOuter, startAngle, endAngle)} fill={domain.color} stroke="white" strokeWidth="2" opacity="0.3" />
)}
</g>
);
})}
</svg>
);
};
const ConcentricVisualization = () => {
const centerX = 500;
const centerY = 500;
const innerRadius = 80;
const ringWidth = 100;
return (
<svg id="competence-visualization" width="1000" height="1000" viewBox="0 0 1000 1000">
{/* Center Circle */}
<circle cx={centerX} cy={centerY} r={innerRadius} fill="#f8f9fa" stroke="#dee2e6" strokeWidth="2" />
<text x={centerX} y={centerY} textAnchor="middle" dominantBaseline="middle" fontSize="16" fontWeight="bold" fill="#495057">
Kompetenz-
</text>
<text x={centerX} y={centerY + 20} textAnchor="middle" dominantBaseline="middle" fontSize="16" fontWeight="bold" fill="#495057">
modell
</text>
{config.domains.map((domain, domainIdx) => {
const domainRadius = innerRadius + (domainIdx + 1) * ringWidth;
const angleStep = (2 * Math.PI) / (domain.goals.length || 8);
return (
<g key={domainIdx}>
{/* Domain ring */}
<circle
cx={centerX}
cy={centerY}
r={domainRadius}
fill="none"
stroke={domain.color}
strokeWidth={ringWidth - 10}
opacity="0.3"
/>
{/* Domain label */}
<text
x={centerX}
y={centerY - domainRadius - 10}
textAnchor="middle"
fontSize="14"
fontWeight="bold"
fill={domain.color}
>
{domain.name}
</text>
{/* Goals as segments */}
{domain.goals.length > 0 ? domain.goals.map((goal, goalIdx) => {
const angle = goalIdx * angleStep - Math.PI / 2;
const x = centerX + Math.cos(angle) * domainRadius;
const y = centerY + Math.sin(angle) * domainRadius;
return (
<g key={goalIdx}>
{/* Goal point */}
<circle cx={x} cy={y} r="8" fill={domain.color} stroke="white" strokeWidth="2" />
{/* Goal label */}
<text
x={x + Math.cos(angle) * 30}
y={y + Math.sin(angle) * 30}
textAnchor="middle"
dominantBaseline="middle"
fontSize="10"
fill={domain.color}
fontWeight="600"
>
{goal.name.length > 20 ? goal.name.substring(0, 20) + '...' : goal.name}
</text>
{/* Outcomes as smaller points */}
{goal.outcomes.map((outcome, outcomeIdx) => {
const outcomeAngleOffset = (outcomeIdx - (goal.outcomes.length - 1) / 2) * 0.15;
const outcomeAngle = angle + outcomeAngleOffset;
const outcomeRadius = domainRadius + 25;
const ox = centerX + Math.cos(outcomeAngle) * outcomeRadius;
const oy = centerY + Math.sin(outcomeAngle) * outcomeRadius;
return (
<g key={outcomeIdx}>
<line x1={x} y1={y} x2={ox} y2={oy} stroke={domain.color} strokeWidth="1" opacity="0.5" />
<circle cx={ox} cy={oy} r="4" fill={domain.color} opacity="0.7" stroke="white" strokeWidth="1" />
</g>
);
})}
</g>
);
}) : null}
</g>
);
})}
</svg>
);
};
const describeArc = (x, y, innerRadius, outerRadius, startAngle, endAngle) => {
const innerStart = polarToCartesian(x, y, innerRadius, endAngle);
const innerEnd = polarToCartesian(x, y, innerRadius, startAngle);
const outerStart = polarToCartesian(x, y, outerRadius, endAngle);
const outerEnd = polarToCartesian(x, y, outerRadius, startAngle);
const largeArcFlag = endAngle - startAngle <= Math.PI ? "0" : "1";
return [
"M", outerStart.x, outerStart.y,
"A", outerRadius, outerRadius, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y,
"L", innerEnd.x, innerEnd.y,
"A", innerRadius, innerRadius, 0, largeArcFlag, 1, innerStart.x, innerStart.y,
"Z"
].join(" ");
};
const polarToCartesian = (centerX, centerY, radius, angleInRadians) => {
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
};
return (
<div className="min-h-screen bg-gray-50 p-8">
<div className="max-w-6xl mx-auto">
<h1 className="text-3xl font-bold text-gray-800 mb-8">Kompetenzmodell Builder</h1>
{/* Progress Steps */}
<div className="flex items-center justify-center mb-8 space-x-4">
{['Struktur', 'Domains', 'Goals & Outcomes', 'Visualisierung'].map((label, idx) => (
<div key={idx} className="flex items-center">
<div className={`w-10 h-10 rounded-full flex items-center justify-center font-semibold ${
step > idx + 1 ? 'bg-green-500 text-white' :
step === idx + 1 ? 'bg-blue-500 text-white' :
'bg-gray-300 text-gray-600'
}`}>
{idx + 1}
</div>
<span className="ml-2 text-sm font-medium text-gray-700">{label}</span>
{idx < 3 && <ChevronRight className="ml-4 text-gray-400" size={20} />}
</div>
))}
</div>
{/* Step 1: Grundstruktur */}
{step === 1 && (
<div className="bg-white rounded-lg shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Schritt 1: Grundstruktur</h2>
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Anzahl der Domains (Ebene 1)
</label>
<input
type="number"
min="2"
max="8"
value={config.numDomains}
onChange={(e) => updateDomainCount(parseInt(e.target.value))}
className="w-32 px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Anordnung der Domains
</label>
<div className="space-y-2">
<label className="flex items-center">
<input
type="radio"
name="arrangement"
value="radial"
checked={config.domainArrangement === 'radial'}
onChange={(e) => setConfig({ ...config, domainArrangement: e.target.value })}
className="mr-2"
/>
<span>Radial (Kuchenstücke)</span>
</label>
<label className="flex items-center">
<input
type="radio"
name="arrangement"
value="concentric"
checked={config.domainArrangement === 'concentric'}
onChange={(e) => setConfig({ ...config, domainArrangement: e.target.value })}
className="mr-2"
/>
<span>Konzentrisch (Ringe)</span>
</label>
</div>
</div>
</div>
<button
onClick={() => setStep(2)}
className="mt-8 px-6 py-3 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-600 transition"
>
Weiter zu Domains
</button>
</div>
)}
{/* Step 2: Domains konfigurieren */}
{step === 2 && (
<div className="bg-white rounded-lg shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Schritt 2: Domains benennen</h2>
<div className="space-y-4">
{config.domains.map((domain, idx) => (
<div key={idx} className="flex items-center space-x-4 p-4 bg-gray-50 rounded-lg">
<div className="flex-1">
<input
type="text"
value={domain.name}
onChange={(e) => updateDomainName(idx, e.target.value)}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"
placeholder="Domain Name"
/>
</div>
<input
type="color"
value={domain.color}
onChange={(e) => updateDomainColor(idx, e.target.value)}
className="w-16 h-10 rounded cursor-pointer"
/>
</div>
))}
</div>
<div className="flex space-x-4 mt-8">
<button
onClick={() => setStep(1)}
className="px-6 py-3 bg-gray-300 text-gray-700 font-semibold rounded-lg hover:bg-gray-400 transition"
>
Zurück
</button>
<button
onClick={() => setStep(3)}
className="px-6 py-3 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-600 transition"
>
Weiter zu Goals & Outcomes
</button>
</div>
</div>
)}
{/* Step 3: Goals und Outcomes */}
{step === 3 && (
<div className="bg-white rounded-lg shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Schritt 3: Goals & Outcomes definieren</h2>
<div className="space-y-6">
{config.domains.map((domain, domainIdx) => (
<div key={domainIdx} className="border-2 rounded-lg p-6" style={{ borderColor: domain.color }}>
<div className="flex items-center justify-between mb-4">
<h3 className="text-xl font-bold" style={{ color: domain.color }}>
{domain.name}
</h3>
<button
onClick={() => addGoal(domainIdx)}
className="flex items-center px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition"
>
<Plus size={16} className="mr-2" />
Goal hinzufügen
</button>
</div>
<div className="space-y-4">
{domain.goals.map((goal, goalIdx) => (
<div key={goalIdx} className="bg-gray-50 rounded-lg p-4">
<div className="flex items-center space-x-2 mb-3">
<input
type="text"
value={goal.name}
onChange={(e) => updateGoalName(domainIdx, goalIdx, e.target.value)}
className="flex-1 px-3 py-2 border border-gray-300 rounded-md"
placeholder="Goal Name"
/>
<button
onClick={() => removeGoal(domainIdx, goalIdx)}
className="p-2 bg-red-500 text-white rounded hover:bg-red-600"
>
<Minus size={16} />
</button>
</div>
<div className="ml-4 space-y-2">
<button
onClick={() => addOutcome(domainIdx, goalIdx)}
className="text-sm px-3 py-1 bg-blue-100 text-blue-700 rounded hover:bg-blue-200"
>
+ Outcome hinzufügen
</button>
{goal.outcomes.map((outcome, outcomeIdx) => (
<div key={outcomeIdx} className="flex items-center space-x-2">
<input
type="text"
value={outcome}
onChange={(e) => updateOutcomeName(domainIdx, goalIdx, outcomeIdx, e.target.value)}
className="flex-1 px-3 py-1 text-sm border border-gray-300 rounded"
placeholder="Outcome Name"
/>
<button
onClick={() => removeOutcome(domainIdx, goalIdx, outcomeIdx)}
className="p-1 text-red-500 hover:bg-red-50 rounded"
>
<Minus size={14} />
</button>
</div>
))}
</div>
</div>
))}
</div>
{domain.goals.length === 0 && (
<p className="text-gray-500 text-sm italic">Noch keine Goals definiert</p>
)}
</div>
))}
</div>
<div className="flex space-x-4 mt-8">
<button
onClick={() => setStep(2)}
className="px-6 py-3 bg-gray-300 text-gray-700 font-semibold rounded-lg hover:bg-gray-400 transition"
>
Zurück
</button>
<button
onClick={generateVisualization}
className="px-6 py-3 bg-green-500 text-white font-semibold rounded-lg hover:bg-green-600 transition"
>
Visualisierung generieren
</button>
</div>
</div>
)}
{/* Step 4: Visualisierung */}
{step === 4 && (
<div className="bg-white rounded-lg shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Schritt 4: Visualisierung</h2>
<div className="flex justify-center mb-6">
{config.domainArrangement === 'radial' ? <RadialVisualization /> : <ConcentricVisualization />}
</div>
<div className="flex justify-center space-x-4 mt-8">
<button
onClick={() => setStep(3)}
className="px-6 py-3 bg-gray-300 text-gray-700 font-semibold rounded-lg hover:bg-gray-400 transition"
>
Zurück zur Konfiguration
</button>
<button
onClick={downloadSVG}
className="flex items-center px-6 py-3 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-600 transition"
>
<Download size={16} className="mr-2" />
SVG herunterladen
</button>
</div>
</div>
)}
</div>
</div>
);
}\nVersionen
\n