import { useState, useRef } from 'react' import useStore from '../store/useStore' const SAMPLE_CATEGORIES = [ { label: '🚗 Vehicles', items: [ { name: 'Race Car', url: 'https://vazxmixjsiawhamofees.supabase.co/storage/v1/object/public/models/car-sport/model.gltf' }, { name: 'Low Poly Car',url: 'https://market-assets.fra1.cdn.digitaloceanspaces.com/market-assets/models/car-with-2-doors/model.gltf' }, { name: 'Truck', url: 'https://market-assets.fra1.cdn.digitaloceanspaces.com/market-assets/models/truck/model.gltf' }, ] }, { label: '🏙️ City / Environment', items: [ { name: 'City Block', url: 'https://market-assets.fra1.cdn.digitaloceanspaces.com/market-assets/models/city-buildings/model.gltf' }, { name: 'Tree', url: 'https://market-assets.fra1.cdn.digitaloceanspaces.com/market-assets/models/tree-spruce/model.gltf' }, { name: 'Bench', url: 'https://market-assets.fra1.cdn.digitaloceanspaces.com/market-assets/models/bench/model.gltf' }, ] }, { label: '🦊 Characters', items: [ { name: 'Fox', url: 'https://threejs.org/examples/models/gltf/Fox/glTF/Fox.gltf' }, { name: 'Robot', url: 'https://threejs.org/examples/models/gltf/RobotExpressive/RobotExpressive.glb' }, { name: 'Soldier', url: 'https://threejs.org/examples/models/gltf/Soldier.glb' }, { name: 'Flamingo', url: 'https://threejs.org/examples/models/gltf/Flamingo.glb' }, ] }, ] // Flatten for backwards compat const SAMPLES = SAMPLE_CATEGORIES.flatMap(c => c.items) const COLORS = ['#4f8eff','#ef4444','#06d6a0','#f59e0b','#8b5cf6','#f97316'] export default function ModelsPanel() { const { models, selectedModelId, addModel, removeModel, selectModel, toggleModelVisibility } = useStore() const [url, setUrl] = useState('') const [name, setName] = useState('') const [samples, setSamples] = useState(false) const [dragging, setDragging] = useState(false) const fileRef = useRef() const handleAdd = () => { if (!url.trim()) return addModel(url.trim(), name.trim() || null) setUrl(''); setName('') } const handleFile = (e) => { const file = e.target.files[0] if (!file) return addModel(URL.createObjectURL(file), file.name.replace(/\.[^.]+$/, '')) } const handleDrop = (e) => { e.preventDefault(); setDragging(false) const file = e.dataTransfer.files[0] if (file && (file.name.endsWith('.glb') || file.name.endsWith('.gltf'))) { addModel(URL.createObjectURL(file), file.name.replace(/\.[^.]+$/, '')) } } return (
{/* Drop zone */}
{ e.preventDefault(); setDragging(true) }} onDragLeave={() => setDragging(false)} onClick={() => fileRef.current?.click()} style={{ border: `2px dashed ${dragging ? 'var(--accent)' : 'var(--border-hi)'}`, borderRadius: 'var(--radius)', padding: '20px 12px', textAlign: 'center', cursor: 'pointer', background: dragging ? 'rgba(79,142,255,0.06)' : 'var(--bg2)', transition: 'all 0.15s', animation: dragging ? 'pulse 1s ease infinite' : 'none', }} >
📦
{dragging ? 'Drop to load' : 'Drop GLB / GLTF here'}
or click to browse
{/* URL input */}
setName(e.target.value)} placeholder="Name (optional)" style={{}} />
setUrl(e.target.value)} onKeyDown={e=>e.key==='Enter'&&handleAdd()} placeholder="Paste GLB / GLTF URL…" style={{ flex:1 }} />
{/* Sample models */} {samples && (
{SAMPLE_CATEGORIES.map(cat => (
{cat.label}
{cat.items.map(item => ( ))}
))}
)} {/* Divider + count */} {models.length > 0 && (
{models.length} MODEL{models.length>1?'S':''}
)} {/* Model list */}
{models.map((m, i) => { const sel = m.id === selectedModelId const c = COLORS[i % COLORS.length] return (
selectModel(m.id)} style={{ display:'flex', alignItems:'center', gap:8, padding:'8px 10px', borderRadius:'var(--radius-sm)', background: sel ? 'rgba(79,142,255,0.1)' : 'var(--bg2)', border:`1px solid ${sel ? 'rgba(79,142,255,0.3)' : 'var(--border)'}`, cursor:'pointer', transition:'all 0.12s', }} onMouseEnter={e => { if (!sel) e.currentTarget.style.background='var(--bg3)' }} onMouseLeave={e => { if (!sel) e.currentTarget.style.background='var(--bg2)' }} > {/* Color dot */}
{/* Name */} {m.name} {/* Anims badge */} {(m.animations?.length??0)>0 && ( {m.animations.length} )} {/* Actions */}
) })} {models.length === 0 && (
No models loaded yet
)}
) }