91 lines
2.8 KiB
TypeScript
91 lines
2.8 KiB
TypeScript
'use client'
|
|
|
|
import { getMasteryLevelInfo } from '@/lib/utils/masteryCalculator'
|
|
|
|
interface MasteryIndicatorProps {
|
|
level: number; // 0-100
|
|
isDecaying?: boolean; // 是否正在衰減
|
|
showPercentage?: boolean; // 是否顯示百分比數字
|
|
size?: 'small' | 'medium' | 'large';
|
|
baseMasteryLevel?: number; // 基礎熟悉度,用於判斷是否衰減
|
|
}
|
|
|
|
export const MasteryIndicator: React.FC<MasteryIndicatorProps> = ({
|
|
level,
|
|
isDecaying = false,
|
|
showPercentage = true,
|
|
size = 'medium',
|
|
baseMasteryLevel
|
|
}) => {
|
|
// 自動判斷是否衰減
|
|
const actualIsDecaying = isDecaying || (baseMasteryLevel !== undefined && level < baseMasteryLevel);
|
|
|
|
const { label, color, bgColor } = getMasteryLevelInfo(level);
|
|
|
|
const getColor = (level: number, isDecaying: boolean) => {
|
|
if (isDecaying) return '#ff9500'; // 橙色表示衰減中
|
|
if (level >= 80) return '#34c759'; // 綠色表示熟悉
|
|
if (level >= 60) return '#007aff'; // 藍色表示良好
|
|
if (level >= 40) return '#ff9500'; // 橙色表示一般
|
|
return '#ff3b30'; // 紅色表示需要加強
|
|
};
|
|
|
|
const sizeClasses = {
|
|
small: 'w-8 h-8',
|
|
medium: 'w-12 h-12',
|
|
large: 'w-16 h-16'
|
|
};
|
|
|
|
const textSizes = {
|
|
small: 'text-xs',
|
|
medium: 'text-sm',
|
|
large: 'text-base'
|
|
};
|
|
|
|
return (
|
|
<div className={`mastery-indicator ${size} flex items-center gap-3`}>
|
|
<div className={`progress-circle relative ${sizeClasses[size]}`}>
|
|
<svg viewBox="0 0 36 36" className="w-full h-full transform -rotate-90">
|
|
{/* 背景圓圈 */}
|
|
<circle
|
|
cx="18" cy="18" r="15.915"
|
|
fill="transparent"
|
|
stroke="#e5e5e7"
|
|
strokeWidth="2"
|
|
/>
|
|
{/* 進度圓圈 */}
|
|
<circle
|
|
cx="18" cy="18" r="15.915"
|
|
fill="transparent"
|
|
stroke={getColor(level, actualIsDecaying)}
|
|
strokeWidth="2"
|
|
strokeDasharray={`${level} 100`}
|
|
className="transition-all duration-500 ease-out"
|
|
/>
|
|
</svg>
|
|
|
|
{showPercentage && (
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<div className={`text-center ${textSizes[size]}`}>
|
|
<div className="font-bold text-gray-900">{level}%</div>
|
|
{actualIsDecaying && (
|
|
<div className="text-orange-500 text-xs animate-pulse">↓</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex flex-col">
|
|
<div className={`${bgColor} ${color} px-2 py-1 rounded-full text-xs font-medium`}>
|
|
{label}
|
|
</div>
|
|
{actualIsDecaying && (
|
|
<div className="text-xs text-orange-600 mt-1">記憶衰減中</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default MasteryIndicator |