import React, { useRef, useEffect } from "react"; import { useRecoilValue, useSetRecoilState } from "recoil"; import { useHotkeys } from "react-hotkeys-hook"; import { motion } from "framer-motion"; import { Svg2Png } from "svg2png-converter"; import { saveAs } from "file-saver"; import { Copy, X, CheckCircle, Download } from "phosphor-react"; import ReactGA from "react-ga"; import { iconWeightAtom, iconSizeAtom, iconColorAtom, iconPreviewOpenAtom, } from "../../state/atoms"; import useTransientState from "../../hooks/useTransientState"; import TagCloud from "./TagCloud"; import { IconEntry } from "../../lib"; const panelVariants = { open: { opacity: 1, height: "100%", marginTop: "4px", marginBottom: "4px", transition: { type: "tween", duration: 0.1 }, }, collapsed: { opacity: 0, height: "0px", marginTop: "0px", marginBottom: "0px", transition: { type: "tween", duration: 0.1 }, }, }; const contentVariants = { open: { opacity: 1, transition: { duration: 0.2, delay: 0.1 } }, collapsed: { opacity: 0, transition: { duration: 0 } }, }; const buttonColor = "#35313D"; const successColor = "#1FA647"; const disabledColor = "#B7B7B7"; interface InfoPanelProps { index: number; spans: number; isDark: boolean; entry: IconEntry; } const DetailsPanel: React.FC = (props) => { const { index, spans, isDark, entry } = props; const { name, Icon, categories, tags } = entry; const weight = useRecoilValue(iconWeightAtom); const size = useRecoilValue(iconSizeAtom); const color = useRecoilValue(iconColorAtom); const setOpen = useSetRecoilState(iconPreviewOpenAtom); const [copied, setCopied] = useTransientState(false, 2000); const ref = useRef(null); useHotkeys("esc", () => setOpen(false)); useEffect( () => ReactGA.event({ category: "Grid", action: "Details", label: name }), [name] ); const buttonBarStyle: React.CSSProperties = { color: isDark ? "white" : buttonColor, }; const snippetButtonStyle: React.CSSProperties = weight === "duotone" ? { color: disabledColor, userSelect: "none" } : { color: buttonColor }; const snippets = { html: weight === "duotone" ? "This weight is not yet supported" : ``, react: `<${Icon.displayName} size={${size}} ${ color !== "#000000" ? `color="${color}" ` : "" }${weight === "regular" ? "" : `weight="${weight}" `}/>`, vue: ``, flutter: weight === "duotone" ? "This weight is not yet supported" : `Icon(\n PhosphorIcons.${ Icon.displayName!.replace(/^\w/, (c) => c.toLowerCase()) }${weight === "regular" ? "" : weight.replace(/^\w/, (c) => c.toUpperCase()) },\n size: ${size.toFixed(1)},\n color: Color(0xff${ color.replace("#", "") }),\n)`, }; const handleCopySnippet = ( event: React.MouseEvent, type: "html" | "react" | "vue" | "flutter" ) => { event.currentTarget.blur(); setCopied(type); const data = snippets[type]; data && void navigator.clipboard?.writeText(data); }; const handleCopySVG = ( event: React.MouseEvent ) => { event.currentTarget.blur(); setCopied("svg"); ref.current && void navigator.clipboard?.writeText(ref.current.outerHTML); }; const handleDownloadSVG = ( event: React.MouseEvent ) => { event.currentTarget.blur(); if (!ref.current?.outerHTML) return; const blob = new Blob([ref.current.outerHTML]); saveAs(blob, `${name}${weight === "regular" ? "" : `-${weight}`}.svg`); }; const handleDownloadPNG = async ( event: React.MouseEvent ) => { event.currentTarget.blur(); if (!ref.current?.outerHTML) return; Svg2Png.save( ref.current, `${name}${weight === "regular" ? "" : `-${weight}`}.png`, { scaleX: 2.667, scaleY: 2.667 } ); }; return (

{name}

([...categories, ...name.split("-"), ...tags]) )} isDark={isDark} />
React
            {snippets.react}
            
          
Vue
            {snippets.vue}
            
          
HTML/CSS
            {snippets.html}
            
          
Flutter
            {snippets.flutter}
            
          
setOpen(false)} onKeyDown={(e) => { e.key === "Enter" && setOpen(false); }} />
); }; export default DetailsPanel;