Files
components/color-picker.tsx
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
158
Color picker.
color-picker-01
Files
components/color-picker.tsx
1'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
89
Color picker with popover.
color-picker-02
Files
components/color-picker.tsx
1'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
123
Color picker with tabs.
color-picker-03
Files
components/color-picker.tsx
1'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
Color picker with tooltip.
color-picker-04