diff --git a/config/docs.ts b/config/docs.ts index c18345829..2f0469d1f 100644 --- a/config/docs.ts +++ b/config/docs.ts @@ -246,6 +246,12 @@ export const docsConfig: DocsConfig = { items: [], label: "", }, + { + title: "Glow", + href: `/docs/components/glow`, + items: [], + label: "New", + }, ], }, { diff --git a/content/docs/components/glow.mdx b/content/docs/components/glow.mdx new file mode 100644 index 000000000..2e54db784 --- /dev/null +++ b/content/docs/components/glow.mdx @@ -0,0 +1,77 @@ +--- +title: Glow Component +date: 2025-04-20 +description: A beautiful glow effect that appears on hover interactions +author: Syeda Hoorain Ali +published: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn@latest add "https://magicui.design/r/glow" +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + +Update `global.css` + +Add the following lines to your `global.css` file: + +```css title="app/global.css" {5-7} +@tailwind base; +@tailwind components; +@tailwind utilities; + +@theme inline { + --radius-inherit: inherit; +} +``` + + + + + + + +## Props + +### GlowArea + +| Prop | Type | Default | Description | +| ----------- | ----------- | ------- | --------------------------------------------- | +| `className` | `string` | `-` | The class name to be applied to the component | +| `children` | `ReactNode` | `-` | Children elements | +| `size` | `number` | `50` | The size of the glow area | + +### Glow + +| Prop | Type | Default | Description | +| ----------- | ----------- | -------- | --------------------------------------------- | +| `className` | `string` | `-` | The class name to be applied to the component | +| `children` | `ReactNode` | `-` | Children elements | +| `color` | `string` | `purple` | The color of the glow | + +## Credits + +- Credit to [@Syeda Hoorain Ali](https://github.com/syeda-hoorain-ali/) diff --git a/registry/example/glow-demo.tsx b/registry/example/glow-demo.tsx new file mode 100644 index 000000000..80cf4b2e1 --- /dev/null +++ b/registry/example/glow-demo.tsx @@ -0,0 +1,22 @@ +import { Card } from "@/components/ui/card"; +import { GlowArea, Glow } from "@/registry/magicui/glow"; + +export default function GlowDemo() { + return ( + + + Hover + + + + Me + + + ); +} diff --git a/registry/magicui/glow.tsx b/registry/magicui/glow.tsx new file mode 100644 index 000000000..6c4898847 --- /dev/null +++ b/registry/magicui/glow.tsx @@ -0,0 +1,128 @@ +"use client"; + +import { + ComponentPropsWithoutRef, + CSSProperties, + MouseEvent, + useEffect, + useRef, +} from "react"; + +import { cn } from "@/lib/utils"; + +interface GlowAreaProps extends ComponentPropsWithoutRef<"div"> { + /** + * @default 50 + * @type number + * @description + * The size of the glow area + * */ + size?: number; +} + +export const GlowArea: React.FC = (props) => { + const { className, size = 50, ...rest } = props; + const element = useRef(null); + const latestCoords = useRef<{ x: number; y: number } | null>(null); + const frameId = useRef(null); + + const animateGlow = () => { + if (latestCoords.current && element.current) { + element.current.style.setProperty( + "--glow-x", + `${latestCoords.current.x}px`, + ); + element.current.style.setProperty( + "--glow-y", + `${latestCoords.current.y}px`, + ); + + frameId.current = null; + } + }; + + const handleMouseMove = (e: MouseEvent) => { + const bounds = e.currentTarget.getBoundingClientRect(); + latestCoords.current = { + x: e.clientX - bounds.left, + y: e.clientY - bounds.top, + }; + console.log(latestCoords.current); + + if (!frameId.current) { + frameId.current = requestAnimationFrame(() => animateGlow()); + } + }; + + const handleMouseLeave = (e: MouseEvent) => { + e.currentTarget.style.removeProperty("--glow-x"); + e.currentTarget.style.removeProperty("--glow-y"); + }; + + return ( +
+ ); +}; + +GlowArea.displayName = "GlowArea"; + +interface GlowProps extends ComponentPropsWithoutRef<"div"> { + /** + * @default "purple" + * @type string + * @description + * The color of the glow + * */ + color?: string; +} + +export const Glow: React.FC = (props) => { + const { className, color = "purple", children, ...rest } = props; + + const element = useRef(null); + + useEffect(() => { + element.current?.style.setProperty( + "--glow-top", + `${element.current.offsetTop}px`, + ); + element.current?.style.setProperty( + "--glow-left", + `${element.current.offsetLeft}px`, + ); + }, []); + + return ( +
+
+ {children} +
+ ); +}; + +Glow.displayName = "Glow"; diff --git a/registry/registry-examples.ts b/registry/registry-examples.ts index ee7ed90f6..d8cced0a2 100644 --- a/registry/registry-examples.ts +++ b/registry/registry-examples.ts @@ -1710,4 +1710,19 @@ export const examples: Registry["items"] = [ }, ], }, + { + name: "glow-demo", + type: "registry:example", + title: "Glow Demo", + description: + "Example showing a beautiful glow effect that appears when hovering over elements.", + registryDependencies: ["https://magicui.design/r/glow"], + files: [ + { + path: "registry/example/glow-demo.tsx", + type: "registry:example", + // target: "components/glow-demo.tsx", + }, + ], + }, ]; diff --git a/registry/registry-ui.ts b/registry/registry-ui.ts index 680792ced..beb6a73ed 100644 --- a/registry/registry-ui.ts +++ b/registry/registry-ui.ts @@ -1174,4 +1174,18 @@ export const ui: Registry["items"] = [ }, ], }, + { + name: "glow", + type: "registry:ui", + title: "Glow", + description: + "A beautiful glow effect that appears when hovering over elements", + files: [ + { + path: "registry/magicui/glow.tsx", + type: "registry:ui", + target: "components/magicui/glow.tsx", + }, + ], + }, ]; diff --git a/styles/globals.css b/styles/globals.css index fa457342c..0a50bce24 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -521,3 +521,7 @@ .steps > h3 { @apply mt-8 mb-4 text-base font-semibold; } + +@theme inline { + --radius-inherit: inherit; +}