153 lines
5.2 KiB
TypeScript
153 lines
5.2 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { motion } from "framer-motion";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface CyberButtonProps {
|
|
href?: string;
|
|
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
children: React.ReactNode;
|
|
className?: string;
|
|
variant?: "primary" | "secondary";
|
|
disabled?: boolean;
|
|
type?: "button" | "submit" | "reset";
|
|
}
|
|
|
|
export function CyberButton({
|
|
href,
|
|
onClick,
|
|
children,
|
|
className,
|
|
variant = "primary",
|
|
disabled = false,
|
|
type = "button",
|
|
}: CyberButtonProps) {
|
|
const isPrimary = variant === "primary";
|
|
|
|
const content = (
|
|
<motion.div
|
|
whileHover={!disabled ? { scale: 1.02 } : {}}
|
|
whileTap={!disabled ? { scale: 0.98 } : {}}
|
|
className={cn(
|
|
"relative z-10 flex items-center justify-center px-8 py-4 overflow-hidden transition-all duration-300 border rounded-xl font-mono",
|
|
|
|
// --- ACTIVE STATE ---
|
|
!disabled && [
|
|
isPrimary
|
|
? "bg-[#8B3DFF] border-[#8B3DFF] text-white shadow-lg shadow-purple-500/20 dark:bg-[radial-gradient(circle_at_center,_rgba(139,61,255,0.4)_0%,_rgba(139,61,255,0.1)_100%)] dark:border-[#8B3DFF]/50 dark:shadow-[0_0_25px_rgba(139,61,255,0.3)] dark:after:absolute dark:after:inset-0 dark:after:shadow-[inset_0_0_15px_rgba(139,61,255,0.2)]"
|
|
: "text-[#00E5F2] border-[#00E5F2]/40 backdrop-blur-md bg-slate-900/5 border-[#00E5F2]/50 shadow-sm dark:bg-[#00E5F2]/5 dark:border-[#00E5F2]/30 dark:shadow-[0_0_15px_rgba(0,229,242,0.1)] hover:border-[#00E5F2] hover:shadow-[0_0_20px_rgba(0,229,242,0.3)]",
|
|
],
|
|
|
|
// --- DISABLED STATE (Исправленный) ---
|
|
disabled && [
|
|
"cursor-not-allowed border-dashed shadow-none",
|
|
// Светлая тема: делаем кнопку матовой и "холодной"
|
|
"bg-slate-100 border-slate-300 text-slate-400",
|
|
// Темная тема: делаем кнопку глубокой и "выключенной"
|
|
"dark:bg-slate-900/40 dark:border-slate-800 dark:text-slate-600",
|
|
],
|
|
|
|
className,
|
|
)}
|
|
>
|
|
{/* CRT Сетка (только когда активна) */}
|
|
{!isPrimary && !disabled && (
|
|
<div className="absolute inset-0 opacity-[0.03] dark:opacity-10 pointer-events-none bg-[linear-gradient(rgba(18,16,16,0)_50%,rgba(0,229,242,0.1)_50%),linear-gradient(90deg,rgba(255,0,0,0.02),rgba(0,255,0,0.01),rgba(0,0,255,0.02))] bg-[length:100%_4px,3px_100%]" />
|
|
)}
|
|
|
|
{/* Энергетический блик (только когда активна) */}
|
|
{!disabled && (
|
|
<div
|
|
className={cn(
|
|
"absolute inset-0 w-full h-full -translate-x-full group-hover:animate-scan pointer-events-none",
|
|
isPrimary
|
|
? "bg-gradient-to-r from-transparent via-white/20 to-transparent"
|
|
: "bg-gradient-to-r from-transparent via-[#00E5F2]/20 to-transparent",
|
|
)}
|
|
/>
|
|
)}
|
|
|
|
{/* Угловые элементы (⌜ ⌟) - прячем или приглушаем при disabled */}
|
|
<div
|
|
className={cn(
|
|
"absolute inset-0 pointer-events-none transition-opacity",
|
|
disabled ? "opacity-20" : "opacity-60",
|
|
)}
|
|
>
|
|
<span
|
|
className={cn(
|
|
"absolute top-1 left-1 text-[10px] font-mono",
|
|
isPrimary ? "text-white" : "text-[#00E5F2]",
|
|
)}
|
|
>
|
|
⌜
|
|
</span>
|
|
<span
|
|
className={cn(
|
|
"absolute bottom-1 right-1 text-[10px] font-mono",
|
|
isPrimary ? "text-white" : "text-[#00E5F2]",
|
|
)}
|
|
>
|
|
⌟
|
|
</span>
|
|
</div>
|
|
|
|
{/* Анимированная полоска заряда (только для Secondary и когда активна) */}
|
|
{!isPrimary && !disabled && (
|
|
<motion.div
|
|
initial={{ height: 0 }}
|
|
whileHover={{ height: "70%" }}
|
|
className="absolute left-0 w-[2px] bg-[#00E5F2] shadow-[0_0_10px_#00E5F2] transition-all"
|
|
/>
|
|
)}
|
|
|
|
{/* Текст */}
|
|
<span
|
|
className={cn(
|
|
"relative z-20 font-black uppercase tracking-[0.2em] text-sm flex items-center gap-2",
|
|
!isPrimary &&
|
|
!disabled &&
|
|
"drop-shadow-[0_0_5px_rgba(0,229,242,0.5)]",
|
|
disabled && "drop-shadow-none",
|
|
)}
|
|
>
|
|
<span className="opacity-50">[</span>
|
|
{children}
|
|
<span className="opacity-50">]</span>
|
|
</span>
|
|
</motion.div>
|
|
);
|
|
|
|
// Фоновое облако свечения (только когда активна)
|
|
const glowEffect = !disabled && (
|
|
<div
|
|
className={cn(
|
|
"absolute inset-0 blur-2xl opacity-0 group-hover:opacity-40 transition-opacity duration-500 -z-10",
|
|
isPrimary ? "bg-[#8B3DFF]" : "bg-[#00E5F2]/40",
|
|
)}
|
|
/>
|
|
);
|
|
|
|
if (href && !disabled) {
|
|
return (
|
|
<Link href={href} className="group relative inline-block">
|
|
{content}
|
|
{glowEffect}
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<button
|
|
type={type}
|
|
disabled={disabled}
|
|
onClick={onClick}
|
|
className="group relative inline-block bg-transparent border-none p-0 outline-none cursor-pointer"
|
|
>
|
|
{content}
|
|
{glowEffect}
|
|
</button>
|
|
);
|
|
}
|