1'use client'
2
3import React, { useState } from 'react'
4import { Plus, Trash2 } from 'lucide-react'
5
6import { Button } from '@/components/ui/button'
7import {
8 Card,
9 CardContent,
10 CardFooter,
11 CardHeader,
12 CardTitle,
13} from '@/components/ui/card'
14import { Label } from '@/components/ui/label'
15import { Slider } from '@/components/ui/slider'
16
17const ColorPicker01 = () => {
18 const [hue, setHue] = React.useState(10)
19 const [currentColor, setCurrentColor] = useState('#FF2F00')
20 const [opacity, setOpacity] = useState(100)
21 const [savedColors, setSavedColors] = useState([
22 '#FFFFFF',
23 '#E0E0E0',
24 '#BDBDBD',
25 '#9E9E9E',
26 '#757575',
27 '#616161',
28 '#424242',
29 '#BBDEFB',
30 '#90CAF9',
31 '#2196F3',
32 '#1976D2',
33 '#0D47A1',
34 ])
35
36 const handleColorChange = (e: any) => {
37 setCurrentColor(e.target.value)
38 }
39
40 const handleOpacityChange = (e: any) => {
41 setOpacity(e.target.value)
42 }
43
44 const handleDeleteColor = () => {
45 setCurrentColor('#FF0000')
46 setOpacity(100)
47 }
48
49 const handleAddNewColor = () => {
50 if (!savedColors.includes(currentColor)) {
51 setSavedColors([...savedColors, currentColor])
52 }
53 }
54
55 const handleSavedColorClick = (color: any) => {
56 setCurrentColor(color)
57 }
58
59 return (
60 <Card>
61 <CardHeader>
62 <CardTitle>Color Picker</CardTitle>
63 </CardHeader>
64 <CardContent className="w-full">
65 <div className="space-y-2">
66 <div className="mb-3 flex items-center justify-between">
67 <Label className="text-gray text-sm font-medium">
68 Choose color
69 </Label>
70 <span className="text-gray font-mono text-sm">
71 {currentColor.toUpperCase()}
72 </span>
73 </div>
74
75 <Slider
76 min={0}
77 max={360}
78 value={[hue]}
79 onValueChange={(value) => {
80 const newHue = value[0]
81 setHue(newHue)
82 const hex = hslToHex(newHue, 100, 50)
83 setCurrentColor(hex)
84 }}
85 trackColor="linear-gradient(to right, #FF0000, #FFFF00, #00FF00, #00FFFF, #0000FF, #FF00FF, #FF0000)"
86 rangeColor="transparent"
87 className="w-full"
88 />
89
90 <div className="border-border flex items-center gap-3 rounded-lg border p-3">
91 <div
92 className="border-secondary h-6 w-6 flex-shrink-0 rounded-full border-2"
93 style={{ backgroundColor: currentColor }}
94 />
95 <span className="text-gray flex-grow font-mono text-sm">
96 {currentColor.toUpperCase()}
97 </span>
98 <span className="text-gray px-2 text-sm">
99 {opacity}%
100 </span>
101 <Button variant="outline" onClick={handleDeleteColor}>
102 <Trash2 size={18} />
103 </Button>
104 </div>
105 </div>
106
107 <div>
108 <div className="my-2 flex items-center justify-between">
109 <h3 className="text-gray text-sm font-medium">
110 Saved colors
111 </h3>
112 <Button variant="outline">Edit</Button>
113 </div>
114
115 <div className="mb-4 grid grid-cols-8 gap-2">
116 {savedColors.map((color, index) => (
117 <Button
118 key={index}
119 asChild
120 onClick={() => handleSavedColorClick(color)}
121 title={color}
122 >
123 <div
124 className="h-10 w-10 cursor-pointer rounded-full border-2 border-gray-200 transition-colors hover:border-gray-400"
125 style={{
126 backgroundColor: color,
127 }}
128 />
129 </Button>
130 ))}
131 </div>
132 </div>
133 </CardContent>
134 <CardFooter className="items-center justify-center">
135 <Button variant="ghost" onClick={handleAddNewColor}>
136 <Plus size={18} />
137 Add new color
138 </Button>
139 </CardFooter>
140 </Card>
141 )
142}
143
144function hslToHex(h: any, s: any, l: any) {
145 l /= 100
146 const a = (s * Math.min(l, 1 - l)) / 100
147 const f = (n: any) => {
148 const k = (n + h / 30) % 12
149 const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)
150 return Math.round(255 * color)
151 .toString(16)
152 .padStart(2, '0')
153 }
154 return `#${f(0)}${f(8)}${f(4)}`
155}
156
157export ColorPicker01
1581'use client'
2
3import React, { useState } from 'react'
4import { Plus, Trash2 } from 'lucide-react'
5
6import { Button } from '@/components/ui/button'
7import {
8 Card,
9 CardContent,
10 CardFooter,
11 CardHeader,
12 CardTitle,
13} from '@/components/ui/card'
14import { Label } from '@/components/ui/label'
15import { Slider } from '@/components/ui/slider'
16
17const ColorPicker01 = () => {
18 const [hue, setHue] = React.useState(10)
19 const [currentColor, setCurrentColor] = useState('#FF2F00')
20 const [opacity, setOpacity] = useState(100)
21 const [savedColors, setSavedColors] = useState([
22 '#FFFFFF',
23 '#E0E0E0',
24 '#BDBDBD',
25 '#9E9E9E',
26 '#757575',
27 '#616161',
28 '#424242',
29 '#BBDEFB',
30 '#90CAF9',
31 '#2196F3',
32 '#1976D2',
33 '#0D47A1',
34 ])
35
36 const handleColorChange = (e: any) => {
37 setCurrentColor(e.target.value)
38 }
39
40 const handleOpacityChange = (e: any) => {
41 setOpacity(e.target.value)
42 }
43
44 const handleDeleteColor = () => {
45 setCurrentColor('#FF0000')
46 setOpacity(100)
47 }
48
49 const handleAddNewColor = () => {
50 if (!savedColors.includes(currentColor)) {
51 setSavedColors([...savedColors, currentColor])
52 }
53 }
54
55 const handleSavedColorClick = (color: any) => {
56 setCurrentColor(color)
57 }
58
59 return (
60 <Card>
61 <CardHeader>
62 <CardTitle>Color Picker</CardTitle>
63 </CardHeader>
64 <CardContent className="w-full">
65 <div className="space-y-2">
66 <div className="mb-3 flex items-center justify-between">
67 <Label className="text-gray text-sm font-medium">
68 Choose color
69 </Label>
70 <span className="text-gray font-mono text-sm">
71 {currentColor.toUpperCase()}
72 </span>
73 </div>
74
75 <Slider
76 min={0}
77 max={360}
78 value={[hue]}
79 onValueChange={(value) => {
80 const newHue = value[0]
81 setHue(newHue)
82 const hex = hslToHex(newHue, 100, 50)
83 setCurrentColor(hex)
84 }}
85 trackColor="linear-gradient(to right, #FF0000, #FFFF00, #00FF00, #00FFFF, #0000FF, #FF00FF, #FF0000)"
86 rangeColor="transparent"
87 className="w-full"
88 />
89
90 <div className="border-border flex items-center gap-3 rounded-lg border p-3">
91 <div
92 className="border-secondary h-6 w-6 flex-shrink-0 rounded-full border-2"
93 style={{ backgroundColor: currentColor }}
94 />
95 <span className="text-gray flex-grow font-mono text-sm">
96 {currentColor.toUpperCase()}
97 </span>
98 <span className="text-gray px-2 text-sm">
99 {opacity}%
100 </span>
101 <Button variant="outline" onClick={handleDeleteColor}>
102 <Trash2 size={18} />
103 </Button>
104 </div>
105 </div>
106
107 <div>
108 <div className="my-2 flex items-center justify-between">
109 <h3 className="text-gray text-sm font-medium">
110 Saved colors
111 </h3>
112 <Button variant="outline">Edit</Button>
113 </div>
114
115 <div className="mb-4 grid grid-cols-8 gap-2">
116 {savedColors.map((color, index) => (
117 <Button
118 key={index}
119 asChild
120 onClick={() => handleSavedColorClick(color)}
121 title={color}
122 >
123 <div
124 className="h-10 w-10 cursor-pointer rounded-full border-2 border-gray-200 transition-colors hover:border-gray-400"
125 style={{
126 backgroundColor: color,
127 }}
128 />
129 </Button>
130 ))}
131 </div>
132 </div>
133 </CardContent>
134 <CardFooter className="items-center justify-center">
135 <Button variant="ghost" onClick={handleAddNewColor}>
136 <Plus size={18} />
137 Add new color
138 </Button>
139 </CardFooter>
140 </Card>
141 )
142}
143
144function hslToHex(h: any, s: any, l: any) {
145 l /= 100
146 const a = (s * Math.min(l, 1 - l)) / 100
147 const f = (n: any) => {
148 const k = (n + h / 30) % 12
149 const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)
150 return Math.round(255 * color)
151 .toString(16)
152 .padStart(2, '0')
153 }
154 return `#${f(0)}${f(8)}${f(4)}`
155}
156
157export ColorPicker01
1581'use client'
2
3import React, { useState } from 'react'
4import { Check, X } from 'lucide-react'
5
6import { Button } from '@/components/ui/button'
7import {
8 Popover,
9 PopoverContent,
10 PopoverTrigger,
11} from '@/components/ui/popover'
12
13const themeColors = [
14 '#FFFFFF',
15 '#E0E0E0',
16 '#C8C8C8',
17 '#A0A0A0',
18 '#5C5C5C',
19 '#2C2C2C',
20 '#0078FF',
21 '#40C4FF',
22 '#7E57C2',
23 '#FFC107',
24 '#F06292',
25]
26
27const ColorPicker02 = () => {
28 const [color, setColor] = useState('#5C5C5C')
29 const [open, setOpen] = useState(false)
30
31 return (
32 <Popover open={open} onOpenChange={setOpen}>
33 <PopoverTrigger asChild>
34 <Button variant="outline" className="border shadow-sm">
35 Open Color Picker
36 </Button>
37 </PopoverTrigger>
38
39 <PopoverContent className="w-72 rounded-2xl p-0 shadow-xl">
40 <div className="flex items-center justify-between border-b px-4 py-3">
41 <h3 className="text-sm font-medium">Color picker</h3>
42 <button
43 onClick={() => setOpen(false)}
44 className="text-gray-400 hover:text-black"
45 >
46 <X className="h-4 w-4" />
47 </button>
48 </div>
49
50 <div className="px-4 py-3">
51 <div className="mb-2 flex items-center justify-between">
52 <span className="text-xs text-gray-500">
53 Theme colors
54 </span>
55 <button className="text-xs font-medium text-blue-500">
56 Edit
57 </button>
58 </div>
59
60 <div className="mb-3 grid grid-cols-6 gap-2">
61 {themeColors.map((c) => (
62 <button
63 key={c}
64 onClick={() => setColor(c)}
65 className="relative h-8 w-8 rounded-full border border-gray-200 transition-all hover:scale-105"
66 style={{ backgroundColor: c }}
67 >
68 {color === c && (
69 <div className="absolute inset-0 flex items-center justify-center">
70 <div className="flex h-5 w-5 items-center justify-center rounded-full border-2 border-white bg-black/30">
71 <Check className="h-3 w-3 text-white" />
72 </div>
73 </div>
74 )}
75 </button>
76 ))}
77 </div>
78
79 <div className="text-center font-mono text-xs text-gray-600">
80 {color.toUpperCase()}
81 </div>
82 </div>
83 </PopoverContent>
84 </Popover>
85 )
86}
87
88export ColorPicker02
891'use client'
2
3import React, { useState } from 'react'
4import { Check, X } from 'lucide-react'
5
6import { Button } from '@/components/ui/button'
7import {
8 Popover,
9 PopoverContent,
10 PopoverTrigger,
11} from '@/components/ui/popover'
12
13const themeColors = [
14 '#FFFFFF',
15 '#E0E0E0',
16 '#C8C8C8',
17 '#A0A0A0',
18 '#5C5C5C',
19 '#2C2C2C',
20 '#0078FF',
21 '#40C4FF',
22 '#7E57C2',
23 '#FFC107',
24 '#F06292',
25]
26
27const ColorPicker02 = () => {
28 const [color, setColor] = useState('#5C5C5C')
29 const [open, setOpen] = useState(false)
30
31 return (
32 <Popover open={open} onOpenChange={setOpen}>
33 <PopoverTrigger asChild>
34 <Button variant="outline" className="border shadow-sm">
35 Open Color Picker
36 </Button>
37 </PopoverTrigger>
38
39 <PopoverContent className="w-72 rounded-2xl p-0 shadow-xl">
40 <div className="flex items-center justify-between border-b px-4 py-3">
41 <h3 className="text-sm font-medium">Color picker</h3>
42 <button
43 onClick={() => setOpen(false)}
44 className="text-gray-400 hover:text-black"
45 >
46 <X className="h-4 w-4" />
47 </button>
48 </div>
49
50 <div className="px-4 py-3">
51 <div className="mb-2 flex items-center justify-between">
52 <span className="text-xs text-gray-500">
53 Theme colors
54 </span>
55 <button className="text-xs font-medium text-blue-500">
56 Edit
57 </button>
58 </div>
59
60 <div className="mb-3 grid grid-cols-6 gap-2">
61 {themeColors.map((c) => (
62 <button
63 key={c}
64 onClick={() => setColor(c)}
65 className="relative h-8 w-8 rounded-full border border-gray-200 transition-all hover:scale-105"
66 style={{ backgroundColor: c }}
67 >
68 {color === c && (
69 <div className="absolute inset-0 flex items-center justify-center">
70 <div className="flex h-5 w-5 items-center justify-center rounded-full border-2 border-white bg-black/30">
71 <Check className="h-3 w-3 text-white" />
72 </div>
73 </div>
74 )}
75 </button>
76 ))}
77 </div>
78
79 <div className="text-center font-mono text-xs text-gray-600">
80 {color.toUpperCase()}
81 </div>
82 </div>
83 </PopoverContent>
84 </Popover>
85 )
86}
87
88export ColorPicker02
891'use client'
2
3import React, { useState } from 'react'
4import { HexColorPicker } from 'react-colorful'
5
6import { Input } from '@/components/ui/input'
7import { Label } from '@/components/ui/label'
8import { Slider } from '@/components/ui/slider'
9import {
10 Tabs,
11 TabsContent,
12 TabsList,
13 TabsTrigger,
14} from '@/components/ui/tabs'
15
16function hslToHex(h: number, s: number, l: number) {
17 s /= 100
18 l /= 100
19 const k = (n: number) => (n + h / 30) % 12
20 const a = s * Math.min(l, 1 - l)
21 const f = (n: number) =>
22 Math.round(
23 255 *
24 (l -
25 a *
26 Math.max(
27 -1,
28 Math.min(k(n) - 3, Math.min(9 - k(n), 1)),
29 )),
30 )
31 return `#${[f(0), f(8), f(4)].map((x) => x.toString(16).padStart(2, '0')).join('')}`
32}
33
34const ColorPicker03 = () => {
35 const [hue, setHue] = useState(210)
36 const [hex, setHex] = useState('#4287f5')
37 const [currentColor, setCurrentColor] = useState('#FF2F00')
38
39 return (
40 <Tabs defaultValue="hex" className="w-full sm:w-80">
41 <TabsList className="grid w-full grid-cols-2">
42 <TabsTrigger value="hex">Hex Picker</TabsTrigger>
43 <TabsTrigger value="slider"> Slider Picker</TabsTrigger>
44 </TabsList>
45 <TabsContent
46 value="hex"
47 className="shadow-3xl min-h-28 space-y-3 rounded-xl bg-gray-100 p-4"
48 >
49 <div className="flex justify-center">
50 <HexColorPicker
51 color={hex}
52 onChange={setHex}
53 style={{
54 width: '100%',
55 height: '150px',
56 borderRadius: '12px',
57 boxShadow: '0 2px 6px rgba(0,0,0,0.1)',
58 }}
59 />
60 </div>
61 <div className="flex items-center justify-between">
62 <Label htmlFor="hex" className="text-xs text-gray-600">
63 Hex Value
64 </Label>
65 <Input
66 id="hex"
67 value={hex.toUpperCase()}
68 onChange={(e) => setHex(e.target.value)}
69 className="w-[100px] text-center font-mono text-sm"
70 />
71 </div>
72 <div
73 className="h-10 w-full rounded-md border shadow-inner"
74 style={{ backgroundColor: hex }}
75 />
76 </TabsContent>
77
78 <TabsContent
79 value="slider"
80 className="shadow-3xl min-h-28 space-y-3 rounded-xl bg-gray-100 p-4"
81 >
82 <div className="space-y-2">
83 <div className="mb-3 flex items-center justify-between">
84 <Label className="text-gray text-sm font-medium">
85 Choose color
86 </Label>
87 <span className="text-gray font-mono text-sm">
88 {currentColor.toUpperCase()}
89 </span>
90 </div>
91
92 <Slider
93 min={0}
94 max={360}
95 value={[hue]}
96 onValueChange={(value) => {
97 const newHue = value[0]
98 setHue(newHue)
99 const hex = hslToHex(newHue, 100, 50)
100 setCurrentColor(hex)
101 }}
102 trackColor="linear-gradient(to right, #FF0000, #FFFF00, #00FF00, #00FFFF, #0000FF, #FF00FF, #FF0000)"
103 rangeColor="transparent"
104 className="w-full"
105 />
106
107 <div className="border-border flex items-center gap-3 rounded-lg border p-3">
108 <div
109 className="border-secondary h-6 w-6 flex-shrink-0 rounded-full border-2"
110 style={{ backgroundColor: currentColor }}
111 />
112 <span className="text-gray flex-grow font-mono text-sm">
113 {currentColor.toUpperCase()}
114 </span>
115 </div>
116 </div>
117 </TabsContent>
118 </Tabs>
119 )
120}
121
122export ColorPicker03
1231'use client'
2
3import React, { useState } from 'react'
4import { HexColorPicker } from 'react-colorful'
5
6import { Input } from '@/components/ui/input'
7import { Label } from '@/components/ui/label'
8import { Slider } from '@/components/ui/slider'
9import {
10 Tabs,
11 TabsContent,
12 TabsList,
13 TabsTrigger,
14} from '@/components/ui/tabs'
15
16function hslToHex(h: number, s: number, l: number) {
17 s /= 100
18 l /= 100
19 const k = (n: number) => (n + h / 30) % 12
20 const a = s * Math.min(l, 1 - l)
21 const f = (n: number) =>
22 Math.round(
23 255 *
24 (l -
25 a *
26 Math.max(
27 -1,
28 Math.min(k(n) - 3, Math.min(9 - k(n), 1)),
29 )),
30 )
31 return `#${[f(0), f(8), f(4)].map((x) => x.toString(16).padStart(2, '0')).join('')}`
32}
33
34const ColorPicker03 = () => {
35 const [hue, setHue] = useState(210)
36 const [hex, setHex] = useState('#4287f5')
37 const [currentColor, setCurrentColor] = useState('#FF2F00')
38
39 return (
40 <Tabs defaultValue="hex" className="w-full sm:w-80">
41 <TabsList className="grid w-full grid-cols-2">
42 <TabsTrigger value="hex">Hex Picker</TabsTrigger>
43 <TabsTrigger value="slider"> Slider Picker</TabsTrigger>
44 </TabsList>
45 <TabsContent
46 value="hex"
47 className="shadow-3xl min-h-28 space-y-3 rounded-xl bg-gray-100 p-4"
48 >
49 <div className="flex justify-center">
50 <HexColorPicker
51 color={hex}
52 onChange={setHex}
53 style={{
54 width: '100%',
55 height: '150px',
56 borderRadius: '12px',
57 boxShadow: '0 2px 6px rgba(0,0,0,0.1)',
58 }}
59 />
60 </div>
61 <div className="flex items-center justify-between">
62 <Label htmlFor="hex" className="text-xs text-gray-600">
63 Hex Value
64 </Label>
65 <Input
66 id="hex"
67 value={hex.toUpperCase()}
68 onChange={(e) => setHex(e.target.value)}
69 className="w-[100px] text-center font-mono text-sm"
70 />
71 </div>
72 <div
73 className="h-10 w-full rounded-md border shadow-inner"
74 style={{ backgroundColor: hex }}
75 />
76 </TabsContent>
77
78 <TabsContent
79 value="slider"
80 className="shadow-3xl min-h-28 space-y-3 rounded-xl bg-gray-100 p-4"
81 >
82 <div className="space-y-2">
83 <div className="mb-3 flex items-center justify-between">
84 <Label className="text-gray text-sm font-medium">
85 Choose color
86 </Label>
87 <span className="text-gray font-mono text-sm">
88 {currentColor.toUpperCase()}
89 </span>
90 </div>
91
92 <Slider
93 min={0}
94 max={360}
95 value={[hue]}
96 onValueChange={(value) => {
97 const newHue = value[0]
98 setHue(newHue)
99 const hex = hslToHex(newHue, 100, 50)
100 setCurrentColor(hex)
101 }}
102 trackColor="linear-gradient(to right, #FF0000, #FFFF00, #00FF00, #00FFFF, #0000FF, #FF00FF, #FF0000)"
103 rangeColor="transparent"
104 className="w-full"
105 />
106
107 <div className="border-border flex items-center gap-3 rounded-lg border p-3">
108 <div
109 className="border-secondary h-6 w-6 flex-shrink-0 rounded-full border-2"
110 style={{ backgroundColor: currentColor }}
111 />
112 <span className="text-gray flex-grow font-mono text-sm">
113 {currentColor.toUpperCase()}
114 </span>
115 </div>
116 </div>
117 </TabsContent>
118 </Tabs>
119 )
120}
121
122export ColorPicker03
1231'use client'
2
3import React, { useState } from 'react'
4
5import { Button } from '@/components/ui/button'
6import { Slider } from '@/components/ui/slider'
7import {
8 Tooltip,
9 TooltipContent,
10 TooltipProvider,
11 TooltipTrigger,
12} from '@/components/ui/tooltip'
13
14const ColorPicker04 = () => {
15 const [activeIndex, setActiveIndex] = useState<number | null>(null)
16 const [savedColors, setSavedColors] = useState([
17 '#DDFF00',
18 '#FF5900',
19 '#00FFFF',
20 '#9D00FF',
21 '#90CAF9',
22 ])
23
24 const hslToHex = (h: number, s: number, l: number) => {
25 l /= 100
26 const a = (s * Math.min(l, 1 - l)) / 100
27 const f = (n: number) => {
28 const k = (n + h / 30) % 12
29 const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)
30 return Math.round(255 * color)
31 .toString(16)
32 .padStart(2, '0')
33 }
34 return `#${f(0)}${f(8)}${f(4)}`
35 }
36
37 return (
38 <TooltipProvider>
39 <div className="flex items-center justify-center p-10">
40 <div className="flex items-center gap-5">
41 <div className="flex flex-col items-center gap-3">
42 {savedColors.map((color, index) => {
43 const { h } = hexToHsl(color)
44 return (
45 <Tooltip
46 key={index}
47 open={activeIndex === index}
48 onOpenChange={(open) =>
49 setActiveIndex(open ? index : null)
50 }
51 >
52 <TooltipTrigger asChild>
53 <Button
54 asChild
55 onClick={() =>
56 setActiveIndex(
57 activeIndex === index
58 ? null
59 : index,
60 )
61 }
62 >
63 <div
64 className={`h-6 w-6 rounded-md border-2 transition-all ${
65 activeIndex === index
66 ? 'border-gray ring-2 ring-black'
67 : 'border-transparent'
68 }`}
69 style={{
70 backgroundColor: color,
71 }}
72 />
73 </Button>
74 </TooltipTrigger>
75
76 <TooltipContent
77 side="right"
78 align="center"
79 className="shadow-gray rounded-xl bg-white px-4 py-3 shadow-lg"
80 >
81 <div className="flex w-60 items-center gap-3">
82 <div
83 className="h-5 w-5 rounded-full border border-gray-300 shadow-sm"
84 style={{
85 backgroundColor: color,
86 }}
87 />
88 <Slider
89 min={0}
90 max={360}
91 value={[h]}
92 onValueChange={(value) => {
93 const newHue = value[0]
94 const newHex = hslToHex(
95 newHue,
96 100,
97 50,
98 )
99 const updated = [
100 ...savedColors,
101 ]
102 updated[index] = newHex
103 setSavedColors(updated)
104 }}
105 trackColor="linear-gradient(to right, red, yellow, lime, cyan, blue, magenta, red)"
106 rangeColor="transparent"
107 className="flex-1"
108 />
109 </div>
110 </TooltipContent>
111 </Tooltip>
112 )
113 })}
114 </div>
115 </div>
116 </div>
117 </TooltipProvider>
118 )
119}
120
121function hslToHex(h: number, s: number, l: number) {
122 l /= 100
123 const a = (s * Math.min(l, 1 - l)) / 100
124 const f = (n: number) => {
125 const k = (n + h / 30) % 12
126 const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)
127 return Math.round(255 * color)
128 .toString(16)
129 .padStart(2, '0')
130 }
131 return `#${f(0)}${f(8)}${f(4)}`
132}
133
134// Convert HEX → HSL (needed to set slider position)
135function hexToHsl(hex: string) {
136 hex = hex.replace(/^#/, '')
137 const r = parseInt(hex.slice(0, 2), 16) / 255
138 const g = parseInt(hex.slice(2, 4), 16) / 255
139 const b = parseInt(hex.slice(4, 6), 16) / 255
140 const max = Math.max(r, g, b)
141 const min = Math.min(r, g, b)
142 let h = 0,
143 s = 0,
144 l = (max + min) / 2
145
146 if (max !== min) {
147 const d = max - min
148 s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
149 switch (max) {
150 case r:
151 h = (g - b) / d + (g < b ? 6 : 0)
152 break
153 case g:
154 h = (b - r) / d + 2
155 break
156 case b:
157 h = (r - g) / d + 4
158 break
159 }
160 h *= 60
161 }
162
163 return { h, s: s * 100, l: l * 100 }
164}
165
166export ColorPicker04
1671'use client'
2
3import React, { useState } from 'react'
4
5import { Button } from '@/components/ui/button'
6import { Slider } from '@/components/ui/slider'
7import {
8 Tooltip,
9 TooltipContent,
10 TooltipProvider,
11 TooltipTrigger,
12} from '@/components/ui/tooltip'
13
14const ColorPicker04 = () => {
15 const [activeIndex, setActiveIndex] = useState<number | null>(null)
16 const [savedColors, setSavedColors] = useState([
17 '#DDFF00',
18 '#FF5900',
19 '#00FFFF',
20 '#9D00FF',
21 '#90CAF9',
22 ])
23
24 const hslToHex = (h: number, s: number, l: number) => {
25 l /= 100
26 const a = (s * Math.min(l, 1 - l)) / 100
27 const f = (n: number) => {
28 const k = (n + h / 30) % 12
29 const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)
30 return Math.round(255 * color)
31 .toString(16)
32 .padStart(2, '0')
33 }
34 return `#${f(0)}${f(8)}${f(4)}`
35 }
36
37 return (
38 <TooltipProvider>
39 <div className="flex items-center justify-center p-10">
40 <div className="flex items-center gap-5">
41 <div className="flex flex-col items-center gap-3">
42 {savedColors.map((color, index) => {
43 const { h } = hexToHsl(color)
44 return (
45 <Tooltip
46 key={index}
47 open={activeIndex === index}
48 onOpenChange={(open) =>
49 setActiveIndex(open ? index : null)
50 }
51 >
52 <TooltipTrigger asChild>
53 <Button
54 asChild
55 onClick={() =>
56 setActiveIndex(
57 activeIndex === index
58 ? null
59 : index,
60 )
61 }
62 >
63 <div
64 className={`h-6 w-6 rounded-md border-2 transition-all ${
65 activeIndex === index
66 ? 'border-gray ring-2 ring-black'
67 : 'border-transparent'
68 }`}
69 style={{
70 backgroundColor: color,
71 }}
72 />
73 </Button>
74 </TooltipTrigger>
75
76 <TooltipContent
77 side="right"
78 align="center"
79 className="shadow-gray rounded-xl bg-white px-4 py-3 shadow-lg"
80 >
81 <div className="flex w-60 items-center gap-3">
82 <div
83 className="h-5 w-5 rounded-full border border-gray-300 shadow-sm"
84 style={{
85 backgroundColor: color,
86 }}
87 />
88 <Slider
89 min={0}
90 max={360}
91 value={[h]}
92 onValueChange={(value) => {
93 const newHue = value[0]
94 const newHex = hslToHex(
95 newHue,
96 100,
97 50,
98 )
99 const updated = [
100 ...savedColors,
101 ]
102 updated[index] = newHex
103 setSavedColors(updated)
104 }}
105 trackColor="linear-gradient(to right, red, yellow, lime, cyan, blue, magenta, red)"
106 rangeColor="transparent"
107 className="flex-1"
108 />
109 </div>
110 </TooltipContent>
111 </Tooltip>
112 )
113 })}
114 </div>
115 </div>
116 </div>
117 </TooltipProvider>
118 )
119}
120
121function hslToHex(h: number, s: number, l: number) {
122 l /= 100
123 const a = (s * Math.min(l, 1 - l)) / 100
124 const f = (n: number) => {
125 const k = (n + h / 30) % 12
126 const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)
127 return Math.round(255 * color)
128 .toString(16)
129 .padStart(2, '0')
130 }
131 return `#${f(0)}${f(8)}${f(4)}`
132}
133
134// Convert HEX → HSL (needed to set slider position)
135function hexToHsl(hex: string) {
136 hex = hex.replace(/^#/, '')
137 const r = parseInt(hex.slice(0, 2), 16) / 255
138 const g = parseInt(hex.slice(2, 4), 16) / 255
139 const b = parseInt(hex.slice(4, 6), 16) / 255
140 const max = Math.max(r, g, b)
141 const min = Math.min(r, g, b)
142 let h = 0,
143 s = 0,
144 l = (max + min) / 2
145
146 if (max !== min) {
147 const d = max - min
148 s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
149 switch (max) {
150 case r:
151 h = (g - b) / d + (g < b ? 6 : 0)
152 break
153 case g:
154 h = (b - r) / d + 2
155 break
156 case b:
157 h = (r - g) / d + 4
158 break
159 }
160 h *= 60
161 }
162
163 return { h, s: s * 100, l: l * 100 }
164}
165
166export ColorPicker04
167