180 lines
6.4 KiB
TypeScript
180 lines
6.4 KiB
TypeScript
'use client'
|
||
|
||
import { useState, useRef, useEffect, useCallback } from 'react'
|
||
import { SimpleCard, CONFIDENCE_LEVELS } from '../data'
|
||
|
||
interface SimpleFlipCardProps {
|
||
card: SimpleCard
|
||
onAnswer: (confidence: number) => void
|
||
}
|
||
|
||
export function SimpleFlipCard({ card, onAnswer }: SimpleFlipCardProps) {
|
||
const [isFlipped, setIsFlipped] = useState(false)
|
||
const [selectedConfidence, setSelectedConfidence] = useState<number | null>(null)
|
||
const [cardHeight, setCardHeight] = useState<number>(400)
|
||
const frontRef = useRef<HTMLDivElement>(null)
|
||
const backRef = useRef<HTMLDivElement>(null)
|
||
|
||
// 智能高度計算 (復用原有邏輯)
|
||
useEffect(() => {
|
||
const updateCardHeight = () => {
|
||
if (backRef.current) {
|
||
const backHeight = backRef.current.scrollHeight
|
||
|
||
// 響應式最小高度設定 (復用原有響應式邏輯)
|
||
const minHeightByScreen = window.innerWidth <= 480 ? 300 :
|
||
window.innerWidth <= 768 ? 350 : 400
|
||
|
||
const finalHeight = Math.max(minHeightByScreen, backHeight)
|
||
setCardHeight(finalHeight)
|
||
}
|
||
}
|
||
|
||
const timer = setTimeout(updateCardHeight, 100)
|
||
window.addEventListener('resize', updateCardHeight)
|
||
|
||
return () => {
|
||
clearTimeout(timer)
|
||
window.removeEventListener('resize', updateCardHeight)
|
||
}
|
||
}, [card.word, card.definition, card.example])
|
||
|
||
const handleFlip = useCallback(() => {
|
||
setIsFlipped(!isFlipped)
|
||
}, [isFlipped])
|
||
|
||
const handleConfidenceSelect = useCallback((level: number) => {
|
||
setSelectedConfidence(level)
|
||
}, [])
|
||
|
||
const handleSubmit = () => {
|
||
if (selectedConfidence) {
|
||
onAnswer(selectedConfidence)
|
||
// 重置狀態為下一張卡片準備
|
||
setIsFlipped(false)
|
||
setSelectedConfidence(null)
|
||
}
|
||
}
|
||
|
||
const hasAnswered = selectedConfidence !== null
|
||
|
||
return (
|
||
<div className="max-w-md mx-auto">
|
||
{/* 高級3D翻卡容器 (復用原有設計) */}
|
||
<div
|
||
className="flip-card-container"
|
||
onClick={handleFlip}
|
||
style={{
|
||
height: `${cardHeight}px`,
|
||
minHeight: '400px',
|
||
transition: 'height 0.4s cubic-bezier(0.4, 0, 0.2, 1)'
|
||
}}
|
||
>
|
||
<div
|
||
className={`flip-card ${isFlipped ? 'flipped' : ''}`}
|
||
style={{
|
||
transform: isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)'
|
||
}}
|
||
>
|
||
{/* 正面 - 單字 (復用原有設計風格) */}
|
||
<div ref={frontRef} className="flip-card-front bg-white">
|
||
<div className="p-8 h-full">
|
||
<div className="space-y-4">
|
||
<p className="text-lg text-gray-700 mb-6 text-left">
|
||
點擊卡片翻面,根據你對單字的熟悉程度進行自我評估:
|
||
</p>
|
||
|
||
<div className="flex-1 flex items-center justify-center mt-6">
|
||
<div className="bg-gray-50 rounded-lg p-8 w-full text-center">
|
||
<h3 className="text-4xl font-bold text-gray-900 mb-6">{card.word}</h3>
|
||
<span className="text-lg text-gray-500">{card.pronunciation}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 背面 - 詳細資訊 (復用原有布局) */}
|
||
<div ref={backRef} className="flip-card-back bg-white">
|
||
<div className="p-8 h-full">
|
||
<div className="space-y-4 pb-6">
|
||
{/* 定義區塊 */}
|
||
<div className="content-block">
|
||
<h3>定義</h3>
|
||
<p>{card.definition}</p>
|
||
</div>
|
||
|
||
{/* 例句區塊 */}
|
||
<div className="content-block">
|
||
<h3>例句</h3>
|
||
<p className="italic mb-2">"{card.example}"</p>
|
||
<p className="text-gray-600 text-sm">"{card.translation}"</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 信心度選擇 - 復用原有的精美設計 */}
|
||
{isFlipped && (
|
||
<div className="mt-6 space-y-3">
|
||
<h3 className="text-lg font-semibold text-gray-900 mb-4 text-left">
|
||
請選擇您對這個詞彙的熟悉程度:
|
||
</h3>
|
||
|
||
<div className="grid grid-cols-5 gap-3">
|
||
{CONFIDENCE_LEVELS.map(({ level, label, color }) => {
|
||
const isSelected = selectedConfidence === level
|
||
const colorClasses = {
|
||
'bg-red-500': 'bg-red-100 text-red-700 border-red-200 hover:bg-red-200',
|
||
'bg-orange-500': 'bg-orange-100 text-orange-700 border-orange-200 hover:bg-orange-200',
|
||
'bg-yellow-500': 'bg-yellow-100 text-yellow-700 border-yellow-200 hover:bg-yellow-200',
|
||
'bg-blue-500': 'bg-blue-100 text-blue-700 border-blue-200 hover:bg-blue-200',
|
||
'bg-green-500': 'bg-green-100 text-green-700 border-green-200 hover:bg-green-200'
|
||
}[color] || 'bg-gray-100 text-gray-700 border-gray-200 hover:bg-gray-200'
|
||
|
||
return (
|
||
<button
|
||
key={level}
|
||
onClick={(e) => {
|
||
e.stopPropagation()
|
||
handleConfidenceSelect(level)
|
||
}}
|
||
className={`confidence-button ${colorClasses} ${
|
||
isSelected ? 'selected' : ''
|
||
}`}
|
||
>
|
||
<div className="flex items-center justify-center h-8">
|
||
<span className="text-sm">{label}</span>
|
||
</div>
|
||
</button>
|
||
)
|
||
})}
|
||
</div>
|
||
|
||
{/* 提交按鈕 - 選擇後顯示 */}
|
||
{hasAnswered && (
|
||
<button
|
||
onClick={(e) => {
|
||
e.stopPropagation()
|
||
handleSubmit()
|
||
}}
|
||
className="w-full bg-blue-600 text-white py-3 px-6 rounded-lg font-semibold hover:bg-blue-700 transition-colors mt-4"
|
||
>
|
||
下一張 →
|
||
</button>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* 翻卡提示 - 只在未翻轉時顯示 */}
|
||
{!isFlipped && (
|
||
<div className="text-center text-gray-500">
|
||
<p>點擊卡片翻轉查看詳細資訊</p>
|
||
</div>
|
||
)}
|
||
|
||
</div>
|
||
)
|
||
} |