- Gemeinsame FormPanel-Karte fuer Passwort- und Zwei-Faktor-Seiten - Zwei-Faktor-Code: grosses, zentriertes Ziffernfeld - Backup-Codes als nummerierte Kacheln statt langer Liste - Newsletter-Bestaetigung: Willkommensrabatt als Gutschein mit gestricheltem Rand und Kopier-Knopf (bestaetigt "Kopiert") Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
56 lines
2.0 KiB
TypeScript
56 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { AnimatePresence, motion } from "motion/react";
|
|
|
|
/**
|
|
* Kopiert einen Gutscheincode in die Zwischenablage und bestaetigt das kurz
|
|
* am Knopf selbst. Ohne Clipboard-API (aeltere Browser, unsicherer Kontext)
|
|
* bleibt der Code sichtbar und markierbar — der Knopf meldet dann nichts.
|
|
*/
|
|
export function CopyCodeButton({ code, label, copiedLabel }: { code: string; label: string; copiedLabel: string }) {
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
async function copy() {
|
|
try {
|
|
await navigator.clipboard.writeText(code);
|
|
setCopied(true);
|
|
window.setTimeout(() => setCopied(false), 2000);
|
|
} catch {
|
|
// Kein Zugriff auf die Zwischenablage — der Code bleibt zum Markieren sichtbar.
|
|
}
|
|
}
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={copy}
|
|
className="inline-flex h-10 items-center gap-2 border border-forest px-4 text-xs tracking-wide-caps text-forest transition-colors hover:bg-forest hover:text-cream"
|
|
aria-live="polite"
|
|
>
|
|
<AnimatePresence mode="wait" initial={false}>
|
|
<motion.span
|
|
key={copied ? "done" : "idle"}
|
|
initial={{ opacity: 0, y: 5 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -5 }}
|
|
transition={{ duration: 0.15 }}
|
|
className="inline-flex items-center gap-2"
|
|
>
|
|
<svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="1.6" aria-hidden="true">
|
|
{copied ? (
|
|
<path d="M5 12.5l4.5 4.5L19 7.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
) : (
|
|
<>
|
|
<rect x="8" y="8" width="12" height="12" rx="1.5" />
|
|
<path d="M16 8V5.5A1.5 1.5 0 0 0 14.5 4h-9A1.5 1.5 0 0 0 4 5.5v9A1.5 1.5 0 0 0 5.5 16H8" />
|
|
</>
|
|
)}
|
|
</svg>
|
|
{copied ? copiedLabel : label}
|
|
</motion.span>
|
|
</AnimatePresence>
|
|
</button>
|
|
);
|
|
}
|