Skip to content

Commit 6991fd6

Browse files
committed
feat: add glow button variant
1 parent 3283201 commit 6991fd6

File tree

3 files changed

+65
-18
lines changed

3 files changed

+65
-18
lines changed

src/components/ui/buttons/Button.tsx

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import * as React from "react"
44
import { cva, type VariantProps } from "class-variance-authority"
5+
import { Sparkles } from "lucide-react"
56
import { Slot } from "@radix-ui/react-slot"
67

78
import { cn } from "@/lib/utils/cn"
@@ -10,6 +11,26 @@ import { scrollIntoView } from "@/lib/utils/scrollIntoView"
1011

1112
import { BaseLink, type LinkProps } from "../Link"
1213

14+
const variants = {
15+
variant: {
16+
solid: cn(
17+
"text-white bg-primary-action border-transparent",
18+
"hover:!text-white hover:bg-primary-action-hover", // Hover
19+
"active:bg-primary-action-hover", // Active
20+
"disabled:bg-disabled disabled:text-background" // Disabled
21+
),
22+
outline: "", // Base styling
23+
ghost: "border-transparent hover:shadow-none",
24+
link: "border-transparent hover:shadow-none underline !min-h-0 !py-0 !px-1 active:text-primary",
25+
glow: "group relative rounded-lg border-none p-px text-body [&_[data-label='inner']]:!rounded-[7px]",
26+
},
27+
size: {
28+
lg: "text-lg py-3 px-8 [&>svg]:size-6 [&>svg]:text-2xl rounded-lg focus-visible:rounded-lg",
29+
md: "min-h-10.5 px-4 py-2 [&>svg]:size-6 [&>svg]:text-2xl",
30+
sm: "text-xs min-h-[31px] py-1.5 px-2 [&>svg]:size-4 [&>svg]:text-md",
31+
},
32+
}
33+
1334
const buttonVariants = cva(
1435
cn(
1536
// Sizing and positioning classes:
@@ -28,24 +49,7 @@ const buttonVariants = cva(
2849
"[&[data-secondary='true']]:text-body"
2950
),
3051
{
31-
variants: {
32-
variant: {
33-
solid: cn(
34-
"text-white bg-primary-action border-transparent",
35-
"hover:!text-white hover:bg-primary-action-hover", // Hover
36-
"active:bg-primary-action-hover", // Active
37-
"disabled:bg-disabled disabled:text-background" // Disabled
38-
),
39-
outline: "", // Base styling
40-
ghost: "border-transparent hover:shadow-none",
41-
link: "border-transparent hover:shadow-none underline !min-h-0 !py-0 !px-1 active:text-primary",
42-
},
43-
size: {
44-
lg: "text-lg py-3 px-8 [&>svg]:text-2xl rounded-lg focus-visible:rounded-lg",
45-
md: "min-h-10.5 px-4 py-2 [&>svg]:text-2xl",
46-
sm: "text-xs min-h-[31px] py-1.5 px-2 [&>svg]:text-md",
47-
},
48-
},
52+
variants,
4953
defaultVariants: {
5054
variant: "solid",
5155
size: "md",
@@ -110,6 +114,30 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
110114

111115
onClick?.(e)
112116
}
117+
if (variant === "glow") {
118+
const { children, ...buttonProps } = props
119+
return (
120+
<button
121+
className={cn(variants.variant.glow, className)}
122+
{...buttonProps}
123+
>
124+
{/* Glow */}
125+
<div className="absolute inset-0 overflow-hidden rounded-[inherit] opacity-50 blur-md transition-transform duration-300 after:absolute after:-inset-[200%] after:bg-rainbow-gradient group-hover:scale-110 group-hover:transition-transform group-hover:duration-300 after:motion-safe:animate-spin-4" />
126+
{/* Border */}
127+
<div className="absolute inset-0 overflow-hidden rounded-[inherit] after:absolute after:-inset-[200%] after:bg-rainbow-gradient after:motion-safe:animate-spin-4" />
128+
<div
129+
data-label="inner"
130+
className={cn(
131+
variants.size[size || "md"],
132+
"relative z-[1] inline-flex gap-2 bg-background/90 px-6 pb-2 pt-3 font-semibold shadow-inner ring-[1px] ring-white/25 backdrop-blur-lg"
133+
)}
134+
>
135+
{children}
136+
<Sparkles className="rotate//-12 mb-1 transition-transform group-hover:animate-wave group-hover:transition-transform" />
137+
</div>
138+
</button>
139+
)
140+
}
113141

114142
const Comp = asChild ? Slot : "button"
115143
return (

src/styles/semantic-tokens.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@
9797
--card-gradient-secondary-hover: linear-gradient(95deg, rgba(211, 145, 242, 0.2) 0%, rgba(159, 43, 212, 0.2) 102.78%);
9898
--ten-year-gradient: linear-gradient(100deg, #F6C9EA 55.38%, #C7A9F1 110.54%);
9999

100+
/* Rainbow gradients */
101+
--rainbow-gradient: conic-gradient(
102+
from 0deg,
103+
hsla(var(--primary)),
104+
hsla(var(--accent-b)),
105+
hsla(var(--accent-a)),
106+
hsla(var(--accent-c)),
107+
hsla(var(--primary))
108+
);
109+
100110
/* Shadows */
101111
--shadow-color-a: hsla(var(--purple-800), 0.02);
102112
--shadow-color-b: hsla(var(--red-800), 0.04);

tailwind.config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ const config = {
237237
"card-gradient-secondary": "var(--card-gradient-secondary)",
238238
"card-gradient-secondary-hover": "var(--card-gradient-secondary-hover)",
239239
"ten-year-gradient": "var(--ten-year-gradient)",
240+
"rainbow-gradient": "var(--rainbow-gradient)",
240241
},
241242
boxShadow: {
242243
"table-box": "var(--table-box-shadow)",
@@ -306,6 +307,12 @@ const config = {
306307
"0%": { opacity: "0" },
307308
"100%": { opacity: "1" },
308309
},
310+
"rotate-back-and-forth": {
311+
"0%": { transform: "rotate(0deg)" },
312+
"25%": { transform: "rotate(5deg)" },
313+
"75%": { transform: "rotate(-5deg)" },
314+
"100%": { transform: "rotate(0deg)" },
315+
},
309316
},
310317
animation: {
311318
"accordion-down": "accordion-down 0.2s ease-out",
@@ -320,9 +327,11 @@ const config = {
320327
"spin-18": "spin 36s linear infinite",
321328
"counter-spin-18": "spin 36s linear infinite reverse",
322329
"spin-9": "spin 18s linear infinite",
330+
"spin-4": "spin 4s linear infinite",
323331
"counter-spin-9": "spin 18s linear infinite reverse",
324332
"pulse-light": "pulse-light 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
325333
"fade-in": "fade-in 150ms ease-in-out",
334+
wave: "rotate-back-and-forth 1s linear infinite",
326335
},
327336
// Add custom border-radius tailwinds extension for "4xl" as "2rem"
328337
borderRadius: {

0 commit comments

Comments
 (0)