ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
1import { useState } from "react";
2import { Globe } from "lucide-react";
3
4interface FaviconIconProps {
5 url: string;
6 alt: string;
7 className?: string;
8 useButtonStyling?: boolean;
9}
10
11export default function FaviconIcon({
12 url,
13 alt,
14 className,
15 useButtonStyling = false,
16}: FaviconIconProps) {
17 const [error, setError] = useState(false);
18 const [loaded, setLoaded] = useState(false);
19
20 // Define the base classes (applied to the image itself)
21 const imageClasses = "w-full h-full object-contain";
22
23 // Define the special button classes conditionally
24 const boundaryClasses = useButtonStyling
25 ? "bg-white p-1 rounded-full shadow-md flex items-center justify-center"
26 : ""; // No special styling by default
27
28 // Combine the passed-in class name (for size) with the conditional boundary classes
29 const finalWrapperClasses = `${className || "w-4 h-4"} ${boundaryClasses}`;
30
31 if (error) {
32 return (
33 <div className={`${finalWrapperClasses}`}>
34 <Globe className={`${imageClasses} text-neutral-500`} />
35 </div>
36 );
37 }
38
39 return (
40 // Use the final combined classes on the wrapper
41 <div className={finalWrapperClasses}>
42 {/* Placeholder while loading */}
43 {!loaded && (
44 <Globe
45 className={`${imageClasses} text-neutral-400 dark:text-neutral-500`}
46 />
47 )}
48
49 {/* The actual image */}
50 <img
51 src={url}
52 alt={`${alt} favicon`}
53 className={imageClasses}
54 style={{ display: loaded ? "block" : "none" }}
55 onLoad={() => {
56 setLoaded(true);
57 setError(false);
58 }}
59 onError={() => {
60 setError(true);
61 }}
62 />
63 </div>
64 );
65}