Replace all instances of "www.folx.tv" with "folx.tv" in the client and server configurations to resolve SSL issues preventing image sharing on social media platforms. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 1f7e7e89-a520-4970-9645-37daadc466dc Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 20f43e40-d815-42d5-9bb6-37729939c10e Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/1f7e7e89-a520-4970-9645-37daadc466dc/mwtHL8H Replit-Helium-Checkpoint-Created: true
143 lines
4.9 KiB
TypeScript
143 lines
4.9 KiB
TypeScript
import { SiFacebook, SiLinkedin, SiX, SiWhatsapp, SiTelegram, SiPinterest } from "react-icons/si";
|
|
import { Mail, Link2, Check } from "lucide-react";
|
|
import { useState } from "react";
|
|
|
|
interface ShareButtonsProps {
|
|
url: string;
|
|
title: string;
|
|
image?: string;
|
|
}
|
|
|
|
const CANONICAL_DOMAIN = "https://folx.tv";
|
|
|
|
function canonicalUrl(url: string): string {
|
|
try {
|
|
const parsed = new URL(url);
|
|
return `${CANONICAL_DOMAIN}${parsed.pathname}${parsed.search}${parsed.hash}`;
|
|
} catch {
|
|
return url;
|
|
}
|
|
}
|
|
|
|
function openPopup(shareUrl: string) {
|
|
const w = 600;
|
|
const h = 500;
|
|
const left = window.screenX + (window.outerWidth - w) / 2;
|
|
const top = window.screenY + (window.outerHeight - h) / 2;
|
|
window.open(shareUrl, "share", `width=${w},height=${h},left=${left},top=${top},toolbar=no,menubar=no,scrollbars=yes`);
|
|
}
|
|
|
|
interface ShareTarget {
|
|
name: string;
|
|
icon: typeof SiFacebook;
|
|
color: string;
|
|
getUrl: (url: string, title: string, image?: string) => string;
|
|
popup?: boolean;
|
|
}
|
|
|
|
const SHARE_TARGETS: ShareTarget[] = [
|
|
{
|
|
name: "Facebook",
|
|
icon: SiFacebook,
|
|
color: "hover:bg-[#1877F2] hover:text-white",
|
|
getUrl: (url: string) => `https://www.facebook.com/sharer.php?u=${encodeURIComponent(url)}`,
|
|
popup: true,
|
|
},
|
|
{
|
|
name: "X",
|
|
icon: SiX,
|
|
color: "hover:bg-[#000] hover:text-white",
|
|
getUrl: (url: string, title: string) => `https://x.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`,
|
|
popup: true,
|
|
},
|
|
{
|
|
name: "LinkedIn",
|
|
icon: SiLinkedin,
|
|
color: "hover:bg-[#0A66C2] hover:text-white",
|
|
getUrl: (url: string) => `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`,
|
|
popup: true,
|
|
},
|
|
{
|
|
name: "WhatsApp",
|
|
icon: SiWhatsapp,
|
|
color: "hover:bg-[#25D366] hover:text-white",
|
|
getUrl: (url: string, title: string) => `https://wa.me/?text=${encodeURIComponent(title + " " + url)}`,
|
|
},
|
|
{
|
|
name: "Telegram",
|
|
icon: SiTelegram,
|
|
color: "hover:bg-[#26A5E4] hover:text-white",
|
|
getUrl: (url: string, title: string) => `https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`,
|
|
},
|
|
{
|
|
name: "Pinterest",
|
|
icon: SiPinterest,
|
|
color: "hover:bg-[#BD081C] hover:text-white",
|
|
getUrl: (url: string, title: string, image?: string) => `https://pinterest.com/pin/create/button/?url=${encodeURIComponent(url)}&description=${encodeURIComponent(title)}${image ? "&media=" + encodeURIComponent(image) : ""}`,
|
|
popup: true,
|
|
},
|
|
{
|
|
name: "E-Mail",
|
|
icon: Mail,
|
|
color: "hover:bg-muted-foreground hover:text-white",
|
|
getUrl: (url: string, title: string) => `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(title + "\n\n" + url)}`,
|
|
},
|
|
];
|
|
|
|
export default function ShareButtons({ url, title, image }: ShareButtonsProps) {
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
const handleCopy = async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(canonicalUrl(url));
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
} catch {
|
|
const input = document.createElement("input");
|
|
input.value = canonicalUrl(url);
|
|
document.body.appendChild(input);
|
|
input.select();
|
|
document.execCommand("copy");
|
|
document.body.removeChild(input);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
}
|
|
};
|
|
|
|
const handleShare = (target: ShareTarget, e: React.MouseEvent) => {
|
|
const shareUrl = target.getUrl(canonicalUrl(url), title, image ? canonicalUrl(image) : undefined);
|
|
if (target.popup) {
|
|
e.preventDefault();
|
|
openPopup(shareUrl);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-wrap items-center gap-2" data-testid="share-buttons">
|
|
<span className="text-sm text-muted-foreground mr-1">Teilen:</span>
|
|
{SHARE_TARGETS.map((target) => (
|
|
<a
|
|
key={target.name}
|
|
href={target.getUrl(canonicalUrl(url), title, image ? canonicalUrl(image) : undefined)}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
onClick={(e) => handleShare(target, e)}
|
|
className={`inline-flex items-center justify-center w-9 h-9 rounded-full border border-border text-muted-foreground transition-all duration-200 ${target.color}`}
|
|
aria-label={`Auf ${target.name} teilen`}
|
|
data-testid={`button-share-${target.name.toLowerCase()}`}
|
|
>
|
|
<target.icon className="w-4 h-4" />
|
|
</a>
|
|
))}
|
|
<button
|
|
onClick={handleCopy}
|
|
className={`inline-flex items-center justify-center w-9 h-9 rounded-full border border-border transition-all duration-200 ${copied ? "bg-green-600 text-white border-green-600" : "text-muted-foreground hover:bg-muted-foreground hover:text-white"}`}
|
|
aria-label="Link kopieren"
|
|
data-testid="button-share-copy"
|
|
>
|
|
{copied ? <Check className="w-4 h-4" /> : <Link2 className="w-4 h-4" />}
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|