fix(web): Run Biome checks and apply fixes

This commit is contained in:
Bjorn Lammers 2025-04-24 16:07:29 +02:00
parent 34fef44222
commit 40482771fa
8 changed files with 123 additions and 82 deletions

View File

@ -22,6 +22,9 @@
"recommended": true,
"suspicious": {
"noArrayIndexKey": "off"
},
"security": {
"noDangerouslySetInnerHtml": "off"
}
}
},

View File

@ -1,13 +1,8 @@
import { readFile } from "node:fs/promises"
import { join } from "node:path"
import { SITE_NAME, SITE_TAGLINE, WEB_URL, getIconDescription } from "@/constants"
import { getAllIcons } from "@/lib/api"
import { ImageResponse } from "next/og"
import {
SITE_NAME,
SITE_TAGLINE,
getIconDescription,
WEB_URL
} from "@/constants"
export const dynamic = "force-static"

View File

@ -1,10 +1,20 @@
import { IconDetails } from "@/components/icon-details"
import { StructuredData } from "@/components/structured-data"
import { BASE_URL, GITHUB_URL, ICON_DETAIL_KEYWORDS, SITE_NAME, SITE_TAGLINE, TITLE_SEPARATOR, WEB_URL, getIconDescription, getIconSchema } 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 type { Metadata, ResolvingMetadata } from "next"
import Script from "next/script"
import { notFound } from "next/navigation"
import Script from "next/script"
export const dynamicParams = false
@ -109,7 +119,7 @@ export default async function IconPage({ params }: { params: { icon: string } })
authorName,
authorData.html_url,
updateDate.toISOString(),
Object.keys(iconsData).length
Object.keys(iconsData).length,
)
return (

View File

@ -1,7 +1,19 @@
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 { StructuredData } from "@/components/structured-data"
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 type { Metadata } from "next"
import { StructuredData } from "@/components/structured-data"
import { IconSearch } from "./components/icon-search"
export async function generateMetadata(): Promise<Metadata> {
@ -42,15 +54,15 @@ export default async function IconsPage() {
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": {
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
}
name: ORGANIZATION_NAME,
url: GITHUB_URL,
},
}
return (
@ -62,7 +74,9 @@ export default async function IconsPage() {
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h1 className="text-3xl font-bold">Icons</h1>
<p className="text-muted-foreground">Search our collection of {icons.length} icons - {SITE_TAGLINE}.</p>
<p className="text-muted-foreground">
Search our collection of {icons.length} icons - {SITE_TAGLINE}.
</p>
</div>
</div>

View File

@ -8,7 +8,20 @@ import type { Metadata, Viewport } from "next"
import { Inter } from "next/font/google"
import { Toaster } from "sonner"
import "./globals.css"
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 {
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"
const inter = Inter({
@ -102,10 +115,7 @@ export default async function RootLayout({ children }: Readonly<{ children: Reac
<html lang="en" suppressHydrationWarning>
<body className={`${inter.variable} antialiased bg-background flex flex-col min-h-screen`}>
<PostHogProvider>
<WebsiteStructuredData
websiteSchema={websiteSchema}
organizationSchema={ORGANIZATION_SCHEMA}
/>
<WebsiteStructuredData websiteSchema={websiteSchema} organizationSchema={ORGANIZATION_SCHEMA} />
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
<HeaderWrapper />
<main className="flex-grow">{children}</main>

View File

@ -1,6 +1,20 @@
import { HeroSection } from "@/components/hero"
import { RecentlyAddedIcons } from "@/components/recently-added-icons"
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 {
BASE_URL,
DEFAULT_KEYWORDS,
DEFAULT_OG_IMAGE,
GITHUB_URL,
ORGANIZATION_NAME,
ORGANIZATION_SCHEMA,
REPO_NAME,
SITE_NAME,
SITE_TAGLINE,
WEB_URL,
getHomeDescription,
websiteFullTitle,
websiteTitle,
} from "@/constants"
import { getRecentlyAddedIcons, getTotalIcons } from "@/lib/api"
import type { Metadata } from "next"

View File

@ -1,31 +1,22 @@
type StructuredDataProps = {
data: any
id?: string
data: Record<string, unknown>
id?: string
}
export const StructuredData = ({ data, id }: StructuredDataProps) => {
return (
<script
id={id}
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
)
return <script id={id} type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }} />
}
type WebsiteStructuredDataProps = {
websiteSchema: any
organizationSchema: any
websiteSchema: Record<string, unknown>
organizationSchema: Record<string, unknown>
}
export const WebsiteStructuredData = ({
websiteSchema,
organizationSchema
}: WebsiteStructuredDataProps) => {
return (
<>
<StructuredData data={websiteSchema} id="website-schema" />
<StructuredData data={organizationSchema} id="organization-schema" />
</>
)
export const WebsiteStructuredData = ({ websiteSchema, organizationSchema }: WebsiteStructuredDataProps) => {
return (
<>
<StructuredData data={websiteSchema} id="website-schema" />
<StructuredData data={organizationSchema} id="organization-schema" />
</>
)
}

View File

@ -34,7 +34,7 @@ export const DEFAULT_KEYWORDS = [
"free icons",
"SVG icons",
"web dashboard",
"app directory"
"app directory",
]
export const BROWSE_KEYWORDS = [
@ -44,7 +44,7 @@ export const BROWSE_KEYWORDS = [
"minimal icons",
"dashboard design",
"UI icons",
...DEFAULT_KEYWORDS
...DEFAULT_KEYWORDS,
]
// Add format-specific keywords
@ -56,63 +56,67 @@ export const ICON_DETAIL_KEYWORDS = (iconName: string): string[] => [
`${iconName} webp icon`, // e.g., "Homarr webp icon"
`${iconName} download`, // e.g., "Homarr download"
`${iconName} dashboard icon`, // e.g., "Homarr dashboard icon"
...DEFAULT_KEYWORDS
...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": {
name: SITE_NAME,
url: WEB_URL,
description: getDescription(totalIcons),
potentialAction: {
"@type": "SearchAction",
"target": {
target: {
"@type": "EntryPoint",
"urlTemplate": `${WEB_URL}/icons?q={search_term_string}`
urlTemplate: `${WEB_URL}/icons?q={search_term_string}`,
},
"query-input": "required name=search_term_string"
"query-input": "required name=search_term_string",
},
"slogan": SITE_TAGLINE
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
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) => ({
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": {
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
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}`
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
@ -121,5 +125,5 @@ export const DEFAULT_OG_IMAGE = {
width: 1200,
height: 630,
alt: `${SITE_NAME} - ${SITE_TAGLINE}`,
type: "image/png"
type: "image/png",
}