mirror of
https://github.com/walkxcode/dashboard-icons.git
synced 2025-06-28 15:30:22 +08:00
feat(web): improve site metadata structure
This commit is contained in:
parent
df3c53818a
commit
b4c4fe2634
@ -1,7 +1,8 @@
|
|||||||
import { IconDetails } from "@/components/icon-details"
|
import { IconDetails } from "@/components/icon-details"
|
||||||
import { BASE_URL, WEB_URL } from "@/constants"
|
import { BASE_URL, GITHUB_URL, ICON_DETAIL_KEYWORDS, SITE_NAME, SITE_TAGLINE, TITLE_SEPARATOR, WEB_URL, getIconDescription, getIconSchema } from "@/constants"
|
||||||
import { getAllIcons, getAuthorData } from "@/lib/api"
|
import { getAllIcons, getAuthorData } from "@/lib/api"
|
||||||
import type { Metadata, ResolvingMetadata } from "next"
|
import type { Metadata, ResolvingMetadata } from "next"
|
||||||
|
import Script from "next/script"
|
||||||
import { notFound } from "next/navigation"
|
import { notFound } from "next/navigation"
|
||||||
|
|
||||||
export const dynamicParams = false
|
export const dynamicParams = false
|
||||||
@ -40,43 +41,39 @@ export async function generateMetadata({ params, searchParams }: Props, parent:
|
|||||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||||
.join(" ")
|
.join(" ")
|
||||||
|
|
||||||
|
const title = `${formattedIconName} Icon ${TITLE_SEPARATOR} ${SITE_NAME}`
|
||||||
|
const fullTitle = `${formattedIconName} Icon ${TITLE_SEPARATOR} ${SITE_NAME} ${TITLE_SEPARATOR} ${SITE_TAGLINE}`
|
||||||
|
const description = getIconDescription(formattedIconName, totalIcons)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: `${formattedIconName} Icon | Dashboard Icons`,
|
title,
|
||||||
description: `Download the ${formattedIconName} icon in SVG, PNG, and WEBP formats. Available for free in our collection of ${totalIcons} icons for dashboards and applications.`,
|
description,
|
||||||
assets: [iconImageUrl],
|
assets: [iconImageUrl],
|
||||||
category: "icons",
|
category: "Icons",
|
||||||
keywords: [
|
keywords: ICON_DETAIL_KEYWORDS(formattedIconName),
|
||||||
`${formattedIconName} icon`,
|
|
||||||
"dashboard icon",
|
|
||||||
"service icon",
|
|
||||||
"application icon",
|
|
||||||
"tool icon",
|
|
||||||
"web dashboard",
|
|
||||||
"app directory",
|
|
||||||
],
|
|
||||||
icons: {
|
icons: {
|
||||||
icon: iconImageUrl,
|
icon: iconImageUrl,
|
||||||
},
|
},
|
||||||
abstract: `Download the ${formattedIconName} icon in SVG, PNG, and WEBP formats. Available for free in our collection of ${totalIcons} icons for dashboards and applications.`,
|
abstract: description,
|
||||||
robots: {
|
robots: {
|
||||||
index: true,
|
index: true,
|
||||||
follow: true,
|
follow: true,
|
||||||
},
|
},
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: `${formattedIconName} Icon | Dashboard Icons`,
|
title: fullTitle,
|
||||||
description: `Download the ${formattedIconName} icon in SVG, PNG, and WEBP formats. Available for free in our collection of ${totalIcons} icons for dashboards and applications.`,
|
description,
|
||||||
type: "article",
|
type: "article",
|
||||||
url: pageUrl,
|
url: pageUrl,
|
||||||
authors: [authorName],
|
authors: [authorName],
|
||||||
publishedTime: updateDate.toISOString(),
|
publishedTime: updateDate.toISOString(),
|
||||||
modifiedTime: updateDate.toISOString(),
|
modifiedTime: updateDate.toISOString(),
|
||||||
section: "Icons",
|
section: "Icons",
|
||||||
tags: [formattedIconName, "dashboard icon", "service icon", "application icon", "tool icon", "web dashboard", "app directory"],
|
tags: [formattedIconName, ...ICON_DETAIL_KEYWORDS(formattedIconName)],
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
title: `${formattedIconName} Icon | Dashboard Icons`,
|
title: fullTitle,
|
||||||
description: `Download the ${formattedIconName} icon in SVG, PNG, and WEBP formats. Available for free in our collection of ${totalIcons} icons for dashboards and applications.`,
|
description,
|
||||||
images: [iconImageUrl],
|
images: [iconImageUrl],
|
||||||
},
|
},
|
||||||
alternates: {
|
alternates: {
|
||||||
@ -87,6 +84,9 @@ export async function generateMetadata({ params, searchParams }: Props, parent:
|
|||||||
webp: `${BASE_URL}/webp/${icon}.webp`,
|
webp: `${BASE_URL}/webp/${icon}.webp`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
other: {
|
||||||
|
"revisit-after": "7 days",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +100,28 @@ export default async function IconPage({ params }: { params: Promise<{ icon: str
|
|||||||
}
|
}
|
||||||
|
|
||||||
const authorData = await getAuthorData(originalIconData.update.author.id)
|
const authorData = await getAuthorData(originalIconData.update.author.id)
|
||||||
|
const updateDate = new Date(originalIconData.update.timestamp)
|
||||||
|
const authorName = authorData.name || authorData.login
|
||||||
|
const formattedIconName = icon
|
||||||
|
.split("-")
|
||||||
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||||
|
.join(" ")
|
||||||
|
|
||||||
return <IconDetails icon={icon} iconData={originalIconData} authorData={authorData} />
|
const imageSchema = getIconSchema(
|
||||||
|
formattedIconName,
|
||||||
|
icon,
|
||||||
|
authorName,
|
||||||
|
authorData.html_url,
|
||||||
|
updateDate.toISOString(),
|
||||||
|
Object.keys(iconsData).length
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Script id="image-schema" type="application/ld+json">
|
||||||
|
{JSON.stringify(imageSchema)}
|
||||||
|
</Script>
|
||||||
|
<IconDetails icon={icon} iconData={originalIconData} authorData={authorData} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,39 @@
|
|||||||
import { BASE_URL } from "@/constants"
|
import { BASE_URL, BROWSE_KEYWORDS, DEFAULT_OG_IMAGE, GITHUB_URL, ORGANIZATION_NAME, ORGANIZATION_SCHEMA, SITE_NAME, SITE_TAGLINE, TITLE_SEPARATOR, WEB_URL, getBrowseDescription } from "@/constants"
|
||||||
import { getIconsArray } from "@/lib/api"
|
import { getIconsArray } from "@/lib/api"
|
||||||
import type { Metadata } from "next"
|
import type { Metadata } from "next"
|
||||||
import { IconSearch } from "./components/icon-search"
|
import { IconSearch } from "./components/icon-search"
|
||||||
|
import Script from "next/script"
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const icons = await getIconsArray()
|
const icons = await getIconsArray()
|
||||||
const totalIcons = icons.length
|
const totalIcons = icons.length
|
||||||
|
|
||||||
|
const title = `Browse Icons ${TITLE_SEPARATOR} ${SITE_NAME}`
|
||||||
|
const description = getBrowseDescription(totalIcons)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: "Browse Icons | Free Dashboard Icons",
|
title,
|
||||||
description: `Browse our collection of ${totalIcons} icons for dashboards and applications. Available in SVG, PNG, and WEBP formats.`,
|
description,
|
||||||
keywords: [
|
keywords: BROWSE_KEYWORDS,
|
||||||
"browse icons",
|
|
||||||
"dashboard icons",
|
|
||||||
"icon search",
|
|
||||||
"service icons",
|
|
||||||
"application icons",
|
|
||||||
"tool icons",
|
|
||||||
"web dashboard",
|
|
||||||
"app directory",
|
|
||||||
],
|
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: "Browse Icons | Free Dashboard Icons",
|
title: `Browse Icons ${TITLE_SEPARATOR} ${SITE_NAME} ${TITLE_SEPARATOR} ${SITE_TAGLINE}`,
|
||||||
description: `Browse our collection of ${totalIcons} icons for dashboards and applications. Available in SVG, PNG, and WEBP formats.`,
|
description,
|
||||||
type: "website",
|
type: "website",
|
||||||
url: `${BASE_URL}/icons`,
|
url: `${WEB_URL}/icons`,
|
||||||
images: [
|
images: [DEFAULT_OG_IMAGE],
|
||||||
{
|
|
||||||
url: "/og-image.png",
|
|
||||||
width: 1200,
|
|
||||||
height: 630,
|
|
||||||
alt: "Browse Dashboard Icons Collection",
|
|
||||||
type: "image/png",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
title: "Browse Icons | Free Dashboard Icons",
|
title: `Browse Icons ${TITLE_SEPARATOR} ${SITE_NAME} ${TITLE_SEPARATOR} ${SITE_TAGLINE}`,
|
||||||
description: `Browse our collection of ${totalIcons} icons for dashboards and applications. Available in SVG, PNG, and WEBP formats.`,
|
description,
|
||||||
images: ["/og-image-browse.png"],
|
images: [DEFAULT_OG_IMAGE.url],
|
||||||
},
|
},
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: `${BASE_URL}/icons`,
|
canonical: `${WEB_URL}/icons`,
|
||||||
},
|
},
|
||||||
|
other: {
|
||||||
|
"revisit-after": "3 days",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,14 +41,36 @@ export const dynamic = "force-static"
|
|||||||
|
|
||||||
export default async function IconsPage() {
|
export default async function IconsPage() {
|
||||||
const icons = await getIconsArray()
|
const icons = await getIconsArray()
|
||||||
|
|
||||||
|
const gallerySchema = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "ImageGallery",
|
||||||
|
"name": `${SITE_NAME} - Browse ${icons.length} Icons - ${SITE_TAGLINE}`,
|
||||||
|
"description": getBrowseDescription(icons.length),
|
||||||
|
"url": `${WEB_URL}/icons`,
|
||||||
|
"numberOfItems": icons.length,
|
||||||
|
"creator": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": ORGANIZATION_NAME,
|
||||||
|
"url": GITHUB_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Script id="gallery-schema" type="application/ld+json">
|
||||||
|
{JSON.stringify(gallerySchema)}
|
||||||
|
</Script>
|
||||||
|
<Script id="org-schema" type="application/ld+json">
|
||||||
|
{JSON.stringify(ORGANIZATION_SCHEMA)}
|
||||||
|
</Script>
|
||||||
<div className="isolate overflow-hidden">
|
<div className="isolate overflow-hidden">
|
||||||
<div className="py-8">
|
<div className="py-8">
|
||||||
<div className="space-y-4 mb-8 mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
<div className="space-y-4 mb-8 mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-3xl font-bold">Icons</h1>
|
<h1 className="text-3xl font-bold">Icons</h1>
|
||||||
<p className="text-muted-foreground">Search our collection of {icons.length} icons.</p>
|
<p className="text-muted-foreground">Search our collection of {icons.length} icons - {SITE_TAGLINE}.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -66,5 +78,6 @@ export default async function IconsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,9 @@ import type { Metadata, Viewport } from "next"
|
|||||||
import { Inter } from "next/font/google"
|
import { Inter } from "next/font/google"
|
||||||
import { Toaster } from "sonner"
|
import { Toaster } from "sonner"
|
||||||
import "./globals.css"
|
import "./globals.css"
|
||||||
import { getDescription, websiteTitle } from "@/constants"
|
import { DEFAULT_KEYWORDS, DEFAULT_OG_IMAGE, GITHUB_URL, ORGANIZATION_NAME, ORGANIZATION_SCHEMA, SITE_NAME, SITE_TAGLINE, WEB_URL, getDescription, getWebsiteSchema, websiteFullTitle, websiteTitle } from "@/constants"
|
||||||
import { ThemeProvider } from "./theme-provider"
|
import { ThemeProvider } from "./theme-provider"
|
||||||
|
import Script from "next/script"
|
||||||
|
|
||||||
const inter = Inter({
|
const inter = Inter({
|
||||||
variable: "--font-inter",
|
variable: "--font-inter",
|
||||||
@ -27,12 +28,13 @@ export const viewport: Viewport = {
|
|||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const { totalIcons } = await getTotalIcons()
|
const { totalIcons } = await getTotalIcons()
|
||||||
|
const description = getDescription(totalIcons)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
metadataBase: new URL("https://dashboardicons.com"),
|
metadataBase: new URL(WEB_URL),
|
||||||
title: websiteTitle,
|
title: websiteTitle,
|
||||||
description: getDescription(totalIcons),
|
description,
|
||||||
keywords: ["dashboard icons", "service icons", "application icons", "tool icons", "web dashboard", "app directory"],
|
keywords: DEFAULT_KEYWORDS,
|
||||||
robots: {
|
robots: {
|
||||||
index: true,
|
index: true,
|
||||||
follow: true,
|
follow: true,
|
||||||
@ -42,33 +44,23 @@ export async function generateMetadata(): Promise<Metadata> {
|
|||||||
googleBot: "index, follow",
|
googleBot: "index, follow",
|
||||||
},
|
},
|
||||||
openGraph: {
|
openGraph: {
|
||||||
siteName: "Dashboard Icons",
|
siteName: SITE_NAME,
|
||||||
type: "website",
|
type: "website",
|
||||||
locale: "en_US",
|
locale: "en_US",
|
||||||
title: websiteTitle,
|
title: websiteFullTitle,
|
||||||
description: getDescription(totalIcons),
|
description,
|
||||||
url: "https://dashboardicons.com",
|
url: WEB_URL,
|
||||||
images: [
|
images: [DEFAULT_OG_IMAGE],
|
||||||
{
|
|
||||||
url: "/og-image.png",
|
|
||||||
width: 1200,
|
|
||||||
height: 630,
|
|
||||||
alt: "Dashboard Icons",
|
|
||||||
type: "image/png",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
site: "@homarr_app",
|
title: websiteFullTitle,
|
||||||
creator: "@homarr_app",
|
description,
|
||||||
title: websiteTitle,
|
images: [DEFAULT_OG_IMAGE.url],
|
||||||
description: getDescription(totalIcons),
|
|
||||||
images: ["/og-image.png"],
|
|
||||||
},
|
},
|
||||||
applicationName: "Dashboard Icons",
|
applicationName: SITE_NAME,
|
||||||
appleWebApp: {
|
appleWebApp: {
|
||||||
title: "Dashboard Icons",
|
title: SITE_NAME,
|
||||||
statusBarStyle: "default",
|
statusBarStyle: "default",
|
||||||
capable: true,
|
capable: true,
|
||||||
},
|
},
|
||||||
@ -88,12 +80,32 @@ export async function generateMetadata(): Promise<Metadata> {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
manifest: "/site.webmanifest",
|
manifest: "/site.webmanifest",
|
||||||
|
authors: [{ name: ORGANIZATION_NAME, url: GITHUB_URL }],
|
||||||
|
creator: ORGANIZATION_NAME,
|
||||||
|
publisher: ORGANIZATION_NAME,
|
||||||
|
archives: [`${WEB_URL}/icons`],
|
||||||
|
category: "Icons",
|
||||||
|
classification: "Dashboard Design Resources",
|
||||||
|
other: {
|
||||||
|
"revisit-after": "7 days",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
export default async function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||||
|
const { totalIcons } = await getTotalIcons()
|
||||||
|
const websiteSchema = getWebsiteSchema(totalIcons)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
|
<head>
|
||||||
|
<Script id="schema-org" type="application/ld+json">
|
||||||
|
{JSON.stringify(websiteSchema)}
|
||||||
|
</Script>
|
||||||
|
<Script id="org-schema" type="application/ld+json">
|
||||||
|
{JSON.stringify(ORGANIZATION_SCHEMA)}
|
||||||
|
</Script>
|
||||||
|
</head>
|
||||||
<body className={`${inter.variable} antialiased bg-background flex flex-col min-h-screen`}>
|
<body className={`${inter.variable} antialiased bg-background flex flex-col min-h-screen`}>
|
||||||
<PostHogProvider>
|
<PostHogProvider>
|
||||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
|
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
|
||||||
|
@ -1,42 +1,37 @@
|
|||||||
import { HeroSection } from "@/components/hero"
|
import { HeroSection } from "@/components/hero"
|
||||||
import { RecentlyAddedIcons } from "@/components/recently-added-icons"
|
import { RecentlyAddedIcons } from "@/components/recently-added-icons"
|
||||||
import { BASE_URL, REPO_NAME, getDescription, websiteTitle } from "@/constants"
|
import { BASE_URL, DEFAULT_KEYWORDS, DEFAULT_OG_IMAGE, GITHUB_URL, ORGANIZATION_NAME, ORGANIZATION_SCHEMA, SITE_NAME, SITE_TAGLINE, WEB_URL, REPO_NAME, getHomeDescription, websiteFullTitle, websiteTitle } from "@/constants"
|
||||||
import { getRecentlyAddedIcons, getTotalIcons } from "@/lib/api"
|
import { getRecentlyAddedIcons, getTotalIcons } from "@/lib/api"
|
||||||
import type { Metadata } from "next"
|
import type { Metadata } from "next"
|
||||||
|
import Script from "next/script"
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const { totalIcons } = await getTotalIcons()
|
const { totalIcons } = await getTotalIcons()
|
||||||
|
const description = getHomeDescription(totalIcons)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: websiteTitle,
|
title: websiteTitle,
|
||||||
description: getDescription(totalIcons),
|
description,
|
||||||
keywords: ["dashboard icons", "service icons", "application icons", "tool icons", "web dashboard", "app directory"],
|
keywords: DEFAULT_KEYWORDS,
|
||||||
robots: {
|
robots: {
|
||||||
index: true,
|
index: true,
|
||||||
follow: true,
|
follow: true,
|
||||||
},
|
},
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: websiteTitle,
|
title: websiteFullTitle,
|
||||||
description: getDescription(totalIcons),
|
description,
|
||||||
type: "website",
|
type: "website",
|
||||||
url: BASE_URL,
|
url: WEB_URL,
|
||||||
images: [
|
images: [DEFAULT_OG_IMAGE],
|
||||||
{
|
|
||||||
url: "/og-image.png",
|
|
||||||
width: 1200,
|
|
||||||
height: 630,
|
|
||||||
alt: "Dashboard Icons",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
title: websiteTitle,
|
title: websiteFullTitle,
|
||||||
description: getDescription(totalIcons),
|
description,
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
images: ["/og-image.png"],
|
images: [DEFAULT_OG_IMAGE.url],
|
||||||
},
|
},
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: BASE_URL,
|
canonical: WEB_URL,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,10 +48,38 @@ export default async function Home() {
|
|||||||
const recentIcons = await getRecentlyAddedIcons(10)
|
const recentIcons = await getRecentlyAddedIcons(10)
|
||||||
const stars = await getGitHubStars()
|
const stars = await getGitHubStars()
|
||||||
|
|
||||||
|
// Collection schema for the homepage
|
||||||
|
const collectionSchema = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "CollectionPage",
|
||||||
|
"name": `${SITE_NAME} Collection - ${SITE_TAGLINE}`,
|
||||||
|
"description": getHomeDescription(totalIcons),
|
||||||
|
"url": WEB_URL,
|
||||||
|
"numberOfItems": totalIcons,
|
||||||
|
"mainEntity": {
|
||||||
|
"@type": "CreativeWork",
|
||||||
|
"name": SITE_NAME,
|
||||||
|
"description": getHomeDescription(totalIcons),
|
||||||
|
"creator": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": ORGANIZATION_NAME,
|
||||||
|
"url": GITHUB_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Script id="collection-schema" type="application/ld+json">
|
||||||
|
{JSON.stringify(collectionSchema)}
|
||||||
|
</Script>
|
||||||
|
<Script id="org-schema" type="application/ld+json">
|
||||||
|
{JSON.stringify(ORGANIZATION_SCHEMA)}
|
||||||
|
</Script>
|
||||||
<div className="flex flex-col min-h-screen">
|
<div className="flex flex-col min-h-screen">
|
||||||
<HeroSection totalIcons={totalIcons} stars={stars} />
|
<HeroSection totalIcons={totalIcons} stars={stars} />
|
||||||
<RecentlyAddedIcons icons={recentIcons} />
|
<RecentlyAddedIcons icons={recentIcons} />
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,119 @@ export const METADATA_URL = "https://raw.githubusercontent.com/homarr-labs/dashb
|
|||||||
export const WEB_URL = "https://dashboardicons.com"
|
export const WEB_URL = "https://dashboardicons.com"
|
||||||
export const REPO_NAME = "homarr-labs/dashboard-icons"
|
export const REPO_NAME = "homarr-labs/dashboard-icons"
|
||||||
|
|
||||||
export const getDescription = (totalIcons: number) =>
|
// Site-wide metadata constants
|
||||||
`Collection of ${totalIcons} icons for applications, services, and tools - designed for dashboards and app directories.`
|
export const SITE_NAME = "Dashboard Icons"
|
||||||
|
export const TITLE_SEPARATOR = " — "
|
||||||
|
export const SITE_TAGLINE = "Your definitive source for dashboard icons"
|
||||||
|
export const ORGANIZATION_NAME = "Homarr Labs"
|
||||||
|
|
||||||
export const websiteTitle = "Free Dashboard Icons - Download High-Quality UI & App Icons"
|
export const getDescription = (totalIcons: number) =>
|
||||||
|
`A curated collection of ${totalIcons} free icons for dashboards and app directories. Available in SVG, PNG, and WEBP formats. ${SITE_TAGLINE}.`
|
||||||
|
|
||||||
|
export const getHomeDescription = (totalIcons: number) =>
|
||||||
|
`Discover our curated collection of ${totalIcons} icons designed specifically for dashboards and app directories. ${SITE_TAGLINE}.`
|
||||||
|
|
||||||
|
export const getBrowseDescription = (totalIcons: number) =>
|
||||||
|
`Browse, search and download from our collection of ${totalIcons} curated icons. All icons available in SVG, PNG, and WEBP formats. ${SITE_TAGLINE}.`
|
||||||
|
|
||||||
|
export const getIconDescription = (iconName: string, totalIcons: number) =>
|
||||||
|
`Download the ${iconName} icon in SVG, PNG, and WEBP formats. Part of our curated collection of ${totalIcons} free icons for dashboards. ${SITE_TAGLINE}.`
|
||||||
|
|
||||||
|
export const websiteTitle = `${SITE_NAME} ${TITLE_SEPARATOR} Free, Curated Icons for Apps & Services`
|
||||||
|
export const websiteFullTitle = `${SITE_NAME} ${TITLE_SEPARATOR} Free, Curated Icons for Apps & Services ${TITLE_SEPARATOR} ${SITE_TAGLINE}`
|
||||||
|
|
||||||
|
// Various keyword sets for different pages
|
||||||
|
export const DEFAULT_KEYWORDS = [
|
||||||
|
"dashboard icons",
|
||||||
|
"app icons",
|
||||||
|
"service icons",
|
||||||
|
"curated icons",
|
||||||
|
"free icons",
|
||||||
|
"SVG icons",
|
||||||
|
"web dashboard",
|
||||||
|
"app directory"
|
||||||
|
]
|
||||||
|
|
||||||
|
export const BROWSE_KEYWORDS = [
|
||||||
|
"browse icons",
|
||||||
|
"search icons",
|
||||||
|
"download icons",
|
||||||
|
"minimal icons",
|
||||||
|
"dashboard design",
|
||||||
|
"UI icons",
|
||||||
|
...DEFAULT_KEYWORDS
|
||||||
|
]
|
||||||
|
|
||||||
|
export const ICON_DETAIL_KEYWORDS = (iconName: string) => [
|
||||||
|
`${iconName} icon`,
|
||||||
|
`${iconName} logo`,
|
||||||
|
`${iconName} svg`,
|
||||||
|
`${iconName} download`,
|
||||||
|
`${iconName} dashboard icon`,
|
||||||
|
...DEFAULT_KEYWORDS
|
||||||
|
]
|
||||||
|
|
||||||
|
// Core structured data for the website (JSON-LD)
|
||||||
|
export const getWebsiteSchema = (totalIcons: number) => ({
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": SITE_NAME,
|
||||||
|
"url": WEB_URL,
|
||||||
|
"description": getDescription(totalIcons),
|
||||||
|
"potentialAction": {
|
||||||
|
"@type": "SearchAction",
|
||||||
|
"target": {
|
||||||
|
"@type": "EntryPoint",
|
||||||
|
"urlTemplate": `${WEB_URL}/icons?q={search_term_string}`
|
||||||
|
},
|
||||||
|
"query-input": "required name=search_term_string"
|
||||||
|
},
|
||||||
|
"slogan": SITE_TAGLINE
|
||||||
|
})
|
||||||
|
|
||||||
|
// Organization schema
|
||||||
|
export const ORGANIZATION_SCHEMA = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": ORGANIZATION_NAME,
|
||||||
|
"url": `https://github.com/${REPO_NAME}`,
|
||||||
|
"logo": `${WEB_URL}/og-image.png`,
|
||||||
|
"sameAs": [
|
||||||
|
`https://github.com/${REPO_NAME}`,
|
||||||
|
"https://homarr.dev"
|
||||||
|
],
|
||||||
|
"slogan": SITE_TAGLINE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Social media
|
||||||
|
export const GITHUB_URL = `https://github.com/${REPO_NAME}`
|
||||||
|
|
||||||
|
// Image schemas
|
||||||
|
export const getIconSchema = (iconName: string, iconId: string, authorName: string, authorUrl: string, updateDate: string, totalIcons: number) => ({
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "ImageObject",
|
||||||
|
"name": `${iconName} Icon`,
|
||||||
|
"description": getIconDescription(iconName, totalIcons),
|
||||||
|
"contentUrl": `${BASE_URL}/png/${iconId}.png`,
|
||||||
|
"thumbnailUrl": `${BASE_URL}/png/${iconId}.png`,
|
||||||
|
"uploadDate": updateDate,
|
||||||
|
"author": {
|
||||||
|
"@type": "Person",
|
||||||
|
"name": authorName,
|
||||||
|
"url": authorUrl
|
||||||
|
},
|
||||||
|
"encodingFormat": ["image/png", "image/svg+xml", "image/webp"],
|
||||||
|
"contentSize": "Variable",
|
||||||
|
"representativeOfPage": true,
|
||||||
|
"creditText": `Icon contributed by ${authorName} to the ${SITE_NAME} collection by ${ORGANIZATION_NAME}`,
|
||||||
|
"embedUrl": `${WEB_URL}/icons/${iconId}`
|
||||||
|
})
|
||||||
|
|
||||||
|
// OpenGraph defaults
|
||||||
|
export const DEFAULT_OG_IMAGE = {
|
||||||
|
url: "/og-image.png",
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: `${SITE_NAME} - ${SITE_TAGLINE}`,
|
||||||
|
type: "image/png"
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user