-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCustomToggle.jsx
More file actions
126 lines (119 loc) · 4.11 KB
/
CustomToggle.jsx
File metadata and controls
126 lines (119 loc) · 4.11 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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import React from 'react';
import { motion } from 'framer-motion';
import { Check, X } from '@phosphor-icons/react';
const CustomToggle = ({
id,
checked,
onChange,
label,
disabled,
colorTheme = 'rose',
fontClass = '',
labelColorClass = 'text-gray-300',
hoverColorClass = 'group-hover:text-white',
}) => {
const themes = {
rose: {
track:
'bg-rose-500/20 border-rose-500/50 shadow-[0_0_15px_rgba(244,63,94,0.2)]',
knob: 'bg-rose-500 border-rose-400 shadow-[0_0_10px_rgba(244,63,94,0.4)]',
},
blue: {
track:
'bg-blue-500/20 border-blue-500/50 shadow-[0_0_15px_rgba(59,130,246,0.2)]',
knob: 'bg-blue-500 border-blue-400 shadow-[0_0_10px_rgba(59,130,246,0.4)]',
},
green: {
track:
'bg-emerald-500/20 border-emerald-500/50 shadow-[0_0_15px_rgba(16,185,129,0.2)]',
knob: 'bg-emerald-500 border-emerald-400 shadow-[0_0_10px_rgba(16,185,129,0.4)]',
},
amber: {
track:
'bg-amber-500/20 border-amber-500/50 shadow-[0_0_15px_rgba(245,158,11,0.2)]',
knob: 'bg-amber-500 border-amber-400 shadow-[0_0_10px_rgba(245,158,11,0.4)]',
},
purple: {
track:
'bg-purple-500/20 border-purple-500/50 shadow-[0_0_15px_rgba(168,85,247,0.2)]',
knob: 'bg-purple-500 border-purple-400 shadow-[0_0_10px_rgba(168,85,247,0.4)]',
},
cyan: {
track:
'bg-cyan-500/20 border-cyan-500/50 shadow-[0_0_15px_rgba(6,182,212,0.2)]',
knob: 'bg-cyan-500 border-cyan-400 shadow-[0_0_10px_rgba(6,182,212,0.4)]',
},
indigo: {
track:
'bg-indigo-500/20 border-indigo-500/50 shadow-[0_0_15px_rgba(99,102,241,0.2)]',
knob: 'bg-indigo-500 border-indigo-400 shadow-[0_0_10px_rgba(99,102,241,0.4)]',
},
};
const activeTheme = themes[colorTheme] || themes.rose;
return (
<div
className={`flex items-center justify-between w-full group py-2 gap-4 ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}
onClick={() => !disabled && onChange({ target: { checked: !checked } })}
>
<label
htmlFor={id}
className={`text-base sm:text-lg font-medium cursor-pointer select-none transition-colors duration-300 ${labelColorClass} ${hoverColorClass} ${fontClass}`}
onClick={(e) => e.stopPropagation()} // Prevent double toggle if label is clicked directly (though container click handles it)
>
{label}
</label>
<div className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
id={id}
className="sr-only"
checked={checked}
onChange={onChange}
disabled={disabled}
/>
{/* Track */}
<div
className={`
w-14 h-8 rounded-full transition-all duration-300 ease-out
border border-transparent shadow-inner relative overflow-hidden
${
checked
? activeTheme.track
: 'bg-gray-900/50 border-white/10 hover:border-white/20'
}
`}
>
{/* Background sheen effect */}
<div
className={`absolute inset-0 bg-gradient-to-r from-transparent via-white/5 to-transparent -skew-x-12 translate-x-[-100%] transition-transform duration-1000 ${checked ? 'group-hover:translate-x-[100%]' : ''}`}
/>
</div>
{/* Knob */}
<motion.div
className={`
absolute top-1 left-1 w-6 h-6 rounded-full shadow-lg
flex items-center justify-center
backdrop-blur-sm border
${checked ? activeTheme.knob : 'bg-gray-700 border-gray-600'}
`}
animate={{
x: checked ? 24 : 0,
rotate: checked ? 360 : 0,
}}
transition={{
type: 'spring',
stiffness: 500,
damping: 30,
}}
>
{checked ? (
<Check size={12} weight="bold" className="text-white" />
) : (
<X size={12} weight="bold" className="text-gray-400" />
)}
</motion.div>
</div>
</div>
);
};
export default CustomToggle;