import { CollectionIncludingMembersAndLinkCount, LinkIncludingShortenedCollectionAndTags, } from "@/types/global"; import Image from "next/image"; import ColorThief, { RGBColor } from "colorthief"; import { useEffect, useState } from "react"; import Link from "next/link"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faArrowUpRightFromSquare, faBoxArchive, faCloudArrowDown, faFolder, } from "@fortawesome/free-solid-svg-icons"; import useCollectionStore from "@/store/collections"; import { faCalendarDays, faFileImage, faFilePdf, } from "@fortawesome/free-regular-svg-icons"; import isValidUrl from "@/lib/client/isValidUrl"; type Props = { link: LinkIncludingShortenedCollectionAndTags; }; export default function LinkDetails({ link }: Props) { const [imageError, setImageError] = useState(false); const formattedDate = new Date(link.createdAt as string).toLocaleString( "en-US", { year: "numeric", month: "short", day: "numeric", } ); const { collections } = useCollectionStore(); const [collection, setCollection] = useState( collections.find( (e) => e.id === link.collection.id ) as CollectionIncludingMembersAndLinkCount ); useEffect(() => { setCollection( collections.find( (e) => e.id === link.collection.id ) as CollectionIncludingMembersAndLinkCount ); }, [collections]); const [colorPalette, setColorPalette] = useState(); const colorThief = new ColorThief(); const url = isValidUrl(link.url) ? new URL(link.url) : undefined; const rgbToHex = (r: number, g: number, b: number): string => "#" + [r, g, b] .map((x) => { const hex = x.toString(16); return hex.length === 1 ? "0" + hex : hex; }) .join(""); useEffect(() => { const banner = document.getElementById("link-banner"); const bannerInner = document.getElementById("link-banner-inner"); if (colorPalette && banner && bannerInner) { banner.style.background = `linear-gradient(to right, ${rgbToHex( colorPalette[0][0], colorPalette[0][1], colorPalette[0][2] )}, ${rgbToHex( colorPalette[1][0], colorPalette[1][1], colorPalette[1][2] )})`; bannerInner.style.background = `linear-gradient(to right, ${rgbToHex( colorPalette[2][0], colorPalette[2][1], colorPalette[2][2] )}, ${rgbToHex( colorPalette[3][0], colorPalette[3][1], colorPalette[3][2] )})`; } }, [colorPalette]); const handleDownload = (format: "png" | "pdf") => { const path = `/api/archives/${link.collection.id}/${link.id}.${format}`; fetch(path) .then((response) => { if (response.ok) { // Create a temporary link and click it to trigger the download const link = document.createElement("a"); link.href = path; link.download = format === "pdf" ? "PDF" : "Screenshot"; link.click(); } else { console.error("Failed to download file"); } }) .catch((error) => { console.error("Error:", error); }); }; return (
{!imageError && ( )}
{!imageError && url && ( { try { const color = colorThief.getPalette( e.target as HTMLImageElement, 4, 20 ); setColorPalette(color); } catch (err) { console.log(err); } }} onError={(e) => { setImageError(true); }} /> )}

{link.name}

{url ? url.host : link.url}

{collection?.name}

{link.tags.map((e, i) => (

{e.name}

))}
{link.description && ( <>
{link.description}
)}

Archived Formats:

{formattedDate}

Screenshot

handleDownload("png")} className="cursor-pointer hover:bg-sky-100 duration-100 p-2 rounded-md" >

PDF

handleDownload("pdf")} className="cursor-pointer hover:bg-sky-100 duration-100 p-2 rounded-md" >
); }