feat(icons/[id]): Refine related icons relevance, display limits, and styling

This commit is contained in:
Bjorn Lammers 2025-04-27 22:57:56 +02:00
parent 23462d2980
commit 575dee0580

View File

@ -10,7 +10,7 @@ import { formatIconName } from "@/lib/utils"
import type { AuthorData, Icon, IconFile } from "@/types/icons" import type { AuthorData, Icon, IconFile } from "@/types/icons"
import confetti from "canvas-confetti" import confetti from "canvas-confetti"
import { motion } from "framer-motion" import { motion } from "framer-motion"
import { Check, Copy, Download, FileType, Github, Moon, PaletteIcon, Sun } from "lucide-react" import { Check, Copy, Download, FileType, Github, Moon, PaletteIcon, Sun, ArrowRight } from "lucide-react"
import dynamic from "next/dynamic" import dynamic from "next/dynamic"
import Image from "next/image" import Image from "next/image"
import Link from "next/link" import Link from "next/link"
@ -479,7 +479,30 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
</Card> </Card>
</div> </div>
</div> </div>
{iconData.categories && iconData.categories.length > 0 && ( {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 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
const topRelatedIcons = relatedIconsWithScore.slice(0, MAX_RELATED_ICONS)
const viewMoreUrl = `/icons?${currentCategories.map((cat) => `category=${encodeURIComponent(cat)}`).join("&")}`
if (topRelatedIcons.length === 0) return null
return (
<section className="container mx-auto mt-12" aria-labelledby="related-icons-title"> <section className="container mx-auto mt-12" aria-labelledby="related-icons-title">
<Card className="bg-background/50 border shadow-lg"> <Card className="bg-background/50 border shadow-lg">
<CardHeader> <CardHeader>
@ -487,23 +510,26 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
<h2 id="related-icons-title">Related Icons</h2> <h2 id="related-icons-title">Related Icons</h2>
</CardTitle> </CardTitle>
<CardDescription> <CardDescription>
Other icons from {iconData.categories.map((cat) => cat.replace(/-/g, " ")).join(", ")} categories Other icons from {currentCategories.map((cat) => cat.replace(/-/g, " ")).join(", ")} categories
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<IconsGrid <IconsGrid filteredIcons={topRelatedIcons} matchedAliases={{}} />
filteredIcons={Object.entries(allIcons) {relatedIconsWithScore.length > MAX_RELATED_ICONS && (
.filter(([name, data]) => { <div className="mt-6 text-center">
if (name === icon) return false <Button asChild variant="link" className="text-muted-foreground hover:text-primary transition-colors duration-200 hover:no-underline">
return data.categories?.some((cat) => iconData.categories?.includes(cat)) <Link href={viewMoreUrl} className="no-underline">
}) View all related icons
.map(([name, data]) => ({ name, data }))} <ArrowRight className="ml-2 h-4 w-4" />
matchedAliases={{}} </Link>
/> </Button>
</div>
)}
</CardContent> </CardContent>
</Card> </Card>
</section> </section>
)} )
})()}
</main> </main>
) )
} }