initial commit
This commit is contained in:
154
components/ui/FontCard.jsx
Normal file
154
components/ui/FontCard.jsx
Normal file
@@ -0,0 +1,154 @@
|
||||
// components/ui/FontCard.jsx
|
||||
import React, { useState } from "react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Copy, Check, Heart, Share2, Info } from "lucide-react";
|
||||
import { fontTransforms } from "../fontTransforms";
|
||||
import { getFontData } from "@/lib/fonts";
|
||||
|
||||
export default function FontCard({
|
||||
fontName,
|
||||
transformedText,
|
||||
category,
|
||||
isPopular,
|
||||
index = 0,
|
||||
}) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [liked, setLiked] = useState(false);
|
||||
|
||||
const fontInfo = fontTransforms[fontName];
|
||||
const fontData = getFontData(fontName);
|
||||
const displayText = transformedText || "Hallo Instagram!";
|
||||
|
||||
const handleCopy = () => {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
navigator.clipboard
|
||||
.writeText(displayText)
|
||||
.then(() => flashCopied())
|
||||
.catch(() => fallbackCopy());
|
||||
} else {
|
||||
fallbackCopy();
|
||||
}
|
||||
};
|
||||
|
||||
const flashCopied = () => {
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
const fallbackCopy = () => {
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = displayText;
|
||||
textarea.setAttribute("readonly", "");
|
||||
textarea.style.position = "fixed";
|
||||
textarea.style.top = "0";
|
||||
textarea.style.left = "0";
|
||||
textarea.style.width = "1px";
|
||||
textarea.style.height = "1px";
|
||||
textarea.style.padding = "0";
|
||||
textarea.style.border = "none";
|
||||
textarea.style.outline = "none";
|
||||
textarea.style.boxShadow = "none";
|
||||
textarea.style.background = "transparent";
|
||||
|
||||
document.body.appendChild(textarea);
|
||||
textarea.focus();
|
||||
textarea.select();
|
||||
try {
|
||||
document.execCommand("copy");
|
||||
flashCopied();
|
||||
} catch (err) {
|
||||
console.error("Fallback Copy fehlgeschlagen:", err);
|
||||
}
|
||||
document.body.removeChild(textarea);
|
||||
};
|
||||
|
||||
const handleShare = async () => {
|
||||
if (!navigator.share) return;
|
||||
try {
|
||||
await navigator.share({
|
||||
title: `FancyText – ${fontName}`,
|
||||
text: displayText,
|
||||
url: window.location.href,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Share fehlgeschlagen:", err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ pointerEvents: "none" }}>
|
||||
<Card className="bg-white/90 backdrop-blur-sm border-0 shadow-xl hover:shadow-2xl transition-all duration-300 overflow-hidden">
|
||||
<div className="p-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="font-semibold text-gray-800 capitalize">{fontName}</h3>
|
||||
{isPopular && (
|
||||
<Badge className="bg-gradient-to-r from-pink-500 to-purple-500 text-white text-[10px] uppercase tracking-wide">
|
||||
Beliebt
|
||||
</Badge>
|
||||
)}
|
||||
{category && (
|
||||
<Badge className="bg-gray-200 text-gray-600 text-[10px] uppercase tracking-wide">
|
||||
{category}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setLiked(!liked)}
|
||||
className={liked ? "text-pink-500" : "text-gray-400"}
|
||||
>
|
||||
<Heart className={`w-4 h-4 ${liked ? "fill-current" : ""}`} />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleShare}
|
||||
className="text-gray-400 hover:text-blue-500"
|
||||
>
|
||||
<Share2 className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{fontInfo?.description && (
|
||||
<p className="text-xs text-gray-500 mb-3 flex items-center gap-1">
|
||||
<Info className="w-3 h-3" />
|
||||
{fontInfo.description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<input
|
||||
type="text"
|
||||
value={displayText}
|
||||
readOnly
|
||||
className={`${fontData.className} text-2xl md:text-3xl mb-6 p-4 bg-gray-50 rounded-xl text-center text-gray-800 min-h-[80px] w-full select-all border-0 focus:ring-0`}
|
||||
style={{ lineHeight: "1.2" }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={handleCopy}
|
||||
className="w-full bg-gradient-to-r from-pink-500 to-purple-500 hover:from-pink-600 hover:to-purple-600 text-white font-medium py-3 rounded-xl shadow-lg pointer-events-auto"
|
||||
disabled={copied}
|
||||
>
|
||||
{copied ? (
|
||||
<>
|
||||
<Check className="w-4 h-4 mr-2" />
|
||||
Copy!
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Copy className="w-4 h-4 mr-2" />
|
||||
Copy now
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user