121 lines
4.3 KiB
TypeScript
121 lines
4.3 KiB
TypeScript
import type React from 'react'
|
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
import { motion, type HTMLMotionProps } from 'framer-motion'
|
|
import { Loader2 } from 'lucide-react'
|
|
|
|
const buttonVariants = cva(
|
|
// Base styles
|
|
'justify-center px-4 text-sm font-medium items-center transition-[box-shadow,background-color] disabled:cursor-not-allowed disabled:opacity-50 flex active:transition-none',
|
|
{
|
|
variants: {
|
|
intent: {
|
|
default: [
|
|
'bg-[#36322F]',
|
|
'text-[#fff]',
|
|
'hover:enabled:bg-[#4a4542]',
|
|
'disabled:bg-[#8c8885]',
|
|
'[box-shadow:inset_0px_-2.108433723449707px_0px_0px_#171310,_0px_1.2048193216323853px_6.325301647186279px_0px_rgba(58,_33,_8,_58%)]',
|
|
'hover:enabled:[box-shadow:inset_0px_-2.53012px_0px_0px_#171310,_0px_1.44578px_7.59036px_0px_rgba(58,_33,_8,_64%)]',
|
|
'disabled:shadow-none',
|
|
'active:bg-[#2A2724]',
|
|
'active:[box-shadow:inset_0px_-1.5px_0px_0px_#171310,_0px_0.5px_2px_0px_rgba(58,_33,_8,_70%)]',
|
|
],
|
|
primary: [
|
|
'bg-primary',
|
|
'text-primary-foreground',
|
|
'hover:enabled:bg-accent',
|
|
'disabled:bg-[#9FC3F5]',
|
|
'[box-shadow:inset_0px_-2.108433723449707px_0px_0px_hsla(var(--accent)),_0px_1.2048193216323853px_6.325301647186279px_0px_hsla(var(--accent))]',
|
|
'hover:enabled:[box-shadow:inset_0px_-2.53012px_0px_0px_hsla(var(--accent)),_0px_1.44578px_7.59036px_0px_hsla(var(--accent))]',
|
|
'disabled:shadow-none',
|
|
'active:bg-[#1A68D1]',
|
|
'active:[box-shadow:inset_0px_-1.5px_0px_0px_#1554AB,_0px_0.5px_2px_0px_rgba(28,_100,_242,_70%)]',
|
|
],
|
|
secondary: [
|
|
'bg-[#FFFFFF]',
|
|
'text-[#36322F]',
|
|
'hover:enabled:bg-[#F8F8F8]',
|
|
'disabled:bg-[#F0F0F0]',
|
|
'[box-shadow:inset_0px_-2.108433723449707px_0px_0px_#E0E0E0,_0px_1.2048193216323853px_6.325301647186279px_0px_rgba(0,_0,_0,_10%)]',
|
|
'hover:enabled:[box-shadow:inset_0px_-2.53012px_0px_0px_#E8E8E8,_0px_1.44578px_7.59036px_0px_rgba(0,_0,_0,_12%)]',
|
|
'disabled:shadow-none',
|
|
'border',
|
|
'border-[#E0E0E0]',
|
|
'active:bg-[#F0F0F0]',
|
|
'active:[box-shadow:inset_0px_-1.5px_0px_0px_#D8D8D8,_0px_0.5px_2px_0px_rgba(0,_0,_0,_15%)]',
|
|
],
|
|
danger: [
|
|
'bg-[#E6492D]',
|
|
'text-[#fff]',
|
|
'hover:enabled:bg-[#F05B41]',
|
|
'disabled:bg-[#F5A799]',
|
|
'[box-shadow:inset_0px_-2.108433723449707px_0px_0px_#D63A1F,_0px_1.2048193216323853px_6.325301647186279px_0px_rgba(214,_58,_31,_58%)]',
|
|
'hover:enabled:[box-shadow:inset_0px_-2.53012px_0px_0px_#E6492D,_0px_1.44578px_7.59036px_0px_rgba(214,_58,_31,_64%)]',
|
|
'disabled:shadow-none',
|
|
'active:bg-[#D63A1F]',
|
|
'active:[box-shadow:inset_0px_-1.5px_0px_0px_#B22E17,_0px_0.5px_2px_0px_rgba(214,_58,_31,_70%)]',
|
|
],
|
|
},
|
|
size: {
|
|
small: ['text-xs', 'py-1', 'px-2', 'h-9', 'rounded-[8px]'],
|
|
medium: ['text-base', 'py-2', 'px-4', 'h-11', 'rounded-[9px]'],
|
|
large: ['text-lg', 'py-3', 'px-6', 'h-14', 'rounded-[11px]'],
|
|
},
|
|
fullWidth: {
|
|
true: 'w-full',
|
|
},
|
|
},
|
|
compoundVariants: [
|
|
{
|
|
intent: ['default', 'primary', 'secondary', 'danger'],
|
|
size: 'medium',
|
|
className: 'uppercase',
|
|
},
|
|
],
|
|
defaultVariants: {
|
|
intent: 'default',
|
|
size: 'medium',
|
|
},
|
|
},
|
|
)
|
|
|
|
export interface NeumorphButtonProps
|
|
extends HTMLMotionProps<'button'>,
|
|
VariantProps<typeof buttonVariants> {
|
|
children: React.ReactNode
|
|
loading?: boolean
|
|
}
|
|
|
|
const NeumorphButton: React.FC<NeumorphButtonProps> = ({
|
|
className,
|
|
intent,
|
|
size,
|
|
fullWidth,
|
|
children,
|
|
loading = false,
|
|
disabled,
|
|
...props
|
|
}) => {
|
|
return (
|
|
<motion.button
|
|
className={buttonVariants({ intent, size, fullWidth, className })}
|
|
disabled={disabled || loading}
|
|
whileTap={{ scale: 0.98 }}
|
|
whileHover={{ scale: 1.02 }}
|
|
transition={{ type: 'spring', stiffness: 400, damping: 10 }}
|
|
{...props}
|
|
>
|
|
{loading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
|
|
<motion.span
|
|
initial={{ opacity: 1 }}
|
|
animate={{ opacity: loading ? 0.7 : 1 }}
|
|
transition={{ duration: 0.2 }}
|
|
>
|
|
{children}
|
|
</motion.span>
|
|
</motion.button>
|
|
)
|
|
}
|
|
|
|
export default NeumorphButton
|