// swipe-card.jsx — Tinder風の二択スワイプカード function SwipeCard({ question, index, total, onAnswer, prompt }) { const [drag, setDrag] = React.useState({ x: 0, y: 0, active: false }); const [exit, setExit] = React.useState(null); // 'a' | 'b' | null const startRef = React.useRef({ x: 0, y: 0 }); var labelA = question.a ? question.a.label : question.textA; var labelB = question.b ? question.b.label : question.textB; var questionText = prompt || question.q || "次の2つのうち、より近い方を選んでください。"; React.useEffect(() => { setDrag({ x: 0, y: 0, active: false }); setExit(null); }, [question.id]); const onDown = (clientX, clientY) => { if (exit) return; startRef.current = { x: clientX, y: clientY }; setDrag({ x: 0, y: 0, active: true }); }; const onMove = (clientX, clientY) => { if (!drag.active || exit) return; setDrag({ x: clientX - startRef.current.x, y: (clientY - startRef.current.y) * 0.3, active: true, }); }; const onUp = () => { if (!drag.active || exit) return; const threshold = 120; if (drag.x > threshold) commit("b"); else if (drag.x < -threshold) commit("a"); else setDrag({ x: 0, y: 0, active: false }); }; const commit = (choice) => { setExit(choice); setTimeout(() => { onAnswer(choice); }, 520); }; // マウス const handleMouseDown = (e) => onDown(e.clientX, e.clientY); React.useEffect(() => { if (!drag.active) return; const mm = (e) => onMove(e.clientX, e.clientY); const mu = () => onUp(); window.addEventListener("mousemove", mm); window.addEventListener("mouseup", mu); return () => { window.removeEventListener("mousemove", mm); window.removeEventListener("mouseup", mu); }; }, [drag.active, drag.x]); // タッチ const handleTouchStart = (e) => { const t = e.touches[0]; onDown(t.clientX, t.clientY); }; const handleTouchMove = (e) => { const t = e.touches[0]; onMove(t.clientX, t.clientY); }; const rotation = drag.x * 0.05; const aOpacity = Math.max(0, Math.min(1, -drag.x / 120)); const bOpacity = Math.max(0, Math.min(1, drag.x / 120)); let transform = `translate(${drag.x}px, ${drag.y}px) rotate(${rotation}deg)`; let cardClass = "sc-card"; if (exit === "a") { transform = "translate(-140vw, -40px) rotate(-30deg)"; cardClass += " sc-exit"; } else if (exit === "b") { transform = "translate(140vw, -40px) rotate(30deg)"; cardClass += " sc-exit"; } else if (drag.active) { cardClass += " sc-drag"; } return (