diff --git a/components/project-creation-modal.tsx b/components/project-creation-modal.tsx index 0d8a2d2..9b669a0 100644 --- a/components/project-creation-modal.tsx +++ b/components/project-creation-modal.tsx @@ -11,21 +11,33 @@ interface ProjectCreationModalProps { initialWorkspacePath?: string; } +const PROJECT_TYPES = [ + { id: 'web-app', label: 'Web App', icon: '⬡', desc: 'SaaS product users log into — dashboards, accounts, core features' }, + { id: 'website', label: 'Website', icon: '◎', desc: 'Marketing site, landing page, or content-driven public site' }, + { id: 'marketplace', label: 'Marketplace', icon: '⇄', desc: 'Two-sided platform connecting buyers and sellers or providers' }, + { id: 'mobile', label: 'Mobile App', icon: '▢', desc: 'iOS and Android app — touch-first, native feel' }, + { id: 'internal', label: 'Internal Tool', icon: '◫', desc: 'Admin panel, ops dashboard, or business process tool' }, + { id: 'ai-product', label: 'AI Product', icon: '◈', desc: 'AI-native product — copilot, agent, or model-powered workflow' }, +]; + export function ProjectCreationModal({ open, onOpenChange, workspace }: ProjectCreationModalProps) { const router = useRouter(); + const [step, setStep] = useState<1 | 2>(1); const [productName, setProductName] = useState(''); + const [projectType, setProjectType] = useState(null); const [loading, setLoading] = useState(false); const inputRef = useRef(null); useEffect(() => { if (open) { + setStep(1); setProductName(''); + setProjectType(null); setLoading(false); setTimeout(() => inputRef.current?.focus(), 80); } }, [open]); - // Close on Escape useEffect(() => { if (!open) return; const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onOpenChange(false); }; @@ -34,18 +46,17 @@ export function ProjectCreationModal({ open, onOpenChange, workspace }: ProjectC }, [open, onOpenChange]); const handleCreate = async () => { - const name = productName.trim(); - if (!name) return; + if (!productName.trim() || !projectType) return; setLoading(true); try { const res = await fetch('/api/projects/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - projectName: name, - projectType: 'scratch', - slug: name.toLowerCase().replace(/[^a-z0-9]+/g, '-'), - product: { name }, + projectName: productName.trim(), + projectType, + slug: productName.toLowerCase().replace(/[^a-z0-9]+/g, '-'), + product: { name: productName.trim(), type: projectType }, }), }); if (!res.ok) { @@ -84,39 +95,56 @@ export function ProjectCreationModal({ open, onOpenChange, workspace }: ProjectC padding: 24, pointerEvents: 'none', }}>
e.stopPropagation()} style={{ background: '#fff', borderRadius: 14, boxShadow: '0 8px 40px rgba(26,26,26,0.14)', - padding: '36px 40px', - width: '100%', maxWidth: 480, + padding: '32px 36px', + width: '100%', maxWidth: step === 2 ? 560 : 460, fontFamily: 'Outfit, sans-serif', pointerEvents: 'all', animation: 'slideUp 0.18s cubic-bezier(0.4,0,0.2,1)', + transition: 'max-width 0.2s ease', }} - onClick={e => e.stopPropagation()} > {/* Header */} -
-
-

- New project -

-

- Give your project a name to get started. -

+
+
+ {step === 2 && ( + + )} +
+

+ {step === 1 ? 'New project' : `What are you building?`} +

+

+ {step === 1 ? 'Give your project a name to get started.' : `Choose the type that best fits "${productName}".`} +

+
- {/* Name input */} -
- - setProductName(e.target.value)} - onKeyDown={e => { if (e.key === 'Enter' && productName.trim() && !loading) handleCreate(); }} - placeholder="e.g. Foxglove, Meridian, OpsAI…" - style={{ - width: '100%', padding: '11px 14px', - borderRadius: 8, border: '1px solid #e0dcd4', - background: '#faf8f5', fontSize: '0.9rem', - fontFamily: 'Outfit, sans-serif', color: '#1a1a1a', - outline: 'none', transition: 'border-color 0.12s', - boxSizing: 'border-box', - }} - onFocus={e => (e.currentTarget.style.borderColor = '#1a1a1a')} - onBlur={e => (e.currentTarget.style.borderColor = '#e0dcd4')} - /> -
+ {/* Step 1 — Name */} + {step === 1 && ( +
+ + setProductName(e.target.value)} + onKeyDown={e => { if (e.key === 'Enter' && productName.trim()) setStep(2); }} + placeholder="e.g. Foxglove, Meridian, OpsAI…" + style={{ + width: '100%', padding: '11px 14px', marginBottom: 16, + borderRadius: 8, border: '1px solid #e0dcd4', + background: '#faf8f5', fontSize: '0.9rem', + fontFamily: 'Outfit, sans-serif', color: '#1a1a1a', + outline: 'none', transition: 'border-color 0.12s', + boxSizing: 'border-box', + }} + onFocus={e => (e.currentTarget.style.borderColor = '#1a1a1a')} + onBlur={e => (e.currentTarget.style.borderColor = '#e0dcd4')} + /> + +
+ )} - {/* Create button */} - + {/* Step 2 — Project type */} + {step === 2 && ( +
+
+ {PROJECT_TYPES.map(type => { + const isSelected = projectType === type.id; + return ( + + ); + })} +
+ + +
+ )}