Split 876-LOC page.tsx into 146 LOC with 7 colocated components (RoadmapCard, CreateRoadmapModal, CreateItemModal, ImportWizard, RoadmapDetailView split into header + items table), plus _types.ts, _constants.ts, and _api.ts. Behavior preserved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
49 lines
2.1 KiB
TypeScript
49 lines
2.1 KiB
TypeScript
import type { Roadmap } from '../_types'
|
|
import { statusColors, statusLabels } from '../_constants'
|
|
|
|
export function RoadmapCard({ roadmap, onSelect, onDelete }: {
|
|
roadmap: Roadmap
|
|
onSelect: (r: Roadmap) => void
|
|
onDelete: (id: string) => void
|
|
}) {
|
|
return (
|
|
<div className="bg-white rounded-xl border-2 border-gray-200 p-6 hover:border-purple-300 transition-colors cursor-pointer"
|
|
onClick={() => onSelect(roadmap)}>
|
|
<div className="flex items-start justify-between mb-3">
|
|
<h4 className="font-semibold text-gray-900 truncate flex-1">{roadmap.title}</h4>
|
|
<span className={`px-2 py-1 text-xs rounded-full ml-2 ${statusColors[roadmap.status] || 'bg-gray-100 text-gray-700'}`}>
|
|
{statusLabels[roadmap.status] || roadmap.status}
|
|
</span>
|
|
</div>
|
|
{roadmap.description && (
|
|
<p className="text-sm text-gray-600 mb-3 line-clamp-2">{roadmap.description}</p>
|
|
)}
|
|
|
|
<div className="mb-3">
|
|
<div className="flex justify-between text-xs text-gray-500 mb-1">
|
|
<span>{roadmap.completed_items}/{roadmap.total_items} Items</span>
|
|
<span>{roadmap.progress}%</span>
|
|
</div>
|
|
<div className="w-full h-2 bg-gray-100 rounded-full overflow-hidden">
|
|
<div className="h-full bg-purple-500 rounded-full transition-all" style={{ width: `${roadmap.progress}%` }} />
|
|
</div>
|
|
</div>
|
|
|
|
{(roadmap.start_date || roadmap.target_date) && (
|
|
<div className="flex items-center gap-2 text-xs text-gray-500 mb-3">
|
|
{roadmap.start_date && <span>Start: {new Date(roadmap.start_date).toLocaleDateString('de-DE')}</span>}
|
|
{roadmap.target_date && <span>Ziel: {new Date(roadmap.target_date).toLocaleDateString('de-DE')}</span>}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-xs text-gray-400">v{roadmap.version}</span>
|
|
<button onClick={(e) => { e.stopPropagation(); onDelete(roadmap.id) }}
|
|
className="text-xs text-red-500 hover:text-red-700 hover:bg-red-50 px-2 py-1 rounded">
|
|
Loeschen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|