All files / islands / CopyButton.tsx

100.00% Branches 0/0
1.14% Lines 1/88
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
x1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


















































































































































import { useCopy } from "@hooks/useCopy.ts";

interface CopyButtonProps {
  text: string;
  className?: string;
  children?: string;
  variant?: "default" | "ghost" | "outline";
  size?: "sm" | "md" | "lg";
}

export default function CopyButton({
  text,
  className = "",
  children = "复制",
  variant = "default",
  size = "md",
}: CopyButtonProps) {
  const { copy, copied, error } = useCopy({
    timeout: 2000,
    onSuccess: () => {
      console.log("复制成功");
    },
    onError: (err) => {
      console.error("复制失败:", err);
    },
  });

  const handleCopy = () => {
    copy(text);
  };

  const variantClasses = {
    default: "bg-primary-500 hover:bg-primary-600 text-white",
    ghost:
      "bg-transparent hover:bg-neutral-100 dark:hover:bg-neutral-800 text-neutral-600 dark:text-neutral-400",
    outline:
      "border border-neutral-300 dark:border-neutral-600 bg-transparent hover:bg-neutral-50 dark:hover:bg-neutral-800 text-neutral-600 dark:text-neutral-400",
  };

  const sizeClasses = {
    sm: "px-2 py-1 text-xs",
    md: "px-3 py-1.5 text-sm",
    lg: "px-4 py-2 text-base",
  };

  return (
    <div className="relative">
      <button
        onClick={handleCopy}
        className={`
          inline-flex items-center gap-2 rounded-lg font-medium
          transition-all duration-200 hover:scale-105
          magnetic-element cursor-none
          ${variantClasses[variant]}
          ${sizeClasses[size]}
          ${className}
        `}
        title={copied ? "已复制!" : "点击复制"}
      >
        {copied
          ? (
            <>
              <svg
                className="w-4 h-4 text-success-500"
                fill="currentColor"
                viewBox="0 0 20 20"
              >
                <path
                  fillRule="evenodd"
                  d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
                  clipRule="evenodd"
                />
              </svg>
              <span className="text-success-500">已复制</span>
            </>
          )
          : (
            <>
              <svg
                className="w-4 h-4"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth="2"
                  d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
                />
              </svg>
              <span>{children}</span>
            </>
          )}
      </button>

      {/* 复制成功提示 - 优化为横向展示 */}
      {copied && (
        <div className="
          fixed top-4 left-1/2 transform -translate-x-1/2
          flex items-center gap-2
          px-4 py-2 bg-success-500 text-white text-sm font-medium
          rounded-lg shadow-lg animate-fade-in
          pointer-events-none z-50
          whitespace-nowrap
        ">
          <svg
            className="w-4 h-4 flex-shrink-0"
            fill="currentColor"
            viewBox="0 0 20 20"
          >
            <path
              fillRule="evenodd"
              d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
              clipRule="evenodd"
            />
          </svg>
          <span>复制成功</span>
        </div>
      )}

      {/* 错误提示 - 也优化为横向展示 */}
      {error && (
        <div className="
          fixed top-4 left-1/2 transform -translate-x-1/2
          flex items-center gap-2
          px-4 py-2 bg-error-500 text-white text-sm font-medium
          rounded-lg shadow-lg animate-fade-in
          pointer-events-none z-50
          whitespace-nowrap
        ">
          <svg
            className="w-4 h-4 flex-shrink-0"
            fill="currentColor"
            viewBox="0 0 20 20"
          >
            <path
              fillRule="evenodd"
              d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
              clipRule="evenodd"
            />
          </svg>
          <span>复制失败</span>
        </div>
      )}
    </div>
  );
}