mirror of
				https://github.com/walkxcode/dashboard-icons.git
				synced 2025-10-31 08:47:57 +01:00 
			
		
		
		
	chore: Run Biome checks and apply fixes
This commit is contained in:
		| @@ -31,9 +31,7 @@ export default function ErrorPage({ | ||||
| 					<AlertTriangle className="w-8 h-8" /> | ||||
| 				</div> | ||||
| 				<h1 className="text-2xl font-bold">Something went wrong</h1> | ||||
| 				<p className="text-muted-foreground"> | ||||
| 					Unable to load this page. We're looking into the issue. | ||||
| 				</p> | ||||
| 				<p className="text-muted-foreground">Unable to load this page. We're looking into the issue.</p> | ||||
| 				<div className="flex flex-col sm:flex-row gap-4 justify-center pt-4"> | ||||
| 					<Button variant="outline" onClick={() => reset()} className="cursor-pointer"> | ||||
| 						<RefreshCcw className="mr-2 h-4 w-4" /> | ||||
|   | ||||
| @@ -4,280 +4,280 @@ import { ImageResponse } from "next/og" | ||||
| export const dynamic = "force-static" | ||||
|  | ||||
| export const size = { | ||||
|   width: 1200, | ||||
|   height: 630, | ||||
| 	width: 1200, | ||||
| 	height: 630, | ||||
| } | ||||
|  | ||||
| // Define a fixed list of representative icons | ||||
| const representativeIcons = [ | ||||
|   "github", | ||||
|   "discord", | ||||
|   "slack", | ||||
|   "docker", | ||||
|   "kubernetes", | ||||
|   "grafana", | ||||
|   "prometheus", | ||||
|   "nextcloud", | ||||
|   "homeassistant", | ||||
|   "cloudflare", | ||||
|   "nginx", | ||||
|   "traefik", | ||||
|   "portainer", | ||||
|   "plex", | ||||
|   "jellyfin", | ||||
| 	"github", | ||||
| 	"discord", | ||||
| 	"slack", | ||||
| 	"docker", | ||||
| 	"kubernetes", | ||||
| 	"grafana", | ||||
| 	"prometheus", | ||||
| 	"nextcloud", | ||||
| 	"homeassistant", | ||||
| 	"cloudflare", | ||||
| 	"nginx", | ||||
| 	"traefik", | ||||
| 	"portainer", | ||||
| 	"plex", | ||||
| 	"jellyfin", | ||||
| ] | ||||
|  | ||||
| export default async function Image() { | ||||
|   const iconsData = await getAllIcons() | ||||
|   const totalIcons = Object.keys(iconsData).length | ||||
|   // Round down to the nearest 100 | ||||
|   const roundedTotalIcons = Math.floor(totalIcons / 100) * 100 | ||||
| 	const iconsData = await getAllIcons() | ||||
| 	const totalIcons = Object.keys(iconsData).length | ||||
| 	// Round down to the nearest 100 | ||||
| 	const roundedTotalIcons = Math.floor(totalIcons / 100) * 100 | ||||
|  | ||||
|   const iconImages = representativeIcons.map((icon) => ({ | ||||
|     name: icon | ||||
|       .split("-") | ||||
|       .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) | ||||
|       .join(" "), | ||||
|     url: `https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/${icon}.png`, | ||||
|   })) | ||||
| 	const iconImages = representativeIcons.map((icon) => ({ | ||||
| 		name: icon | ||||
| 			.split("-") | ||||
| 			.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) | ||||
| 			.join(" "), | ||||
| 		url: `https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/${icon}.png`, | ||||
| 	})) | ||||
|  | ||||
|   return new ImageResponse( | ||||
|     <div | ||||
|       style={{ | ||||
|         display: "flex", | ||||
|         width: "100%", | ||||
|         height: "100%", | ||||
|         position: "relative", | ||||
|         fontFamily: "Inter, system-ui, sans-serif", | ||||
|         overflow: "hidden", | ||||
|         backgroundColor: "white", | ||||
|         backgroundImage: | ||||
|           "radial-gradient(circle at 25px 25px, lightgray 2%, transparent 0%), radial-gradient(circle at 75px 75px, lightgray 2%, transparent 0%)", | ||||
|         backgroundSize: "100px 100px", | ||||
|       }} | ||||
|     > | ||||
|       <div | ||||
|         style={{ | ||||
|           position: "absolute", | ||||
| 	return new ImageResponse( | ||||
| 		<div | ||||
| 			style={{ | ||||
| 				display: "flex", | ||||
| 				width: "100%", | ||||
| 				height: "100%", | ||||
| 				position: "relative", | ||||
| 				fontFamily: "Inter, system-ui, sans-serif", | ||||
| 				overflow: "hidden", | ||||
| 				backgroundColor: "white", | ||||
| 				backgroundImage: | ||||
| 					"radial-gradient(circle at 25px 25px, lightgray 2%, transparent 0%), radial-gradient(circle at 75px 75px, lightgray 2%, transparent 0%)", | ||||
| 				backgroundSize: "100px 100px", | ||||
| 			}} | ||||
| 		> | ||||
| 			<div | ||||
| 				style={{ | ||||
| 					position: "absolute", | ||||
| 					display: "flex", | ||||
|           top: -100, | ||||
|           left: -100, | ||||
|           width: 400, | ||||
|           height: 400, | ||||
|           borderRadius: "50%", | ||||
|           background: "linear-gradient(135deg, rgba(56, 189, 248, 0.1) 0%, rgba(59, 130, 246, 0.1) 100%)", | ||||
|           filter: "blur(80px)", | ||||
|           zIndex: 2, | ||||
|         }} | ||||
|       /> | ||||
|       <div | ||||
|         style={{ | ||||
|           position: "absolute", | ||||
|           display: "flex", | ||||
|           bottom: -150, | ||||
|           right: -150, | ||||
|           width: 500, | ||||
|           height: 500, | ||||
|           borderRadius: "50%", | ||||
|           background: "linear-gradient(135deg, rgba(249, 115, 22, 0.1) 0%, rgba(234, 88, 12, 0.1) 100%)", | ||||
|           filter: "blur(100px)", | ||||
|           zIndex: 2, | ||||
|         }} | ||||
|       /> | ||||
| 					top: -100, | ||||
| 					left: -100, | ||||
| 					width: 400, | ||||
| 					height: 400, | ||||
| 					borderRadius: "50%", | ||||
| 					background: "linear-gradient(135deg, rgba(56, 189, 248, 0.1) 0%, rgba(59, 130, 246, 0.1) 100%)", | ||||
| 					filter: "blur(80px)", | ||||
| 					zIndex: 2, | ||||
| 				}} | ||||
| 			/> | ||||
| 			<div | ||||
| 				style={{ | ||||
| 					position: "absolute", | ||||
| 					display: "flex", | ||||
| 					bottom: -150, | ||||
| 					right: -150, | ||||
| 					width: 500, | ||||
| 					height: 500, | ||||
| 					borderRadius: "50%", | ||||
| 					background: "linear-gradient(135deg, rgba(249, 115, 22, 0.1) 0%, rgba(234, 88, 12, 0.1) 100%)", | ||||
| 					filter: "blur(100px)", | ||||
| 					zIndex: 2, | ||||
| 				}} | ||||
| 			/> | ||||
|  | ||||
|       <div | ||||
|         style={{ | ||||
|           display: "flex", | ||||
|           flexDirection: "column", | ||||
|           alignItems: "center", | ||||
|           justifyContent: "center", | ||||
|           width: "100%", | ||||
|           height: "100%", | ||||
|           padding: "50px", | ||||
|           zIndex: 10, | ||||
|           gap: "30px", | ||||
|         }} | ||||
|       > | ||||
|         <div | ||||
|           style={{ | ||||
|             display: "flex", | ||||
|             flexDirection: "column", | ||||
|             alignItems: "center", | ||||
|             gap: "16px", | ||||
|             marginBottom: "10px", | ||||
|           }} | ||||
|         > | ||||
|           <div | ||||
|             style={{ | ||||
|               fontSize: 64, | ||||
|               display: "flex", | ||||
|               fontWeight: 800, | ||||
| 			<div | ||||
| 				style={{ | ||||
| 					display: "flex", | ||||
| 					flexDirection: "column", | ||||
| 					alignItems: "center", | ||||
| 					justifyContent: "center", | ||||
| 					width: "100%", | ||||
| 					height: "100%", | ||||
| 					padding: "50px", | ||||
| 					zIndex: 10, | ||||
| 					gap: "30px", | ||||
| 				}} | ||||
| 			> | ||||
| 				<div | ||||
| 					style={{ | ||||
| 						display: "flex", | ||||
| 						flexDirection: "column", | ||||
| 						alignItems: "center", | ||||
| 						gap: "16px", | ||||
| 						marginBottom: "10px", | ||||
| 					}} | ||||
| 				> | ||||
| 					<div | ||||
| 						style={{ | ||||
| 							fontSize: 64, | ||||
| 							display: "flex", | ||||
| 							fontWeight: 800, | ||||
| 							fontFamily: "monospace", | ||||
|               color: "#0f172a", | ||||
|               lineHeight: 1.1, | ||||
|               textAlign: "center", | ||||
|             }} | ||||
|           > | ||||
|             Dashboard Icons | ||||
|           </div> | ||||
|           <div | ||||
|             style={{ | ||||
|               fontSize: 28, | ||||
|               display: "flex", | ||||
|               fontWeight: 500, | ||||
|               color: "#64748b", | ||||
|               lineHeight: 1.4, | ||||
|               textAlign: "center", | ||||
|               maxWidth: 1100, | ||||
|             }} | ||||
|           > | ||||
|             A curated collection of {roundedTotalIcons}+ free icons for dashboards and app directories | ||||
|           </div> | ||||
|         </div> | ||||
| 							color: "#0f172a", | ||||
| 							lineHeight: 1.1, | ||||
| 							textAlign: "center", | ||||
| 						}} | ||||
| 					> | ||||
| 						Dashboard Icons | ||||
| 					</div> | ||||
| 					<div | ||||
| 						style={{ | ||||
| 							fontSize: 28, | ||||
| 							display: "flex", | ||||
| 							fontWeight: 500, | ||||
| 							color: "#64748b", | ||||
| 							lineHeight: 1.4, | ||||
| 							textAlign: "center", | ||||
| 							maxWidth: 1100, | ||||
| 						}} | ||||
| 					> | ||||
| 						A curated collection of {roundedTotalIcons}+ free icons for dashboards and app directories | ||||
| 					</div> | ||||
| 				</div> | ||||
|  | ||||
|         <div | ||||
|           style={{ | ||||
|             display: "flex", | ||||
|             flexDirection: "row", | ||||
|             flexWrap: "wrap", | ||||
|             justifyContent: "center", | ||||
|             gap: "20px", | ||||
|             width: "1100px", | ||||
|             margin: "0 auto", | ||||
|           }} | ||||
|         > | ||||
|           {iconImages.map((icon, index) => ( | ||||
|             <div | ||||
|               key={index} | ||||
|               style={{ | ||||
|                 display: "flex", | ||||
|                 flexDirection: "column", | ||||
|                 alignItems: "center", | ||||
|                 justifyContent: "center", | ||||
|                 background: "white", | ||||
|                 borderRadius: 16, | ||||
|                 boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05)", | ||||
|                 padding: "20px", | ||||
|                 position: "relative", | ||||
|                 overflow: "hidden", | ||||
|                 width: "120px", | ||||
|                 height: "75px", | ||||
|                 margin: "0", | ||||
|               }} | ||||
|             > | ||||
|               <div | ||||
|                 style={{ | ||||
|                   display: "flex", | ||||
|                   position: "absolute", | ||||
|                   inset: 0, | ||||
|                   background: "linear-gradient(145deg, #ffffff 0%, #f8fafc 100%)", | ||||
|                   zIndex: 0, | ||||
|                 }} | ||||
|               /> | ||||
|               <img | ||||
|                 src={icon.url} | ||||
|                 alt={icon.name} | ||||
|                 width={50} | ||||
|                 height={50} | ||||
|                 style={{ | ||||
|                   objectFit: "contain", | ||||
|                   position: "relative", | ||||
|                   zIndex: 1, | ||||
|                   filter: "drop-shadow(0 5px 10px rgba(0, 0, 0, 0.1))", | ||||
|                 }} | ||||
|               /> | ||||
|             </div> | ||||
|           ))} | ||||
|           <div | ||||
|             style={{ | ||||
|               display: "flex", | ||||
|               flexDirection: "column", | ||||
|               alignItems: "center", | ||||
|               justifyContent: "center", | ||||
|               background: "white", | ||||
|               borderRadius: 16, | ||||
|               boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05)", | ||||
|               padding: "20px", | ||||
|               position: "relative", | ||||
|               overflow: "hidden", | ||||
|               width: "120px", | ||||
|               height: "75px", | ||||
|               margin: "0", | ||||
|             }} | ||||
|           > | ||||
|             <div | ||||
|               style={{ | ||||
|                 display: "flex", | ||||
|                 position: "absolute", | ||||
|                 inset: 0, | ||||
|                 background: "linear-gradient(145deg, #ffffff 0%, #f8fafc 100%)", | ||||
|                 zIndex: 0, | ||||
|               }} | ||||
|             /> | ||||
|             <div | ||||
|               style={{ | ||||
|                 display: "flex", | ||||
|                 fontSize: 20, | ||||
|                 fontWeight: 600, | ||||
|                 color: "#64748b", | ||||
|                 zIndex: 1, | ||||
|               }} | ||||
|             > | ||||
|               +{totalIcons - representativeIcons.length} | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
| 				<div | ||||
| 					style={{ | ||||
| 						display: "flex", | ||||
| 						flexDirection: "row", | ||||
| 						flexWrap: "wrap", | ||||
| 						justifyContent: "center", | ||||
| 						gap: "20px", | ||||
| 						width: "1100px", | ||||
| 						margin: "0 auto", | ||||
| 					}} | ||||
| 				> | ||||
| 					{iconImages.map((icon, index) => ( | ||||
| 						<div | ||||
| 							key={index} | ||||
| 							style={{ | ||||
| 								display: "flex", | ||||
| 								flexDirection: "column", | ||||
| 								alignItems: "center", | ||||
| 								justifyContent: "center", | ||||
| 								background: "white", | ||||
| 								borderRadius: 16, | ||||
| 								boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05)", | ||||
| 								padding: "20px", | ||||
| 								position: "relative", | ||||
| 								overflow: "hidden", | ||||
| 								width: "120px", | ||||
| 								height: "75px", | ||||
| 								margin: "0", | ||||
| 							}} | ||||
| 						> | ||||
| 							<div | ||||
| 								style={{ | ||||
| 									display: "flex", | ||||
| 									position: "absolute", | ||||
| 									inset: 0, | ||||
| 									background: "linear-gradient(145deg, #ffffff 0%, #f8fafc 100%)", | ||||
| 									zIndex: 0, | ||||
| 								}} | ||||
| 							/> | ||||
| 							<img | ||||
| 								src={icon.url} | ||||
| 								alt={icon.name} | ||||
| 								width={50} | ||||
| 								height={50} | ||||
| 								style={{ | ||||
| 									objectFit: "contain", | ||||
| 									position: "relative", | ||||
| 									zIndex: 1, | ||||
| 									filter: "drop-shadow(0 5px 10px rgba(0, 0, 0, 0.1))", | ||||
| 								}} | ||||
| 							/> | ||||
| 						</div> | ||||
| 					))} | ||||
| 					<div | ||||
| 						style={{ | ||||
| 							display: "flex", | ||||
| 							flexDirection: "column", | ||||
| 							alignItems: "center", | ||||
| 							justifyContent: "center", | ||||
| 							background: "white", | ||||
| 							borderRadius: 16, | ||||
| 							boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05)", | ||||
| 							padding: "20px", | ||||
| 							position: "relative", | ||||
| 							overflow: "hidden", | ||||
| 							width: "120px", | ||||
| 							height: "75px", | ||||
| 							margin: "0", | ||||
| 						}} | ||||
| 					> | ||||
| 						<div | ||||
| 							style={{ | ||||
| 								display: "flex", | ||||
| 								position: "absolute", | ||||
| 								inset: 0, | ||||
| 								background: "linear-gradient(145deg, #ffffff 0%, #f8fafc 100%)", | ||||
| 								zIndex: 0, | ||||
| 							}} | ||||
| 						/> | ||||
| 						<div | ||||
| 							style={{ | ||||
| 								display: "flex", | ||||
| 								fontSize: 20, | ||||
| 								fontWeight: 600, | ||||
| 								color: "#64748b", | ||||
| 								zIndex: 1, | ||||
| 							}} | ||||
| 						> | ||||
| 							+{totalIcons - representativeIcons.length} | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</div> | ||||
|  | ||||
|         <div | ||||
|           style={{ | ||||
|             display: "flex", | ||||
|             gap: 16, | ||||
|             marginTop: 10, | ||||
|           }} | ||||
|         /> | ||||
|       </div> | ||||
| 				<div | ||||
| 					style={{ | ||||
| 						display: "flex", | ||||
| 						gap: 16, | ||||
| 						marginTop: 10, | ||||
| 					}} | ||||
| 				/> | ||||
| 			</div> | ||||
|  | ||||
|       <div | ||||
|         style={{ | ||||
|           position: "absolute", | ||||
|           bottom: 0, | ||||
|           left: 0, | ||||
|           right: 0, | ||||
|           height: 80, | ||||
|           display: "flex", | ||||
|           alignItems: "center", | ||||
|           justifyContent: "center", | ||||
|           background: "#ffffff", | ||||
|           borderTop: "2px solid rgba(0, 0, 0, 0.05)", | ||||
|           zIndex: 20, | ||||
|         }} | ||||
|       > | ||||
|         <div | ||||
|           style={{ | ||||
|             display: "flex", | ||||
|             fontSize: 24, | ||||
|             fontWeight: 600, | ||||
|             color: "#334155", | ||||
|             alignItems: "center", | ||||
|             gap: 10, | ||||
|           }} | ||||
|         > | ||||
|           <div | ||||
|             style={{ | ||||
|               display: "flex", | ||||
|               width: 8, | ||||
|               height: 8, | ||||
|               borderRadius: "50%", | ||||
|               backgroundColor: "#3b82f6", | ||||
|               marginRight: 4, | ||||
|             }} | ||||
|           /> | ||||
|           dashboardicons.com | ||||
|         </div> | ||||
|       </div> | ||||
|     </div>, | ||||
|     { | ||||
|       ...size, | ||||
|     }, | ||||
|   ) | ||||
| 			<div | ||||
| 				style={{ | ||||
| 					position: "absolute", | ||||
| 					bottom: 0, | ||||
| 					left: 0, | ||||
| 					right: 0, | ||||
| 					height: 80, | ||||
| 					display: "flex", | ||||
| 					alignItems: "center", | ||||
| 					justifyContent: "center", | ||||
| 					background: "#ffffff", | ||||
| 					borderTop: "2px solid rgba(0, 0, 0, 0.05)", | ||||
| 					zIndex: 20, | ||||
| 				}} | ||||
| 			> | ||||
| 				<div | ||||
| 					style={{ | ||||
| 						display: "flex", | ||||
| 						fontSize: 24, | ||||
| 						fontWeight: 600, | ||||
| 						color: "#334155", | ||||
| 						alignItems: "center", | ||||
| 						gap: 10, | ||||
| 					}} | ||||
| 				> | ||||
| 					<div | ||||
| 						style={{ | ||||
| 							display: "flex", | ||||
| 							width: 8, | ||||
| 							height: 8, | ||||
| 							borderRadius: "50%", | ||||
| 							backgroundColor: "#3b82f6", | ||||
| 							marginRight: 4, | ||||
| 						}} | ||||
| 					/> | ||||
| 					dashboardicons.com | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div>, | ||||
| 		{ | ||||
| 			...size, | ||||
| 		}, | ||||
| 	) | ||||
| } | ||||
|   | ||||
| @@ -16,9 +16,7 @@ export default function NotFound({ | ||||
| 						<AlertTriangle className="w-8 h-8" /> | ||||
| 					</div> | ||||
| 					<h1 className="text-2xl sm:text-3xl font-bold mt-6">Not found</h1> | ||||
| 					<p className="text-muted-foreground mt-3 max-w-md"> | ||||
| 						This icon does not exist or could not be loaded. | ||||
| 					</p> | ||||
| 					<p className="text-muted-foreground mt-3 max-w-md">This icon does not exist or could not be loaded.</p> | ||||
| 				</div> | ||||
|  | ||||
| 				<div className="flex flex-col sm:flex-row gap-4 justify-center"> | ||||
| @@ -33,9 +31,7 @@ export default function NotFound({ | ||||
| 				<div className="border-t border-border pt-8 mt-8"> | ||||
| 					<div className="text-center mb-6"> | ||||
| 						<h2 className="text-xl font-semibold">Missing an icon?</h2> | ||||
| 						<p className="text-muted-foreground mt-2"> | ||||
| 							Submit a new icon or suggest improvements to our collection. | ||||
| 						</p> | ||||
| 						<p className="text-muted-foreground mt-2">Submit a new icon or suggest improvements to our collection.</p> | ||||
| 					</div> | ||||
|  | ||||
| 					<div className="mt-6"> | ||||
|   | ||||
| @@ -216,19 +216,19 @@ export function HeroSection({ totalIcons, stars }: { totalIcons: number; stars: | ||||
| 							transition={{ | ||||
| 								duration: 0.5, | ||||
| 								delay: 0.3, | ||||
| 								ease: "easeOut" | ||||
| 								ease: "easeOut", | ||||
| 							}} | ||||
| 						> | ||||
| 							<motion.div | ||||
| 								animate={{ | ||||
| 									y: [0, -3, 0], | ||||
| 									rotate: [0, 5, 0] | ||||
| 									rotate: [0, 5, 0], | ||||
| 								}} | ||||
| 								transition={{ | ||||
| 									duration: 3, | ||||
| 									repeat: Infinity, | ||||
| 									repeat: Number.POSITIVE_INFINITY, | ||||
| 									repeatType: "reverse", | ||||
| 									ease: "easeInOut" | ||||
| 									ease: "easeInOut", | ||||
| 								}} | ||||
| 							> | ||||
| 								<Sparkles className="text-rose-500 h-8 w-8 sm:h-12 sm:w-12 md:h-16 md:w-12" /> | ||||
| @@ -242,19 +242,19 @@ export function HeroSection({ totalIcons, stars }: { totalIcons: number; stars: | ||||
| 							transition={{ | ||||
| 								duration: 0.5, | ||||
| 								delay: 0.3, | ||||
| 								ease: "easeOut" | ||||
| 								ease: "easeOut", | ||||
| 							}} | ||||
| 						> | ||||
| 							<motion.div | ||||
| 								animate={{ | ||||
| 									y: [0, -3, 0], | ||||
| 									rotate: [0, -5, 0] | ||||
| 									rotate: [0, -5, 0], | ||||
| 								}} | ||||
| 								transition={{ | ||||
| 									duration: 4, | ||||
| 									repeat: Infinity, | ||||
| 									repeat: Number.POSITIVE_INFINITY, | ||||
| 									repeatType: "reverse", | ||||
| 									ease: "easeInOut" | ||||
| 									ease: "easeInOut", | ||||
| 								}} | ||||
| 							> | ||||
| 								<Sparkles className="text-rose-500 h-5 w-5 sm:h-8 sm:w-8 md:h-12 md:w-12" /> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import { BASE_URL, REPO_PATH } from "@/constants" | ||||
| import type { AuthorData, Icon, IconFile } from "@/types/icons" | ||||
| import confetti from "canvas-confetti" | ||||
| import { motion } from "framer-motion" | ||||
| import { Check, Copy, Download, FileType, Github, Moon, PaletteIcon, Sun, ArrowRight } from "lucide-react" | ||||
| import { ArrowRight, Check, Copy, Download, FileType, Github, Moon, PaletteIcon, Sun } from "lucide-react" | ||||
| import Image from "next/image" | ||||
| import Link from "next/link" | ||||
| import { useCallback, useState } from "react" | ||||
| @@ -238,12 +238,7 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail | ||||
|  | ||||
| 							<Tooltip> | ||||
| 								<TooltipTrigger asChild> | ||||
| 									<Button | ||||
| 										variant="outline" | ||||
| 										size="icon" | ||||
| 										className="h-8 w-8 rounded-lg" | ||||
| 										asChild | ||||
| 									> | ||||
| 									<Button variant="outline" size="icon" className="h-8 w-8 rounded-lg" asChild> | ||||
| 										<Link | ||||
| 											href={githubUrl} | ||||
| 											target="_blank" | ||||
| @@ -363,14 +358,16 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail | ||||
| 									<h3 className="text-sm font-semibold text-muted-foreground mb-2">About this icon</h3> | ||||
| 									<div className="text-xs text-muted-foreground space-y-2"> | ||||
| 										<p> | ||||
| 											Available in {availableFormats.length > 1 | ||||
| 											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."} | ||||
| 										</p> | ||||
| 										<p> | ||||
| 											Perfect for adding to dashboards, app directories, documentation, or anywhere you need the {icon.replace(/-/g, " ")} logo. | ||||
| 											Perfect for adding to dashboards, app directories, documentation, or anywhere you need the {icon.replace(/-/g, " ")}{" "} | ||||
| 											logo. | ||||
| 										</p> | ||||
| 									</div> | ||||
| 								</div> | ||||
| @@ -476,57 +473,63 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail | ||||
| 					</Card> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			{iconData.categories && iconData.categories.length > 0 && (() => { | ||||
| 				const MAX_RELATED_ICONS = 16 | ||||
| 				const currentCategories = iconData.categories || [] | ||||
| 			{iconData.categories && | ||||
| 				iconData.categories.length > 0 && | ||||
| 				(() => { | ||||
| 					const MAX_RELATED_ICONS = 16 | ||||
| 					const currentCategories = iconData.categories || [] | ||||
|  | ||||
| 				const relatedIconsWithScore = Object.entries(allIcons) | ||||
| 					.map(([name, data]) => { | ||||
| 						if (name === icon) return null // Exclude the current icon | ||||
| 					const relatedIconsWithScore = Object.entries(allIcons) | ||||
| 						.map(([name, data]) => { | ||||
| 							if (name === icon) return null // Exclude the current icon | ||||
|  | ||||
| 						const otherCategories = data.categories || [] | ||||
| 						const commonCategories = currentCategories.filter((cat) => otherCategories.includes(cat)) | ||||
| 						const score = commonCategories.length | ||||
| 							const otherCategories = data.categories || [] | ||||
| 							const commonCategories = currentCategories.filter((cat) => otherCategories.includes(cat)) | ||||
| 							const score = commonCategories.length | ||||
|  | ||||
| 						return score > 0 ? { name, data, score } : null | ||||
| 					}) | ||||
| 					.filter((item): item is { name: string; data: Icon; score: number } => item !== null) // Type guard | ||||
| 					.sort((a, b) => b.score - a.score) // Sort by score DESC | ||||
| 							return score > 0 ? { name, data, score } : null | ||||
| 						}) | ||||
| 						.filter((item): item is { name: string; data: Icon; score: number } => item !== null) // Type guard | ||||
| 						.sort((a, b) => b.score - a.score) // Sort by score DESC | ||||
|  | ||||
| 				const topRelatedIcons = relatedIconsWithScore.slice(0, MAX_RELATED_ICONS) | ||||
| 					const topRelatedIcons = relatedIconsWithScore.slice(0, MAX_RELATED_ICONS) | ||||
|  | ||||
| 				const viewMoreUrl = `/icons?${currentCategories.map((cat) => `category=${encodeURIComponent(cat)}`).join("&")}` | ||||
| 					const viewMoreUrl = `/icons?${currentCategories.map((cat) => `category=${encodeURIComponent(cat)}`).join("&")}` | ||||
|  | ||||
| 				if (topRelatedIcons.length === 0) return null | ||||
| 					if (topRelatedIcons.length === 0) return null | ||||
|  | ||||
| 				return ( | ||||
| 					<section className="container mx-auto mt-12" aria-labelledby="related-icons-title"> | ||||
| 						<Card className="bg-background/50 border shadow-lg"> | ||||
| 							<CardHeader> | ||||
| 								<CardTitle> | ||||
| 									<h2 id="related-icons-title">Related Icons</h2> | ||||
| 								</CardTitle> | ||||
| 								<CardDescription> | ||||
| 									Other icons from {currentCategories.map((cat) => cat.replace(/-/g, " ")).join(", ")} categories | ||||
| 								</CardDescription> | ||||
| 							</CardHeader> | ||||
| 							<CardContent> | ||||
| 								<IconsGrid filteredIcons={topRelatedIcons} matchedAliases={{}} /> | ||||
| 								{relatedIconsWithScore.length > MAX_RELATED_ICONS && ( | ||||
| 									<div className="mt-6 text-center"> | ||||
| 										<Button asChild variant="link" className="text-muted-foreground hover:text-primary transition-colors duration-200 hover:no-underline"> | ||||
| 											<Link href={viewMoreUrl} className="no-underline"> | ||||
| 												View all related icons | ||||
| 												<ArrowRight className="ml-2 h-4 w-4" /> | ||||
| 											</Link> | ||||
| 										</Button> | ||||
| 									</div> | ||||
| 								)} | ||||
| 							</CardContent> | ||||
| 						</Card> | ||||
| 					</section> | ||||
| 				) | ||||
| 			})()} | ||||
| 					return ( | ||||
| 						<section className="container mx-auto mt-12" aria-labelledby="related-icons-title"> | ||||
| 							<Card className="bg-background/50 border shadow-lg"> | ||||
| 								<CardHeader> | ||||
| 									<CardTitle> | ||||
| 										<h2 id="related-icons-title">Related Icons</h2> | ||||
| 									</CardTitle> | ||||
| 									<CardDescription> | ||||
| 										Other icons from {currentCategories.map((cat) => cat.replace(/-/g, " ")).join(", ")} categories | ||||
| 									</CardDescription> | ||||
| 								</CardHeader> | ||||
| 								<CardContent> | ||||
| 									<IconsGrid filteredIcons={topRelatedIcons} matchedAliases={{}} /> | ||||
| 									{relatedIconsWithScore.length > MAX_RELATED_ICONS && ( | ||||
| 										<div className="mt-6 text-center"> | ||||
| 											<Button | ||||
| 												asChild | ||||
| 												variant="link" | ||||
| 												className="text-muted-foreground hover:text-primary transition-colors duration-200 hover:no-underline" | ||||
| 											> | ||||
| 												<Link href={viewMoreUrl} className="no-underline"> | ||||
| 													View all related icons | ||||
| 													<ArrowRight className="ml-2 h-4 w-4" /> | ||||
| 												</Link> | ||||
| 											</Button> | ||||
| 										</div> | ||||
| 									)} | ||||
| 								</CardContent> | ||||
| 							</Card> | ||||
| 						</section> | ||||
| 					) | ||||
| 				})()} | ||||
| 		</div> | ||||
| 	) | ||||
| } | ||||
|   | ||||
| @@ -25,7 +25,7 @@ export function VirtualizedIconsGrid({ filteredIcons, matchedAliases }: IconsGri | ||||
|  | ||||
| 	useEffect(() => { | ||||
| 		setWindowWidth(window.innerWidth) | ||||
| 		 | ||||
|  | ||||
| 		const handleResize = () => { | ||||
| 			setWindowWidth(window.innerWidth) | ||||
| 		} | ||||
|   | ||||
| @@ -335,10 +335,12 @@ export function IconSearch({ icons }: IconSearchProps) { | ||||
| 									Relevance | ||||
| 								</DropdownMenuRadioItem> | ||||
| 								<DropdownMenuRadioItem value="alphabetical-asc" className="cursor-pointer"> | ||||
| 									<ArrowDownAZ className="h-4 w-4 mr-2" />Name (A-Z) | ||||
| 									<ArrowDownAZ className="h-4 w-4 mr-2" /> | ||||
| 									Name (A-Z) | ||||
| 								</DropdownMenuRadioItem> | ||||
| 								<DropdownMenuRadioItem value="alphabetical-desc" className="cursor-pointer"> | ||||
| 									<ArrowUpZA className="h-4 w-4 mr-2" />Name (Z-A) | ||||
| 									<ArrowUpZA className="h-4 w-4 mr-2" /> | ||||
| 									Name (Z-A) | ||||
| 								</DropdownMenuRadioItem> | ||||
| 								<DropdownMenuRadioItem value="newest" className="cursor-pointer"> | ||||
| 									<Calendar className="h-4 w-4 mr-2" /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user