cult-ui
Display
Animation

shader-lens-blur

blur go brr.

animated
effect
form
gradient
hover
list
motion
positioning
text
transition

Source Code

Files
demo
1"use client"
2 
3import React, { useCallback } from "react"
4import { useAtom } from "jotai"
5import { Circle, CircleOff, Sliders, Square, Triangle } from "lucide-react"
6import { motion } from "motion/react"
7 
8import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
9import { Label } from "@/components/ui/label"
10import {
11  Popover,
12  PopoverContent,
13  PopoverTrigger,
14} from "@/components/ui/popover"
15import {
16  Select,
17  SelectContent,
18  SelectItem,
19  SelectTrigger,
20  SelectValue,
21} from "@/components/ui/select"
22import { Separator } from "@/components/ui/separator"
23import { Slider } from "@/components/ui/slider"
24import { Switch } from "@/components/ui/switch"
25 
26import ColorPicker from "../ui/color-picker"
27import ShaderLensBlur, { configAtom } from "../ui/shader-lens-blur"
28 
29function ShaderLensBlurDemo() {
30  return (
31    <div className="grid grid-cols-1  gap-8   ">
32      <ShaderLensBlur />
33      <ShaderBlurConfig />
34    </div>
35  )
36}
37 
38function ShaderBlurConfig() {
39  const [config, setConfig] = useAtom(configAtom)
40 
41  const handleVariationChange = useCallback(
42    (value: string) => {
43      setConfig((prev) => ({ ...prev, variation: parseInt(value) }))
44    },
45    [setConfig]
46  )
47 
48  const handleColorChange = useCallback(
49    (key: "color1" | "color2" | "color3" | "color4", value: string) => {
50      setConfig((prev) => ({ ...prev, [key]: value }))
51    },
52    [setConfig]
53  )
54 
55  const handleDimensionChange = useCallback(
56    (key: "width" | "height", value: number) => {
57      setConfig((prev) => ({ ...prev, [key]: value }))
58    },
59    [setConfig]
60  )
61 
62  const variationIcons = [
63    { icon: Square, label: "Square" },
64    { icon: Circle, label: "Solid Circle" },
65    { icon: CircleOff, label: "Hollow Circle" },
66    { icon: Triangle, label: "Triangle" },
67  ]
68 
69  return (
70    <Card className="bg-black text-white border-neutral-800 to-bg-primary/100 bg-gradient-to-b from-primary/90 dark:from-card/100 dark:to-card/90">
71      <CardHeader className="border-b border-neutral-800">
72        <CardTitle className="text-xl font-bold flex items-center">
73          <Sliders className="w-5 h-5 mr-2" />
74          Shader Configuration
75        </CardTitle>
76      </CardHeader>
77      <CardContent className="space-y-6 p-6">
78        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
79          <div className="space-y-6">
80            <div className="space-y-4">
81              <Label
82                htmlFor="variation"
83                className="text-sm font-medium text-neutral-400"
84              >
85                Variation
86              </Label>
87              <Select
88                value={config.variation.toString()}
89                onValueChange={handleVariationChange}
90              >
91                <SelectTrigger
92                  id="variation"
93                  className="w-full bg-neutral-900 border-neutral-700 text-white"
94                >
95                  <SelectValue placeholder="Select variation" />
96                </SelectTrigger>
97                <SelectContent className="bg-neutral-900 border-neutral-700 text-white">
98                  {variationIcons.map((variation, index) => (
99                    <SelectItem
100                      key={index}
101                      value={index.toString()}
102                      className="hover:bg-neutral-800"
103                    >
104                      <div className="flex items-center space-x-2">
105                        <variation.icon className="w-5 h-5" />
106                        <span>- {variation.label}</span>
107                      </div>
108                    </SelectItem>
109                  ))}
110                </SelectContent>
111              </Select>
112            </div>
113 
114            <Separator className="bg-neutral-800" />
115 
116            <div className="space-y-4">
117              <h3 className="text-lg font-semibold text-neutral-300">Colors</h3>
118              <div className="grid grid-cols-2 gap-4">
119                {(["color1", "color2", "color3", "color4"] as const).map(
120                  (color) => (
121                    <div key={color} className="space-y-2">
122                      <Label
123                        htmlFor={color}
124                        className="text-sm font-medium text-neutral-400 block"
125                      >
126                        {color}
127                      </Label>
128                      <Popover>
129                        <PopoverTrigger asChild>
130                          <motion.button
131                            whileHover={{ scale: 1.05 }}
132                            whileTap={{ scale: 0.95 }}
133                            className="w-full h-10 rounded-md border-2 border-neutral-700 focus:border-blue-500 focus:outline-none"
134                            style={{ backgroundColor: config[color] }}
135                          />
136                        </PopoverTrigger>
137                        <PopoverContent className="w-64 p-3 border-neutral-700">
138                          <ColorPicker
139                            color={config[color]}
140                            onChange={(value) =>
141                              handleColorChange(color, value)
142                            }
143                          />
144                        </PopoverContent>
145                      </Popover>
146                    </div>
147                  )
148                )}
149              </div>
150            </div>
151          </div>
152 
153          <div className="space-y-6">
154            <div className="space-y-4">
155              <h3 className="text-lg font-semibold text-neutral-300">
156                Options
157              </h3>
158              <div className="flex flex-col space-y-4">
159                <div className="flex items-center justify-between">
160                  <Label
161                    htmlFor="enableHover"
162                    className="text-sm font-medium text-neutral-400"
163                  >
164                    Enable Hover
165                  </Label>
166                  <Switch
167                    id="enableHover"
168                    checked={config.enableHover}
169                    onCheckedChange={(checked) =>
170                      setConfig((prev) => ({ ...prev, enableHover: checked }))
171                    }
172                    className="data-[state=checked]:bg-blue-500"
173                  />
174                </div>
175                <div className="flex items-center justify-between">
176                  <Label
177                    htmlFor="invertMouse"
178                    className="text-sm font-medium text-neutral-400"
179                  >
180                    Invert Mouse
181                  </Label>
182                  <Switch
183                    id="invertMouse"
184                    checked={config.invertMouse}
185                    onCheckedChange={(checked) =>
186                      setConfig((prev) => ({ ...prev, invertMouse: checked }))
187                    }
188                    className="data-[state=checked]:bg-blue-500"
189                  />
190                </div>
191              </div>
192            </div>
193 
194            <Separator className="bg-neutral-800" />
195 
196            <div className="space-y-4">
197              <h3 className="text-lg font-semibold text-neutral-300">
198                Dimensions
199              </h3>
200              <div className="space-y-6">
201                <div className="space-y-2">
202                  <div className="flex items-center justify-between">
203                    <Label
204                      htmlFor="width"
205                      className="text-sm font-medium text-neutral-400"
206                    >
207                      Width
208                    </Label>
209                    <span className="text-sm text-neutral-400">
210                      {config.width}px
211                    </span>
212                  </div>
213                  <Slider
214                    id="width"
215                    min={100}
216                    max={1000}
217                    step={10}
218                    value={[parseInt(config.width.toString())]}
219                    onValueChange={([value]) =>
220                      handleDimensionChange("width", value)
221                    }
222                    className="[&_[role=slider]]:bg-blue-500"
223                  />
224                </div>
225                <div className="space-y-2">
226                  <div className="flex items-center justify-between">
227                    <Label
228                      htmlFor="height"
229                      className="text-sm font-medium text-neutral-400"
230                    >
231                      Height
232                    </Label>
233                    <span className="text-sm text-neutral-400">
234                      {config.height}px
235                    </span>
236                  </div>
237                  <Slider
238                    id="height"
239                    min={100}
240                    max={1000}
241                    step={10}
242                    value={[parseInt(config.height.toString())]}
243                    onValueChange={([value]) =>
244                      handleDimensionChange("height", value)
245                    }
246                    className="[&_[role=slider]]:bg-blue-500"
247                  />
248                </div>
249              </div>
250            </div>
251          </div>
252        </div>
253      </CardContent>
254    </Card>
255  )
256}
257export ShaderLensBlurDemo