Spaces:
Running
Running
| import { useState } from 'react'; | |
| import { FrameworkType } from '../../types'; | |
| import { FRAMEWORKS } from '../../types/project'; | |
| import { | |
| Globe, Monitor, Smartphone, Server, ChevronRight, | |
| Check, Code2, Zap, Layers, Layout | |
| } from 'lucide-react'; | |
| interface FrameworkSelectorProps { | |
| onSelect: (name: string, framework: FrameworkType, description: string) => void; | |
| onCancel: () => void; | |
| } | |
| export default function FrameworkSelector({ onSelect, onCancel }: FrameworkSelectorProps) { | |
| const [selected, setSelected] = useState<FrameworkType | null>(null); | |
| const [projectName, setProjectName] = useState(''); | |
| const [description, setDescription] = useState(''); | |
| const getIcon = (fw: FrameworkType) => { | |
| switch (fw) { | |
| case 'web': return Globe; | |
| case 'electron': return Monitor; | |
| case 'maui': return Smartphone; | |
| case 'nodejs': return Server; | |
| } | |
| }; | |
| const handleSubmit = (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| if (selected && projectName.trim()) { | |
| onSelect(projectName.trim(), selected, description.trim()); | |
| } | |
| }; | |
| return ( | |
| <form onSubmit={handleSubmit} className="space-y-6"> | |
| {/* Project Name */} | |
| <div> | |
| <div className="flex items-center justify-between mb-1"> | |
| <label className="block text-sm text-surface-300">Project Name</label> | |
| <span className={`text-xs ${projectName.length > 45 ? 'text-red-400' : 'text-surface-500'}`}> | |
| {projectName.length}/50 | |
| </span> | |
| </div> | |
| <input | |
| type="text" | |
| value={projectName} | |
| onChange={(e) => setProjectName(e.target.value.slice(0, 50))} | |
| className="input" | |
| placeholder="My Awesome App" | |
| required | |
| autoFocus | |
| maxLength={50} | |
| /> | |
| </div> | |
| {/* Framework Selection */} | |
| <div> | |
| <label className="block text-sm text-surface-300 mb-3">Choose Framework</label> | |
| <div className="grid grid-cols-2 gap-3"> | |
| {(Object.entries(FRAMEWORKS) as [FrameworkType, typeof FRAMEWORKS[FrameworkType]][]).map(([key, fw]) => { | |
| const Icon = getIcon(key); | |
| const isSelected = selected === key; | |
| return ( | |
| <button | |
| type="button" | |
| key={key} | |
| onClick={() => setSelected(key)} | |
| className={`relative p-4 rounded-xl border text-left transition-all duration-200 ${ | |
| isSelected | |
| ? 'border-primary-500 bg-primary-500/10 ring-1 ring-primary-500' | |
| : 'border-surface-700 bg-surface-800/50 hover:border-surface-500' | |
| }`} | |
| > | |
| {isSelected && ( | |
| <div className="absolute top-2 right-2 w-5 h-5 bg-primary-500 rounded-full flex items-center justify-center"> | |
| <Check className="w-3 h-3 text-white" /> | |
| </div> | |
| )} | |
| <div className={`w-10 h-10 rounded-lg bg-gradient-to-br ${fw.gradient} flex items-center justify-center mb-2`}> | |
| <Icon className="w-5 h-5 text-white" /> | |
| </div> | |
| <h4 className="font-semibold text-white text-sm">{fw.name}</h4> | |
| <p className="text-xs text-surface-400 mt-1 line-clamp-2">{fw.description}</p> | |
| <div className="flex flex-wrap gap-1 mt-2"> | |
| {fw.languages.map((lang) => ( | |
| <span key={lang} className="text-[10px] px-1.5 py-0.5 rounded bg-surface-700 text-surface-300"> | |
| {lang} | |
| </span> | |
| ))} | |
| </div> | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| {/* Description */} | |
| <div> | |
| <label className="block text-sm text-surface-300 mb-1"> | |
| Description <span className="text-surface-500">(optional)</span> | |
| </label> | |
| <textarea | |
| value={description} | |
| onChange={(e) => setDescription(e.target.value)} | |
| className="input resize-none h-20" | |
| placeholder="What does your project do?" | |
| /> | |
| </div> | |
| {/* Action Buttons */} | |
| <div className="flex gap-3 justify-end pt-2"> | |
| <button type="button" onClick={onCancel} className="btn-secondary"> | |
| Cancel | |
| </button> | |
| <button | |
| type="submit" | |
| disabled={!selected || !projectName.trim()} | |
| className="btn-primary" | |
| > | |
| <Zap className="w-4 h-4" /> | |
| Create Project | |
| </button> | |
| </div> | |
| </form> | |
| ); | |
| } | |