"use client" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { BASE_URL, REPO_PATH } from "@/constants" import type { AuthorData, Icon } from "@/types/icons" import confetti from "canvas-confetti" import { motion } from "framer-motion" import { Check, Copy, Download, FileType, Github, Moon, PaletteIcon, Sun } from "lucide-react" import { useTheme } from "next-themes" import Image from "next/image" import Link from "next/link" import { useCallback, useState } from "react" import { toast } from "sonner" import { Carbon } from "./carbon" import { MagicCard } from "./magicui/magic-card" import { Badge } from "./ui/badge" export type IconDetailsProps = { icon: string iconData: Icon authorData: AuthorData } export function IconDetails({ icon, iconData, authorData }: IconDetailsProps) { const authorName = authorData.name || authorData.login || "" const iconColorVariants = iconData.colors const formattedDate = new Date(iconData.update.timestamp).toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric", }) const getAvailableFormats = () => { switch (iconData.base) { case "svg": return ["svg", "png", "webp"] case "png": return ["png", "webp"] default: return [iconData.base] } } const availableFormats = getAvailableFormats() const [copiedVariants, setCopiedVariants] = useState>({}) // Launch confetti from the pointer position const launchConfetti = useCallback((originX?: number, originY?: number) => { const defaults = { startVelocity: 15, spread: 180, ticks: 50, zIndex: 20, disableForReducedMotion: true, colors: ["#ff0a54", "#ff477e", "#ff7096", "#ff85a1", "#fbb1bd", "#f9bec7"], } // If we have origin coordinates, use them if (originX !== undefined && originY !== undefined) { confetti({ ...defaults, particleCount: 50, origin: { x: originX / window.innerWidth, y: originY / window.innerHeight, }, }) } else { // Default to center of screen confetti({ ...defaults, particleCount: 50, origin: { x: 0.5, y: 0.5 }, }) } }, []) const handleCopy = (url: string, variantKey: string, event?: React.MouseEvent) => { navigator.clipboard.writeText(url) setCopiedVariants((prev) => ({ ...prev, [variantKey]: true, })) setTimeout(() => { setCopiedVariants((prev) => ({ ...prev, [variantKey]: false, })) }, 2000) // Launch confetti from click position or center of screen if (event) { launchConfetti(event.clientX, event.clientY) } else { launchConfetti() } toast.success("URL copied", { description: "The icon URL has been copied to your clipboard. Ready to use!", }) } const handleDownload = async (event: React.MouseEvent, url: string, filename: string) => { event.preventDefault() // Launch confetti from download button position launchConfetti(event.clientX, event.clientY) try { // Show loading toast toast.loading("Preparing download...") // Fetch the file first as a blob const response = await fetch(url) const blob = await response.blob() // Create a blob URL and use it for download const blobUrl = URL.createObjectURL(blob) const link = document.createElement("a") link.href = blobUrl link.download = filename document.body.appendChild(link) link.click() // Clean up document.body.removeChild(link) setTimeout(() => URL.revokeObjectURL(blobUrl), 100) toast.dismiss() toast.success("Download started", { description: "Your icon file is being downloaded and will be saved to your device.", }) } catch (error) { console.error("Download error:", error) toast.dismiss() toast.error("Download failed", { description: "There was an error downloading the file. Please try again.", }) } } const renderVariant = (format: string, iconName: string, theme?: "light" | "dark") => { const variantName = theme && iconColorVariants?.[theme] ? iconColorVariants[theme] : iconName const imageUrl = `${BASE_URL}/${format}/${variantName}.${format}` const githubUrl = `${REPO_PATH}/tree/main/${format}/${iconName}.${format}` const variantKey = `${format}-${theme || "default"}` const isCopied = copiedVariants[variantKey] || false return (
handleCopy(imageUrl, variantKey, e)} >
{`${iconName}

Click to copy direct URL to clipboard

{format.toUpperCase()}

Download icon file

Copy direct URL to clipboard

View on GitHub

) } return (
{/* Left Column: Icon Info and Author */}
{icon}
{icon}

Updated on: {formattedDate}

By:

{authorName ? authorName.slice(0, 2).toUpperCase() : "??"} {authorData.html_url ? ( {authorName} ) : ( {authorName} )}
{iconData.categories && iconData.categories.length > 0 && (

Categories

{iconData.categories.map((category) => ( {category .split("-") .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(" ")} ))}
)} {iconData.aliases && iconData.aliases.length > 0 && (

Aliases

{iconData.aliases.map((alias) => ( {alias} ))}
)}

About this icon

Available in{" "} {availableFormats.length > 1 ? `${availableFormats.length} formats (${availableFormats.map((f) => f.toUpperCase()).join(", ")})` : `${availableFormats[0].toUpperCase()} format`}{" "} with a base format of {iconData.base.toUpperCase()}. {iconData.colors && " Includes both light and dark theme variants for better integration with different UI designs."}

Use the {icon} icon in your web applications, dashboards, or documentation to enhance visual communication and user experience.

{/* Middle Column: Icon variants */}
Icon variants Click on any icon to copy its URL to your clipboard {!iconData.colors ? (
{availableFormats.map((format) => renderVariant(format, icon))}
) : (

Light theme

{availableFormats.map((format) => renderVariant(format, icon, "light"))}

Dark theme

{availableFormats.map((format) => renderVariant(format, icon, "dark"))}
)}
{/* Right Column: Technical details */}
Technical details

Base format

{iconData.base.toUpperCase()}

Available formats

{availableFormats.map((format) => (
{format.toUpperCase()}
))}
{iconData.colors && (

Color variants

{Object.entries(iconData.colors).map(([theme, variant]) => (
{theme}: {variant}
))}
)}

Source

) }