Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 59 additions & 21 deletions apps/www/public/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9298,8 +9298,13 @@ Description: A spotlight effect that follows your mouse cursor and highlights bo
--- file: magicui/magic-card.tsx ---
"use client"

import React, { useCallback, useEffect } from "react"
import { motion, useMotionTemplate, useMotionValue } from "motion/react"
import React, { useCallback, useEffect, useRef } from "react"
import {
animate,
motion,
useMotionTemplate,
useMotionValue,
} from "motion/react"

import { cn } from "@/lib/utils"

Expand All @@ -9322,11 +9327,43 @@ export function MagicCard({
gradientFrom = "#9E7AFF",
gradientTo = "#FE8BBB",
}: MagicCardProps) {
const ref = useRef<HTMLDivElement>(null)

const mouseX = useMotionValue(-gradientSize)
const mouseY = useMotionValue(-gradientSize)

const reset = useCallback(() => {
mouseX.set(-gradientSize)
mouseY.set(-gradientSize)
if (!ref.current) return
const rect = ref.current.getBoundingClientRect()
const x = mouseX.get()
const y = mouseY.get()

const distances = {
left: x,
right: rect.width - x,
top: y,
bottom: rect.height - y,
}

const closestEdge = Object.entries(distances).reduce(
(closest, [edge, distance]) =>
distance < closest.distance ? { edge, distance } : closest,
{ edge: "left", distance: distances.left }
).edge

switch (closestEdge) {
case "left":
return animate(mouseX, -gradientSize)
case "right":
return animate(mouseX, rect.width + gradientSize)
case "top":
return animate(mouseY, -gradientSize)
case "bottom":
return animate(mouseY, rect.height + gradientSize)
default:
animate(mouseX, -gradientSize)
animate(mouseY, -gradientSize)
}
}, [gradientSize, mouseX, mouseY])

const handlePointerMove = useCallback(
Expand Down Expand Up @@ -9367,27 +9404,28 @@ export function MagicCard({
}, [reset])

return (
<div
className={cn("group relative rounded-[inherit]", className)}
<motion.div
ref={ref}
className={cn(
"group relative overflow-hidden rounded-[inherit] border border-transparent",
className
)}
onPointerMove={handlePointerMove}
onPointerLeave={reset}
onPointerEnter={reset}
>
<motion.div
className="bg-border pointer-events-none absolute inset-0 rounded-[inherit] duration-300 group-hover:opacity-100"
style={{
background: useMotionTemplate`
radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px,
style={{
background: useMotionTemplate`
linear-gradient(var(--color-background) 0 0) padding-box,
radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px,
${gradientFrom},
${gradientTo},
var(--border) 100%
)
`,
}}
/>
<div className="bg-background absolute inset-px rounded-[inherit]" />
${gradientTo},
var(--color-border) 100%
) border-box
`,
}}
>
<motion.div
className="pointer-events-none absolute inset-px rounded-[inherit] opacity-0 transition-opacity duration-300 group-hover:opacity-100"
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100"
style={{
background: useMotionTemplate`
radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px, ${gradientColor}, transparent 100%)
Expand All @@ -9396,7 +9434,7 @@ export function MagicCard({
}}
/>
<div className="relative">{children}</div>
</div>
</motion.div>
)
}

Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/r/magic-card.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"files": [
{
"path": "registry/magicui/magic-card.tsx",
"content": "\"use client\"\n\nimport React, { useCallback, useEffect } from \"react\"\nimport { motion, useMotionTemplate, useMotionValue } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface MagicCardProps {\n children?: React.ReactNode\n className?: string\n gradientSize?: number\n gradientColor?: string\n gradientOpacity?: number\n gradientFrom?: string\n gradientTo?: string\n}\n\nexport function MagicCard({\n children,\n className,\n gradientSize = 200,\n gradientColor = \"#262626\",\n gradientOpacity = 0.8,\n gradientFrom = \"#9E7AFF\",\n gradientTo = \"#FE8BBB\",\n}: MagicCardProps) {\n const mouseX = useMotionValue(-gradientSize)\n const mouseY = useMotionValue(-gradientSize)\n const reset = useCallback(() => {\n mouseX.set(-gradientSize)\n mouseY.set(-gradientSize)\n }, [gradientSize, mouseX, mouseY])\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n const rect = e.currentTarget.getBoundingClientRect()\n mouseX.set(e.clientX - rect.left)\n mouseY.set(e.clientY - rect.top)\n },\n [mouseX, mouseY]\n )\n\n useEffect(() => {\n reset()\n }, [reset])\n\n useEffect(() => {\n const handleGlobalPointerOut = (e: PointerEvent) => {\n if (!e.relatedTarget) {\n reset()\n }\n }\n\n const handleVisibility = () => {\n if (document.visibilityState !== \"visible\") {\n reset()\n }\n }\n\n window.addEventListener(\"pointerout\", handleGlobalPointerOut)\n window.addEventListener(\"blur\", reset)\n document.addEventListener(\"visibilitychange\", handleVisibility)\n\n return () => {\n window.removeEventListener(\"pointerout\", handleGlobalPointerOut)\n window.removeEventListener(\"blur\", reset)\n document.removeEventListener(\"visibilitychange\", handleVisibility)\n }\n }, [reset])\n\n return (\n <div\n className={cn(\"group relative rounded-[inherit]\", className)}\n onPointerMove={handlePointerMove}\n onPointerLeave={reset}\n onPointerEnter={reset}\n >\n <motion.div\n className=\"bg-border pointer-events-none absolute inset-0 rounded-[inherit] duration-300 group-hover:opacity-100\"\n style={{\n background: useMotionTemplate`\n radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px,\n ${gradientFrom}, \n ${gradientTo}, \n var(--border) 100%\n )\n `,\n }}\n />\n <div className=\"bg-background absolute inset-px rounded-[inherit]\" />\n <motion.div\n className=\"pointer-events-none absolute inset-px rounded-[inherit] opacity-0 transition-opacity duration-300 group-hover:opacity-100\"\n style={{\n background: useMotionTemplate`\n radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px, ${gradientColor}, transparent 100%)\n `,\n opacity: gradientOpacity,\n }}\n />\n <div className=\"relative\">{children}</div>\n </div>\n )\n}\n",
"content": "\"use client\"\n\nimport React, { useCallback, useEffect, useRef } from \"react\"\nimport {\n animate,\n motion,\n useMotionTemplate,\n useMotionValue,\n} from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface MagicCardProps {\n children?: React.ReactNode\n className?: string\n gradientSize?: number\n gradientColor?: string\n gradientOpacity?: number\n gradientFrom?: string\n gradientTo?: string\n}\n\nexport function MagicCard({\n children,\n className,\n gradientSize = 200,\n gradientColor = \"#262626\",\n gradientOpacity = 0.8,\n gradientFrom = \"#9E7AFF\",\n gradientTo = \"#FE8BBB\",\n}: MagicCardProps) {\n const ref = useRef<HTMLDivElement>(null)\n\n const mouseX = useMotionValue(-gradientSize)\n const mouseY = useMotionValue(-gradientSize)\n\n const reset = useCallback(() => {\n if (!ref.current) return\n const rect = ref.current.getBoundingClientRect()\n const x = mouseX.get()\n const y = mouseY.get()\n\n const distances = {\n left: x,\n right: rect.width - x,\n top: y,\n bottom: rect.height - y,\n }\n\n const closestEdge = Object.entries(distances).reduce(\n (closest, [edge, distance]) =>\n distance < closest.distance ? { edge, distance } : closest,\n { edge: \"left\", distance: distances.left }\n ).edge\n\n switch (closestEdge) {\n case \"left\":\n return animate(mouseX, -gradientSize)\n case \"right\":\n return animate(mouseX, rect.width + gradientSize)\n case \"top\":\n return animate(mouseY, -gradientSize)\n case \"bottom\":\n return animate(mouseY, rect.height + gradientSize)\n default:\n animate(mouseX, -gradientSize)\n animate(mouseY, -gradientSize)\n }\n }, [gradientSize, mouseX, mouseY])\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n const rect = e.currentTarget.getBoundingClientRect()\n mouseX.set(e.clientX - rect.left)\n mouseY.set(e.clientY - rect.top)\n },\n [mouseX, mouseY]\n )\n\n useEffect(() => {\n reset()\n }, [reset])\n\n useEffect(() => {\n const handleGlobalPointerOut = (e: PointerEvent) => {\n if (!e.relatedTarget) {\n reset()\n }\n }\n\n const handleVisibility = () => {\n if (document.visibilityState !== \"visible\") {\n reset()\n }\n }\n\n window.addEventListener(\"pointerout\", handleGlobalPointerOut)\n window.addEventListener(\"blur\", reset)\n document.addEventListener(\"visibilitychange\", handleVisibility)\n\n return () => {\n window.removeEventListener(\"pointerout\", handleGlobalPointerOut)\n window.removeEventListener(\"blur\", reset)\n document.removeEventListener(\"visibilitychange\", handleVisibility)\n }\n }, [reset])\n\n return (\n <motion.div\n ref={ref}\n className={cn(\n \"group relative overflow-hidden rounded-[inherit] border border-transparent\",\n className\n )}\n onPointerMove={handlePointerMove}\n onPointerLeave={reset}\n onPointerEnter={reset}\n style={{\n background: useMotionTemplate`\n linear-gradient(var(--color-background) 0 0) padding-box,\n radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px,\n ${gradientFrom}, \n ${gradientTo},\n var(--color-border) 100%\n ) border-box\n `,\n }}\n >\n <motion.div\n className=\"pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100\"\n style={{\n background: useMotionTemplate`\n radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px, ${gradientColor}, transparent 100%)\n `,\n opacity: gradientOpacity,\n }}\n />\n <div className=\"relative\">{children}</div>\n </motion.div>\n )\n}\n",
"type": "registry:ui"
}
]
Expand Down
80 changes: 59 additions & 21 deletions apps/www/registry/magicui/magic-card.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
"use client"

import React, { useCallback, useEffect } from "react"
import { motion, useMotionTemplate, useMotionValue } from "motion/react"
import React, { useCallback, useEffect, useRef } from "react"
import {
animate,
motion,
useMotionTemplate,
useMotionValue,
} from "motion/react"

import { cn } from "@/lib/utils"

Expand All @@ -24,11 +29,43 @@ export function MagicCard({
gradientFrom = "#9E7AFF",
gradientTo = "#FE8BBB",
}: MagicCardProps) {
const ref = useRef<HTMLDivElement>(null)

const mouseX = useMotionValue(-gradientSize)
const mouseY = useMotionValue(-gradientSize)

const reset = useCallback(() => {
mouseX.set(-gradientSize)
mouseY.set(-gradientSize)
if (!ref.current) return
const rect = ref.current.getBoundingClientRect()
const x = mouseX.get()
const y = mouseY.get()

const distances = {
left: x,
right: rect.width - x,
top: y,
bottom: rect.height - y,
}

const closestEdge = Object.entries(distances).reduce(
(closest, [edge, distance]) =>
distance < closest.distance ? { edge, distance } : closest,
{ edge: "left", distance: distances.left }
).edge

switch (closestEdge) {
case "left":
return animate(mouseX, -gradientSize)
case "right":
return animate(mouseX, rect.width + gradientSize)
case "top":
return animate(mouseY, -gradientSize)
case "bottom":
return animate(mouseY, rect.height + gradientSize)
default:
animate(mouseX, -gradientSize)
animate(mouseY, -gradientSize)
}
}, [gradientSize, mouseX, mouseY])

const handlePointerMove = useCallback(
Expand Down Expand Up @@ -69,27 +106,28 @@ export function MagicCard({
}, [reset])

return (
<div
className={cn("group relative rounded-[inherit]", className)}
<motion.div
ref={ref}
className={cn(
"group relative overflow-hidden rounded-[inherit] border border-transparent",
className
)}
onPointerMove={handlePointerMove}
onPointerLeave={reset}
onPointerEnter={reset}
>
<motion.div
className="bg-border pointer-events-none absolute inset-0 rounded-[inherit] duration-300 group-hover:opacity-100"
style={{
background: useMotionTemplate`
radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px,
style={{
background: useMotionTemplate`
linear-gradient(var(--color-background) 0 0) padding-box,
radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px,
${gradientFrom},
${gradientTo},
var(--border) 100%
)
`,
}}
/>
<div className="bg-background absolute inset-px rounded-[inherit]" />
${gradientTo},
var(--color-border) 100%
) border-box
`,
}}
>
<motion.div
className="pointer-events-none absolute inset-px rounded-[inherit] opacity-0 transition-opacity duration-300 group-hover:opacity-100"
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100"
style={{
background: useMotionTemplate`
radial-gradient(${gradientSize}px circle at ${mouseX}px ${mouseY}px, ${gradientColor}, transparent 100%)
Expand All @@ -98,6 +136,6 @@ export function MagicCard({
}}
/>
<div className="relative">{children}</div>
</div>
</motion.div>
)
}