-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathPasswordStrengthIndicator.tsx
More file actions
85 lines (78 loc) · 2.42 KB
/
PasswordStrengthIndicator.tsx
File metadata and controls
85 lines (78 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import React from 'react'
import { motion } from 'framer-motion'
import { checkPasswordStrength } from '@/lib/security'
import { useTheme } from '@/context/ThemeContext'
interface PasswordStrengthProps {
password: string
}
export function PasswordStrengthIndicator({ password }: PasswordStrengthProps) {
const { theme } = useTheme()
const strength = checkPasswordStrength(password)
if (!password) return null
const strengthLabels = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong']
const strengthColors = [
'bg-red-500',
'bg-orange-500',
'bg-yellow-500',
'bg-blue-500',
'bg-green-500',
]
return (
<div className="mt-2 space-y-2">
{/* Strength Bar */}
<div className="flex gap-1">
{[0, 1, 2, 3, 4].map((index) => (
<motion.div
key={index}
initial={{ scaleX: 0 }}
animate={{ scaleX: index <= strength.score ? 1 : 0 }}
transition={{ duration: 0.3, delay: index * 0.05 }}
className={`h-1 flex-1 rounded-full ${
index <= strength.score
? strengthColors[strength.score]
: theme === 'dark'
? 'bg-neutral-700'
: 'bg-neutral-300'
}`}
/>
))}
</div>
{/* Strength Label */}
<div className="flex items-center justify-between text-xs">
<span
className={
strength.score <= 1
? 'text-red-500'
: strength.score <= 2
? 'text-yellow-500'
: strength.score <= 3
? 'text-blue-500'
: 'text-green-500'
}
>
{strengthLabels[strength.score]}
</span>
<span className={theme === 'dark' ? 'text-neutral-500' : 'text-neutral-400'}>
{password.length}/25
</span>
</div>
{/* Feedback */}
{strength.feedback.length > 0 && (
<motion.ul
initial={{ opacity: 0, y: -5 }}
animate={{ opacity: 1, y: 0 }}
className={`text-xs space-y-1 ${
theme === 'dark' ? 'text-neutral-400' : 'text-neutral-600'
}`}
>
{strength.feedback.map((item, index) => (
<li key={index} className="flex items-start gap-1">
<span className="text-red-500 mt-0.5">•</span>
<span>{item}</span>
</li>
))}
</motion.ul>
)}
</div>
)
}