From 916aaf92ef0eac5aa4a76c71f7a16e5124fbef3b Mon Sep 17 00:00:00 2001 From: gunshiz Date: Sun, 9 Aug 2026 21:37:25 +0700 Subject: [PATCH] perf(home): shrink carousel client boundary --- app/page.tsx | 2 +- components/LinkCard.tsx | 142 ++++++++++++++++++----------------- components/link-carousel.tsx | 53 +++++++++++++ 3 files changed, 127 insertions(+), 70 deletions(-) create mode 100644 components/link-carousel.tsx diff --git a/app/page.tsx b/app/page.tsx index 6d1a9f7..3b4d485 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -24,7 +24,7 @@ export default async function Home() { // Use configured profile data. const profileName = config.profile.name; const profileAvatar = config.profile.avatar; - const links1 = [...config.links]; + const links1 = config.links; const jsonLd = { "@context": "https://schema.org", diff --git a/components/LinkCard.tsx b/components/LinkCard.tsx index e4a1bd8..16f8684 100644 --- a/components/LinkCard.tsx +++ b/components/LinkCard.tsx @@ -1,14 +1,15 @@ -"use client"; - -import { useState } from "react"; import type { ComponentType, SVGProps } from "react"; import { Button } from "@/components/ui/button"; -import { CardContent } from "@/components/ui/card"; import Link from "next/link"; -import { ArrowLeft, ArrowRight, Trophy } from "lucide-react"; -import { LinkConfig, type IconName } from "@/lib/config"; -import { getCountForLink, formatCount, FollowerCounts } from "@/lib/followers/utils"; +import { Trophy } from "lucide-react"; +import type { LinkConfig, IconName } from "@/lib/config"; +import { + getCountForLink, + formatCount, + type FollowerCounts, +} from "@/lib/followers/utils"; import { RobloxIcon, DiscordIcon, TiktokIcon, YoutubeIcon, FormIcon, DonateIcon } from "@/lib/icons"; +import { LinkCarousel } from "@/components/link-carousel"; const iconMap: Record>> = { roblox: RobloxIcon, @@ -20,71 +21,74 @@ const iconMap: Record>> = { leaderboard: Trophy, }; -export function LinkCard({ counts, links1, links2 }: { counts: FollowerCounts, links1: LinkConfig[], links2: LinkConfig[] }) { - const [isPage2, setIsPage2] = useState(false); - const currentLinks = isPage2 ? links2 : links1; - +function LinkList({ + counts, + label, + links, +}: { + counts: FollowerCounts; + label: string; + links: readonly LinkConfig[]; +}) { return ( - -
-
- - - ); - })} - - -
- - -
-
+ + + {item.icon === "donate" ? ( + + ขึ้นจอ 10 บาท+ + + ) : count !== null ? ( + + {formatCount(count.count)}{" "} + {count.label} + + ) : null} + + + + ); + })} + + ); +} + +export function LinkCard({ counts, links1, links2 }: { counts: FollowerCounts; links1: readonly LinkConfig[]; links2: readonly LinkConfig[] }) { + return ( + } + secondary={} + /> ); } diff --git a/components/link-carousel.tsx b/components/link-carousel.tsx new file mode 100644 index 0000000..123d1cb --- /dev/null +++ b/components/link-carousel.tsx @@ -0,0 +1,53 @@ +"use client"; + +import { useState, type ReactNode } from "react"; +import { ArrowLeft, ArrowRight } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { CardContent } from "@/components/ui/card"; + +export function LinkCarousel({ + primary, + secondary, +}: { + primary: ReactNode; + secondary: ReactNode; +}) { + const [page, setPage] = useState<0 | 1>(0); + + return ( + +
+ {page === 0 ? primary : secondary} +
+
+ + + {page + 1} / 2 + + +
+
+ ); +}