fancytextstuff/components/PerformanceOptimizedFontCar...

178 lines
7.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// components/PerformanceOptimizedFontCard.jsx
import React, { useState, useCallback, forwardRef, memo } 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, Zap } from "lucide-react";
import { fontTransforms } from "@/components/fontTransforms";
const sStr = (v) => (v ?? "").toString();
const updateFontHistory = (fontName) => {
  if (typeof window === "undefined") return;
  try {
    const key = "fancytext_recent_fonts";
    const stored = JSON.parse(sessionStorage.getItem(key) || "[]");
    const updated = [fontName, ...stored.filter((f) => f !== fontName)].slice(0, 5);
    sessionStorage.setItem(key, JSON.stringify(updated));
  } catch {}
};
const PerformanceOptimizedFontCard = forwardRef(({
  fontName,
  transformedText,
  category,
  isPopular,
  animationsEnabled,
  index,
  onCopy,
  onLike,
  onShare
}, ref) => {
  const [copied, setCopied] = useState(false);
  const [liked, setLiked] = useState(() => {
    if (typeof window === "undefined") return false;
    try {
      return localStorage.getItem(`liked_${fontName}`) === "true";
    } catch {
      return false;
    }
  });
  const handleCopy = useCallback(async () => {
    const textToCopy = sStr(transformedText?.transformed ?? transformedText);
    try {
      await navigator.clipboard.writeText(textToCopy);
      setCopied(true);
      updateFontHistory(fontName);
      navigator.vibrate?.(50);
      onCopy?.(fontName, textToCopy);
      setTimeout(() => setCopied(false), 2000);
    } catch {
      const textarea = document.createElement("textarea");
      textarea.value = textToCopy;
      textarea.setAttribute("readonly", "");
      textarea.style.position = "fixed";
      textarea.style.opacity = "0";
      document.body.appendChild(textarea);
      textarea.select();
      try {
        document.execCommand("copy");
        setCopied(true);
        updateFontHistory(fontName);
        setTimeout(() => setCopied(false), 2000);
      } catch (e) {
        console.error("Fallback copy failed:", e);
      }
      document.body.removeChild(textarea);
    }
  }, [transformedText, fontName, onCopy]);
  const handleLike = useCallback(() => {
    const newLiked = !liked;
    setLiked(newLiked);
    try { localStorage.setItem(`liked_${fontName}`, newLiked.toString()); } catch {}
    navigator.vibrate?.(newLiked ? 30 : 0);
    onLike?.(fontName, newLiked);
  }, [liked, fontName, onLike]);
  const handleShare = useCallback(async () => {
    const shareText = `${sStr(transformedText?.transformed ?? transformedText)}\n\nErstellt mit FancyText: ${window.location.href}`;
    if (navigator.share) {
      try {
        await navigator.share({ title: "Schau dir diese coole Schriftart an! 🔥", text: shareText, url: window.location.href });
        onShare?.(fontName);
      } catch {}
    } else {
      try {
        await navigator.clipboard.writeText(shareText);
        setCopied(true);
        setTimeout(() => setCopied(false), 2000);
      } catch (e) {
        console.error("Share fallback failed:", e);
      }
    }
  }, [transformedText, fontName, onShare]);
  const previewText = sStr(transformedText?.transformed ?? transformedText) || "Hallo Instagram!";
  const fontClass = transformedText?.fontClassName ?? "";
  const displayName = fontTransforms[fontName]?.description;
  return (
    <div ref={ref} className="will-change-transform mb-6">
      <Card className="bg-white/95 backdrop-blur-sm border-0 shadow-xl hover:shadow-2xl transition-all duration-200 overflow-hidden touch-manipulation">
        <div className="p-4 sm:p-6">
          <div className="flex items-center justify-between mb-3">
            <div className="flex items-center gap-2 min-w-0 flex-1">
              <h3 className="font-semibold text-gray-800 truncate text-sm sm:text-base">{fontName}</h3>
              {isPopular && (
                <Badge className="bg-gradient-to-r from-pink-500 to-purple-500 text-white text-xs shrink-0">
                  <Zap className="w-3 h-3 mr-1" /> Top
                </Badge>
              )}
            </div>
            <div className="flex items-center gap-1 shrink-0">
              <Button
                variant="ghost"
                size="sm"
                onClick={handleLike}
                style={{ pointerEvents: "auto" }}
                className={`p-2 touch-manipulation ${liked ? "text-pink-500" : "text-gray-400"}`}
                aria-label={liked ? "Unlike font" : "Like font"}
              >
                <Heart className={`w-4 h-4 ${liked ? "fill-current" : ""}`} />
              </Button>
              <Button
                variant="ghost"
                size="sm"
                onClick={handleShare}
                style={{ pointerEvents: "auto" }}
                className="p-2 touch-manipulation text-gray-400 hover:text-blue-500"
                aria-label="Share font"
              >
                <Share2 className="w-4 h-4" />
              </Button>
            </div>
          </div>
          {displayName && (
            <p className="text-xs text-gray-500 mb-3 flex items-start gap-1 leading-tight">
              <Info className="w-3 h-3 mt-0.5 shrink-0" />
              {displayName}
            </p>
          )}
          <div
            onClick={handleCopy}
            role="button"
            tabIndex={0}
            onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && handleCopy()}
            aria-label="Click to copy text"
            style={{ pointerEvents: "auto" }}
            className={`text-xl sm-text-2xl md-text-3xl mb-4 p-3 sm:p-4 bg-gray-50 rounded-xl text-center select-all text-gray-800 min-h-[70px] sm:min-h-[80px] flex items-center justify-center cursor-pointer hover:bg-gray-100 transition-colors ${fontClass}`}
          >
            {previewText}
          </div>
          <Button
            onClick={handleCopy}
            disabled={copied}
            style={{ pointerEvents: "auto" }}
            className={`w-full transition-all duration-200 touch-manipulation text-white font-medium py-3 rounded-xl shadow-lg hover:shadow-xl active:scale-95 ${
              copied
                ? "bg-green-500 hover:bg-green-600 shadow-green-200"
                : "bg-gradient-to-r from-pink-500 to-purple-500 hover:from-pink-600 hover:to-purple-600 shadow-pink-200"
            }`}
          >
            {copied ? (
              <><Check className="w-4 h-4 mr-2" /> Copy! </>
            ) : (
              <><Copy className="w-4 h-4 mr-2" /> Copy! </>
            )}
          </Button>
        </div>
      </Card>
    </div>
  );
});
PerformanceOptimizedFontCard.displayName = "PerformanceOptimizedFontCard";
export default memo(PerformanceOptimizedFontCard);