feat(website): enhance web app support and icon metadata
- Add PWA-compatible icons in multiple sizes: - android-chrome-192x192.png - android-chrome-512x512.png - apple-touch-icon.png - favicon-16x16.png - favicon-32x32.png - Modernize favicon handling: - Update favicon.ico - Remove deprecated favicon.png and favicon.svg - Add site.webmanifest for better PWA integration - Update metadata to reflect total icon count across pages
							
								
								
									
										
											BIN
										
									
								
								web/public/android-chrome-192x192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										
											BIN
										
									
								
								web/public/android-chrome-512x512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 62 KiB | 
							
								
								
									
										
											BIN
										
									
								
								web/public/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										
											BIN
										
									
								
								web/public/favicon-16x16.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 753 B | 
							
								
								
									
										
											BIN
										
									
								
								web/public/favicon-32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
| Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 15 KiB | 
| Before Width: | Height: | Size: 29 KiB | 
| @@ -1 +0,0 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 82.9 512 346.2"><path d="M169.3 102.7c28.8 0 52.2 23.4 52.2 52.2v66.8c1.8-.6 3.6-1 5.5-1 5.9 0 11.1 2.9 14.2 7.4v-73.2c0-39.7-32.3-72-72-72-24.8 0-46.8 12.6-59.7 31.8 5.6 3.6 10.9 7.5 16 11.8 9.4-14.3 25.5-23.8 43.8-23.8m115.6 118.1c1.9 0 3.8.4 5.5 1V155c0-28.8 23.4-52.2 52.2-52.2 18.3 0 34.4 9.5 43.8 23.8 5.1-4.2 10.4-8.2 16-11.8C389.5 95.6 367.5 83 342.7 83c-39.7 0-72 32.3-72 72v73.2c3.1-4.5 8.3-7.4 14.2-7.4m-69.3 104.8c-35.7 8.6-66 28.1-88.1 54-12.2 14.3-21.9 30.6-28.6 48l46.6.3 265.5 1.2v-.1c-29.2-77.8-112.5-123.4-195.4-103.4m11.5-61.9c-9.7 0-17.5 7.8-17.5 17.5s7.8 17.5 17.5 17.5 17.5-7.8 17.5-17.5-7.8-17.5-17.5-17.5m57.8 35.1c9.7 0 17.5-7.8 17.5-17.5s-7.8-17.5-17.5-17.5-17.5 7.8-17.5 17.5 7.8 17.5 17.5 17.5m162.5-75.6 26.7-108.8c-22.6 2.8-43.5 11.1-61.5 23.4-6.3 4.3-12.3 9.2-17.8 14.4-26.4 25.4-42.9 61.1-42.9 100.6 0 30.7 9.9 59.1 26.7 82.1 9.2 12.7 20.6 23.7 33.4 32.6l9.3-37.8c47.9-14.3 84.1-55.7 90.7-106.5zM133.5 334.9c16.8-23 26.7-51.4 26.7-82.1 0-39.5-16.5-75.2-42.9-100.6-5.5-5.3-11.5-10.1-17.8-14.4-17.9-12.3-38.8-20.6-61.5-23.4l26.7 108.8H0c6.6 50.8 42.8 92.2 90.7 106.5l9.3 37.8c12.9-8.9 24.2-19.9 33.5-32.6" style="fill:#fa5252"/></svg> | ||||
| Before Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										1
									
								
								web/public/site.webmanifest
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#FA5252","background_color":"#1B1B1D","display":"standalone"} | ||||
| @@ -30,16 +30,26 @@ export async function generateMetadata({ params, searchParams }: Props, parent: | ||||
| 	const authorData = await getAuthorData(iconsData[icon].update.author.id) | ||||
| 	const authorName = authorData.name || authorData.login | ||||
| 	const updateDate = new Date(iconsData[icon].update.timestamp) | ||||
| 	const totalIcons = Object.keys(iconsData).length | ||||
|  | ||||
| 	console.debug(`Generated metadata for ${icon} by ${authorName} (${authorData.html_url}) updated at ${updateDate.toLocaleString()}`) | ||||
|  | ||||
| 	const iconImageUrl = `${BASE_URL}/png/${icon}.png` | ||||
| 	const pageUrl = `${BASE_URL}/icons/${icon}` | ||||
| 	const formattedIconName = icon.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ') | ||||
|  | ||||
| 	return { | ||||
| 		title: `${icon} icon · Dashboard Icons`, | ||||
| 		description: `Download and use the ${icon} icon from Dashboard Icons for your applications`, | ||||
| 		keywords: [`${icon} icon`, "dashboard icon", "free icon", "open source icon", "application icon"], | ||||
| 		title: `${formattedIconName} Icon | Dashboard Icons`, | ||||
| 		description: `Download the ${formattedIconName} icon in SVG, PNG, and WEBP formats. Part of a collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 		keywords: [ | ||||
| 			`${formattedIconName} icon`, | ||||
| 			"dashboard icon", | ||||
| 			"service icon", | ||||
| 			"application icon", | ||||
| 			"tool icon", | ||||
| 			"web dashboard", | ||||
| 			"app directory", | ||||
| 		], | ||||
| 		authors: [ | ||||
| 			{ | ||||
| 				name: "homarr", | ||||
| @@ -51,8 +61,8 @@ export async function generateMetadata({ params, searchParams }: Props, parent: | ||||
| 			}, | ||||
| 		], | ||||
| 		openGraph: { | ||||
| 			title: `${icon} icon · Dashboard Icons`, | ||||
| 			description: `Download and use the ${icon} icon from Dashboard Icons for your applications`, | ||||
| 			title: `${formattedIconName} Icon | Dashboard Icons`, | ||||
| 			description: `Download the ${formattedIconName} icon in SVG, PNG, and WEBP formats. Part of a collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			type: "article", | ||||
| 			url: pageUrl, | ||||
| 			images: [ | ||||
| @@ -60,7 +70,7 @@ export async function generateMetadata({ params, searchParams }: Props, parent: | ||||
| 					url: iconImageUrl, | ||||
| 					width: 512, | ||||
| 					height: 512, | ||||
| 					alt: `${icon} icon`, | ||||
| 					alt: `${formattedIconName} Icon`, | ||||
| 					type: "image/png", | ||||
| 				}, | ||||
| 				...previousImages, | ||||
| @@ -71,10 +81,10 @@ export async function generateMetadata({ params, searchParams }: Props, parent: | ||||
| 		}, | ||||
| 		twitter: { | ||||
| 			card: "summary_large_image", | ||||
| 			title: `${icon} icon · Dashboard Icons`, | ||||
| 			description: `Download and use the ${icon} icon from Dashboard Icons for your applications`, | ||||
| 			title: `${formattedIconName} Icon | Dashboard Icons`, | ||||
| 			description: `Download the ${formattedIconName} icon in SVG, PNG, and WEBP formats. Part of a collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			images: [iconImageUrl], | ||||
| 			creator: "@ajnavocado", | ||||
| 			creator: "@homarr_app", | ||||
| 		}, | ||||
| 		alternates: { | ||||
| 			canonical: pageUrl, | ||||
|   | ||||
| @@ -3,34 +3,48 @@ import { getIconsArray } from "@/lib/api" | ||||
| import type { Metadata } from "next" | ||||
| import { IconSearch } from "./components/icon-search" | ||||
|  | ||||
| export const metadata: Metadata = { | ||||
| 	title: "Browse icons | Dashboard Icons", | ||||
| 	description: "Search and browse through our collection of beautiful dashboard icons for your applications", | ||||
| 	keywords: ["dashboard icons", "browse icons", "icon search", "free icons", "open source icons"], | ||||
| 	openGraph: { | ||||
| 		title: "Browse Dashboard Icons Collection", | ||||
| 		description: "Search and browse through our collection of beautiful dashboard icons for your applications", | ||||
| 		type: "website", | ||||
| 		url: `${BASE_URL}/icons`, | ||||
| 		images: [ | ||||
| 			{ | ||||
| 				url: "/og-image-browse.png", | ||||
| 				width: 1200, | ||||
| 				height: 630, | ||||
| 				alt: "Browse Dashboard Icons", | ||||
| 				type: "image/png", | ||||
| 			}, | ||||
| export async function generateMetadata(): Promise<Metadata> { | ||||
| 	const icons = await getIconsArray() | ||||
| 	const totalIcons = icons.length | ||||
|  | ||||
| 	return { | ||||
| 		title: "Browse Icons | Dashboard Icons", | ||||
| 		description: `Search and browse through our collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 		keywords: [ | ||||
| 			"browse icons", | ||||
| 			"dashboard icons", | ||||
| 			"icon search", | ||||
| 			"service icons", | ||||
| 			"application icons", | ||||
| 			"tool icons", | ||||
| 			"web dashboard", | ||||
| 			"app directory", | ||||
| 		], | ||||
| 	}, | ||||
| 	twitter: { | ||||
| 		card: "summary_large_image", | ||||
| 		title: "Browse Dashboard Icons Collection", | ||||
| 		description: "Search and browse through our collection of beautiful dashboard icons for your applications", | ||||
| 		images: ["/og-image-browse.png"], | ||||
| 	}, | ||||
| 	alternates: { | ||||
| 		canonical: `${BASE_URL}/icons`, | ||||
| 	}, | ||||
| 		openGraph: { | ||||
| 			title: "Browse Dashboard Icons Collection", | ||||
| 			description: `Search and browse through our collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			type: "website", | ||||
| 			url: `${BASE_URL}/icons`, | ||||
| 			images: [ | ||||
| 				{ | ||||
| 					url: "/og-image-browse.png", | ||||
| 					width: 1200, | ||||
| 					height: 630, | ||||
| 					alt: "Browse Dashboard Icons Collection", | ||||
| 					type: "image/png", | ||||
| 				}, | ||||
| 			], | ||||
| 		}, | ||||
| 		twitter: { | ||||
| 			card: "summary_large_image", | ||||
| 			title: "Browse Dashboard Icons Collection", | ||||
| 			description: `Search and browse through our collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			images: ["/og-image-browse.png"], | ||||
| 		}, | ||||
| 		alternates: { | ||||
| 			canonical: `${BASE_URL}/icons`, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export const dynamic = "force-static" | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import { Inter } from "next/font/google"; | ||||
| import { Toaster } from "sonner"; | ||||
| import "./globals.css"; | ||||
| import { ThemeProvider } from "./theme-provider"; | ||||
| import { getTotalIcons } from "@/lib/api" | ||||
|  | ||||
| const inter = Inter({ | ||||
| 	variable: "--font-inter", | ||||
| @@ -18,76 +19,85 @@ export const viewport: Viewport = { | ||||
| 	themeColor: "#ffffff", | ||||
| }; | ||||
|  | ||||
| export const metadata: Metadata = { | ||||
| 	metadataBase: new URL("https://icons.homarr.dev"), | ||||
| 	title: "Dashboard Icons", | ||||
| 	description: "Curated icons for your dashboard", | ||||
| 	keywords: [ | ||||
| 		"dashboard", | ||||
| 		"icons", | ||||
| 		"open source", | ||||
| 		"free icons", | ||||
| 		"dashboard design", | ||||
| 	], | ||||
| 	robots: { | ||||
| 		index: true, | ||||
| 		follow: true, | ||||
| 		"max-image-preview": "large", | ||||
| 		"max-snippet": -1, | ||||
| 		"max-video-preview": -1, | ||||
| 		googleBot: "index, follow", | ||||
| 	}, | ||||
| 	openGraph: { | ||||
| 		siteName: "Dashboard Icons", | ||||
| 		type: "website", | ||||
| 		locale: "en_US", | ||||
| 		title: "Dashboard Icons", | ||||
| 		description: "Curated icons for your dashboard", | ||||
| 		url: "https://icons.homarr.dev", | ||||
| 		images: [ | ||||
| 			{ | ||||
| 				url: "/og-image.png", | ||||
| 				width: 1200, | ||||
| 				height: 630, | ||||
| 				alt: "Dashboard Icons", | ||||
| 				type: "image/png", | ||||
| 			}, | ||||
| export async function generateMetadata(): Promise<Metadata> { | ||||
| 	const { totalIcons } = await getTotalIcons() | ||||
|  | ||||
| 	return { | ||||
| 		metadataBase: new URL("https://dashboardicons.com"), | ||||
| 		title: "Dashboard Icons - Your definitive source for dashboard icons", | ||||
| 		description: `A collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 		keywords: [ | ||||
| 			"dashboard icons", | ||||
| 			"service icons", | ||||
| 			"application icons", | ||||
| 			"tool icons", | ||||
| 			"web dashboard", | ||||
| 			"app directory", | ||||
| 		], | ||||
| 	}, | ||||
| 	twitter: { | ||||
| 		card: "summary_large_image", | ||||
| 		site: "@homarr_app", | ||||
| 		creator: "@homarr_app", | ||||
| 		title: "Dashboard Icons", | ||||
| 		description: "Curated icons for your dashboard", | ||||
| 		images: ["/og-image.png"], | ||||
| 	}, | ||||
| 	applicationName: "Dashboard Icons", | ||||
| 	appleWebApp: { | ||||
| 		title: "Dashboard Icons", | ||||
| 		statusBarStyle: "default", | ||||
| 		capable: true, | ||||
| 	}, | ||||
| 	alternates: { | ||||
| 		types: { | ||||
| 			"application/rss+xml": "https://icons.homarr.dev/rss.xml", | ||||
| 		robots: { | ||||
| 			index: true, | ||||
| 			follow: true, | ||||
| 			"max-image-preview": "large", | ||||
| 			"max-snippet": -1, | ||||
| 			"max-video-preview": -1, | ||||
| 			googleBot: "index, follow", | ||||
| 		}, | ||||
| 	}, | ||||
| 	icons: { | ||||
| 		icon: [ | ||||
| 			{ | ||||
| 				url: "/favicon.ico", | ||||
| 				type: "image/x-icon", | ||||
| 		openGraph: { | ||||
| 			siteName: "Dashboard Icons", | ||||
| 			type: "website", | ||||
| 			locale: "en_US", | ||||
| 			title: "Dashboard Icons - Your definitive source for dashboard icons", | ||||
| 			description: `A collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			url: "https://dashboardicons.com", | ||||
| 			images: [ | ||||
| 				{ | ||||
| 					url: "/og-image.png", | ||||
| 					width: 1200, | ||||
| 					height: 630, | ||||
| 					alt: "Dashboard Icons", | ||||
| 					type: "image/png", | ||||
| 				}, | ||||
| 			], | ||||
| 		}, | ||||
| 		twitter: { | ||||
| 			card: "summary_large_image", | ||||
| 			site: "@homarr_app", | ||||
| 			creator: "@homarr_app", | ||||
| 			title: "Dashboard Icons - Your definitive source for dashboard icons", | ||||
| 			description: `A collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			images: ["/og-image.png"], | ||||
| 		}, | ||||
| 		applicationName: "Dashboard Icons", | ||||
| 		appleWebApp: { | ||||
| 			title: "Dashboard Icons", | ||||
| 			statusBarStyle: "default", | ||||
| 			capable: true, | ||||
| 		}, | ||||
| 		alternates: { | ||||
| 			types: { | ||||
| 				"application/rss+xml": "https://dashboardicons.com/rss.xml", | ||||
| 			}, | ||||
| 		], | ||||
| 		shortcut: [ | ||||
| 			{ | ||||
| 				url: "/favicon.ico", | ||||
| 				type: "image/x-icon", | ||||
| 			}, | ||||
| 		], | ||||
| 	}, | ||||
| }; | ||||
| 		}, | ||||
| 		icons: { | ||||
| 			icon: [ | ||||
| 				{ url: "/favicon.ico", sizes: "any" }, | ||||
| 				{ url: "/favicon-16x16.png", sizes: "16x16", type: "image/png" }, | ||||
| 				{ url: "/favicon-32x32.png", sizes: "32x32", type: "image/png" }, | ||||
| 			], | ||||
| 			apple: [ | ||||
| 				{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" }, | ||||
| 			], | ||||
| 			other: [ | ||||
| 				{ | ||||
| 					rel: "mask-icon", | ||||
| 					url: "/safari-pinned-tab.svg", | ||||
| 					color: "#000000", | ||||
| 				}, | ||||
| 			], | ||||
| 		}, | ||||
| 		manifest: "/site.webmanifest", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default function RootLayout({ | ||||
| 	children, | ||||
|   | ||||
| @@ -3,33 +3,44 @@ import { BASE_URL } from "@/constants" | ||||
| import { getTotalIcons } from "@/lib/api" | ||||
| import type { Metadata } from "next" | ||||
|  | ||||
| export const metadata: Metadata = { | ||||
| 	title: "Dashboard Icons - Beautiful icons for your dashboard", | ||||
| 	description: "Free, open-source icons for your dashboard. Choose from hundreds of high-quality icons for your web applications.", | ||||
| 	keywords: ["self hosted", "dashboard icons", "free icons", "open source icons", "web dashboard", "application icons"], | ||||
| 	openGraph: { | ||||
| 		title: "Dashboard Icons - Your definitive source for dashboard icons", | ||||
| 		description: "Free, open-source icons for your dashboard. Choose from thousands of high-quality icons.", | ||||
| 		type: "website", | ||||
| 		url: BASE_URL, | ||||
| 		images: [ | ||||
| 			{ | ||||
| 				url: "/og-image.png", | ||||
| 				width: 1200, | ||||
| 				height: 630, | ||||
| 				alt: "Dashboard Icons", | ||||
| 			}, | ||||
| export async function generateMetadata(): Promise<Metadata> { | ||||
| 	const { totalIcons } = await getTotalIcons() | ||||
|  | ||||
| 	return { | ||||
| 		title: "Dashboard Icons - Beautiful icons for your dashboard", | ||||
| 		description: `A collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 		keywords: [ | ||||
| 			"dashboard icons", | ||||
| 			"service icons", | ||||
| 			"application icons", | ||||
| 			"tool icons", | ||||
| 			"web dashboard", | ||||
| 			"app directory", | ||||
| 		], | ||||
| 	}, | ||||
| 	twitter: { | ||||
| 		title: "Dashboard Icons - Your definitive source for dashboard icons", | ||||
| 		description: "Free, open-source icons for your dashboard. Choose from thousands of high-quality icons.", | ||||
| 		card: "summary_large_image", | ||||
| 		images: ["/og-image.png"], | ||||
| 	}, | ||||
| 	alternates: { | ||||
| 		canonical: BASE_URL, | ||||
| 	}, | ||||
| 		openGraph: { | ||||
| 			title: "Dashboard Icons - Your definitive source for dashboard icons", | ||||
| 			description: `A collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			type: "website", | ||||
| 			url: BASE_URL, | ||||
| 			images: [ | ||||
| 				{ | ||||
| 					url: "/og-image.png", | ||||
| 					width: 1200, | ||||
| 					height: 630, | ||||
| 					alt: "Dashboard Icons", | ||||
| 				}, | ||||
| 			], | ||||
| 		}, | ||||
| 		twitter: { | ||||
| 			title: "Dashboard Icons - Your definitive source for dashboard icons", | ||||
| 			description: `A collection of ${totalIcons} curated icons for services, applications and tools, designed specifically for dashboards and app directories.`, | ||||
| 			card: "summary_large_image", | ||||
| 			images: ["/og-image.png"], | ||||
| 		}, | ||||
| 		alternates: { | ||||
| 			canonical: BASE_URL, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default async function Home() { | ||||
|   | ||||