From e90d3c4b7f14170320e8fa4e6b88ed4551db7c5b Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Thu, 17 Apr 2025 16:19:42 +0200 Subject: [PATCH] Virtualize (kind of) the list --- web/src/app/icons/components/icon-search.tsx | 26 +++- web/src/components/hero.tsx | 123 ++++++++----------- web/src/constants.ts | 2 +- 3 files changed, 69 insertions(+), 82 deletions(-) diff --git a/web/src/app/icons/components/icon-search.tsx b/web/src/app/icons/components/icon-search.tsx index 0aa979b1..76abd97e 100644 --- a/web/src/app/icons/components/icon-search.tsx +++ b/web/src/app/icons/components/icon-search.tsx @@ -399,11 +399,8 @@ export function IconSearch({ icons }: IconSearchProps) { {getSortLabel(sortOption)} -
- {filteredIcons.map(({ name, data }) => ( - - ))} -
+ + )} @@ -419,7 +416,6 @@ function IconCard({ data: Icon matchedAlias?: string | null }) { - return ( @@ -440,3 +436,21 @@ function IconCard({ ) } + +interface IconsGridProps { + filteredIcons: { name: string; data: Icon }[] + matchedAliases: Record +} + +function IconsGrid({ filteredIcons, matchedAliases }: IconsGridProps) { + return ( + <> +
+ {filteredIcons.slice(0, 120).map(({ name, data }) => ( + + ))} +
+ {filteredIcons.length > 120 &&

And {filteredIcons.length - 120} more...

} + + ) +} diff --git a/web/src/components/hero.tsx b/web/src/components/hero.tsx index 0ffc83e8..077a10c6 100644 --- a/web/src/components/hero.tsx +++ b/web/src/components/hero.tsx @@ -1,19 +1,19 @@ -"use client"; +"use client" -import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; -import { cn } from "@/lib/utils"; -import { motion, useAnimation, useInView } from "framer-motion"; -import { DollarSign, Heart, Search, Star } from "lucide-react"; -import Link from "next/link"; -import { useEffect, useRef, useState } from "react"; -import { AuroraText } from "./magicui/aurora-text"; -import { InteractiveHoverButton } from "./magicui/interactive-hover-button"; +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { cn } from "@/lib/utils" +import { motion, useAnimation, useInView } from "framer-motion" +import { DollarSign, Heart, Search, Star } from "lucide-react" +import Link from "next/link" +import { useEffect, useRef, useState } from "react" +import { AuroraText } from "./magicui/aurora-text" +import { InteractiveHoverButton } from "./magicui/interactive-hover-button" interface IconCardProps { - name: string; - imageUrl: string; + name: string + imageUrl: string } function IconCard({ name, imageUrl }: IconCardProps) { @@ -22,11 +22,9 @@ function IconCard({ name, imageUrl }: IconCardProps) {
{name}
-

- {name} -

+

{name}

- ); + ) } function ElegantShape({ @@ -39,28 +37,28 @@ function ElegantShape({ mobileWidth, mobileHeight, }: { - className?: string; - delay?: number; - width?: number; - height?: number; - rotate?: number; - gradient?: string; - mobileWidth?: number; - mobileHeight?: number; + className?: string + delay?: number + width?: number + height?: number + rotate?: number + gradient?: string + mobileWidth?: number + mobileHeight?: number }) { - const controls = useAnimation(); - const [isMobile, setIsMobile] = useState(false); - const ref = useRef(null); - const isInView = useInView(ref, { once: true, amount: 0.1 }); + const controls = useAnimation() + const [isMobile, setIsMobile] = useState(false) + const ref = useRef(null) + const isInView = useInView(ref, { once: true, amount: 0.1 }) useEffect(() => { const checkMobile = () => { - setIsMobile(window.innerWidth < 768); - }; - checkMobile(); - window.addEventListener("resize", checkMobile); - return () => window.removeEventListener("resize", checkMobile); - }, []); + setIsMobile(window.innerWidth < 768) + } + checkMobile() + window.addEventListener("resize", checkMobile) + return () => window.removeEventListener("resize", checkMobile) + }, []) useEffect(() => { if (isInView) { @@ -77,9 +75,9 @@ function ElegantShape({ ease: [0.23, 0.86, 0.39, 0.96], opacity: { duration: 1.2 }, }, - }); + }) } - }, [controls, delay, isInView, rotate]); + }, [controls, delay, isInView, rotate]) return ( - ); + ) } -export function HeroSection({ - totalIcons, - stars, -}: { totalIcons: number; stars: number }) { - const [searchQuery, setSearchQuery] = useState(""); +export function HeroSection({ totalIcons, stars }: { totalIcons: number; stars: number }) { + const [searchQuery, setSearchQuery] = useState("") return (
@@ -193,40 +188,26 @@ export function HeroSection({
- + - - Made with love by Homarr Labs - + Made with love by Homarr Labs

Your definitive source for
- - dashboard icons - + dashboard icons

- +

- A collection of {totalIcons}{" "} - curated icons for services, applications and tools, designed - specifically for dashboards and app directories. + A collection of {totalIcons} curated icons for services, applications and tools, + designed specifically for dashboards and app directories.

@@ -234,11 +215,7 @@ export function HeroSection({ custom={3} className="flex flex-col items-center gap-4 md:gap-6 mb-8 md:mb-12 motion-safe:motion-preset-slide-up motion-duration-1500" > -
+
- - Explore icons - + Explore icons

Give us a star

- - {stars} - + {stars}
@@ -294,5 +267,5 @@ export function HeroSection({
- ); + ) } diff --git a/web/src/constants.ts b/web/src/constants.ts index 36800875..b567c5b6 100644 --- a/web/src/constants.ts +++ b/web/src/constants.ts @@ -2,4 +2,4 @@ export const BASE_URL = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons export const REPO_PATH = "https://github.com/homarr-labs/dashboard-icons" export const METADATA_URL = "https://raw.githubusercontent.com/homarr-labs/dashboard-icons/refs/heads/main/metadata.json" export const WEB_URL = "https://icons.homarr.dev" -export const REPO_NAME = "homarr-labs/dashboard-icons" \ No newline at end of file +export const REPO_NAME = "homarr-labs/dashboard-icons"