feat: 統一所有選擇題組件的選項布局和圖片功能
## 主要改動 ### 響應式選項布局統一 - VocabChoiceTest: 改為2x2網格布局,支援響應式設計 - VocabListeningTest: 添加響應式斷點 (grid-cols-1 sm:grid-cols-2) - SentenceListeningTest: 改為響應式2x2網格,移除選項標籤 ### 圖片功能完善 - SentenceListeningTest: 新增exampleImage和onImageClick支援 - 添加完整的圖片顯示區塊和點擊處理 - review-design頁面: 為SentenceListeningTest傳遞圖片屬性 ### 視覺一致性提升 - 所有選擇題組件採用相同的按鈕樣式和網格布局 - 統一文字置中對齊和font-medium字重 - 手機版自動切換為單列布局,提升觸控體驗 - 桌面版使用2x2網格,充分利用屏幕空間 ### 響應式設計 - 小屏幕 (< 640px): 選項垂直單列排列 - 中等以上屏幕 (≥ 640px): 選項2x2網格排列 - 保持所有組件一致的響應式行為 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b913d13543
commit
5a9e7f727c
|
|
@ -231,8 +231,10 @@ export default function ReviewTestsPage() {
|
|||
exampleTranslation={mockCardData.exampleTranslation}
|
||||
difficultyLevel={mockCardData.difficultyLevel}
|
||||
options={vocabChoiceOptions}
|
||||
exampleImage={mockCardData.exampleImage}
|
||||
onAnswer={handleAnswer}
|
||||
onReportError={handleReportError}
|
||||
onImageClick={handleImageClick}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ interface SentenceListeningTestProps {
|
|||
exampleTranslation: string
|
||||
difficultyLevel: string
|
||||
options: string[]
|
||||
exampleImage?: string
|
||||
onAnswer: (answer: string) => void
|
||||
onReportError: () => void
|
||||
onImageClick?: (image: string) => void
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
|
|
@ -18,8 +20,10 @@ export const SentenceListeningTest: React.FC<SentenceListeningTestProps> = ({
|
|||
exampleTranslation,
|
||||
difficultyLevel,
|
||||
options,
|
||||
exampleImage,
|
||||
onAnswer,
|
||||
onReportError,
|
||||
onImageClick,
|
||||
disabled = false
|
||||
}) => {
|
||||
const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null)
|
||||
|
|
@ -70,14 +74,29 @@ export const SentenceListeningTest: React.FC<SentenceListeningTestProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* 選項區域 - 垂直列表布局 */}
|
||||
<div className="grid grid-cols-1 gap-3 mb-6">
|
||||
{/* 圖片區(如果有) */}
|
||||
{exampleImage && (
|
||||
<div className="mb-6">
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<h3 className="font-semibold text-gray-900 mb-2 text-left">圖片提示</h3>
|
||||
<img
|
||||
src={exampleImage}
|
||||
alt="Example illustration"
|
||||
className="w-full max-w-md mx-auto rounded-lg cursor-pointer"
|
||||
onClick={() => onImageClick?.(exampleImage)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 選項區域 - 響應式網格布局 */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-6">
|
||||
{options.map((sentence, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => handleAnswerSelect(sentence)}
|
||||
disabled={disabled || showResult}
|
||||
className={`w-full p-4 text-left rounded-lg border-2 transition-all ${
|
||||
className={`p-4 text-center rounded-lg border-2 transition-all ${
|
||||
showResult
|
||||
? sentence === example
|
||||
? 'border-green-500 bg-green-50 text-green-700'
|
||||
|
|
@ -87,8 +106,7 @@ export const SentenceListeningTest: React.FC<SentenceListeningTestProps> = ({
|
|||
: 'border-gray-200 hover:border-blue-300 hover:bg-blue-50'
|
||||
}`}
|
||||
>
|
||||
<div className="text-sm text-gray-600 mb-1">選項 {String.fromCharCode(65 + idx)}:</div>
|
||||
<div className="text-base">{sentence}</div>
|
||||
<div className="text-lg font-medium">{sentence}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -72,14 +72,14 @@ export const VocabChoiceTest: React.FC<VocabChoiceTestProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* 選項區域 */}
|
||||
<div className="space-y-3 mb-6">
|
||||
{/* 選項區域 - 響應式網格布局 */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-6">
|
||||
{options.map((option, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => handleAnswerSelect(option)}
|
||||
disabled={disabled || showResult}
|
||||
className={`w-full p-4 text-left rounded-lg border-2 transition-all ${
|
||||
className={`p-4 text-center rounded-lg border-2 transition-all ${
|
||||
showResult
|
||||
? option === word
|
||||
? 'border-green-500 bg-green-50 text-green-700'
|
||||
|
|
@ -89,7 +89,7 @@ export const VocabChoiceTest: React.FC<VocabChoiceTestProps> = ({
|
|||
: 'border-gray-200 hover:border-blue-300 hover:bg-blue-50'
|
||||
}`}
|
||||
>
|
||||
{option}
|
||||
<div className="text-lg font-medium">{option}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export const VocabListeningTest: React.FC<VocabListeningTestProps> = ({
|
|||
</div>
|
||||
|
||||
{/* 選項區域 - 2x2網格布局 */}
|
||||
<div className="grid grid-cols-2 gap-3 mb-6">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-6">
|
||||
{options.map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
|
|
|
|||
Loading…
Reference in New Issue