From d90236bcf01c43c4c8fd51e3ee9d19b289e0b40b Mon Sep 17 00:00:00 2001 From: mzaxd Date: Mon, 23 Feb 2026 18:12:54 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E8=B0=83=E6=95=B4=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E7=BB=9F=E8=AE=A1=E4=B8=8E=E6=A0=87=E7=AD=BE=E6=B4=9E?= =?UTF-8?q?=E5=AF=9F=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/[locale]/page.tsx | 10 +-- src/app/globals.css | 55 +++++++++++++ src/components/home/HomeOverviewStats.tsx | 17 ++-- src/components/home/HomeRankings.tsx | 15 ++-- src/components/home/HomeTagInsights.tsx | 99 ++++++----------------- src/hooks/useHome.ts | 82 +++++-------------- src/messages/en.json | 12 +-- src/messages/zh.json | 12 +-- 8 files changed, 134 insertions(+), 168 deletions(-) diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 53c81ff..c213175 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -56,10 +56,9 @@ export default async function HomePage({ params }: HomePageProps) { translations={{ sectionTitle: t('insightsSection'), totalProjects: t('statsTotalProjects'), - activeProjects: t('statsActiveProjects'), - archivedProjects: t('statsArchivedProjects'), - totalTags: t('statsTotalTags'), + newProjects30d: t('statsNewProjects30d'), newProjects7d: t('statsNewProjects7d'), + newProjects24h: t('statsNewProjects24h'), }} /> @@ -84,13 +83,8 @@ export default async function HomePage({ params }: HomePageProps) { {translations.sectionTitle} -
+
{cards.map((card) => (
{showStars && ( - - ★ {formatNumber(project.githubStars, locale)} + + )}
@@ -85,13 +90,13 @@ export function HomeRankings({ topStars, translations, }: HomeRankingsProps) { - const [activeWindow, setActiveWindow] = useState('7d') + const [activeWindow, setActiveWindow] = useState('30d') const windowOptions = useMemo( () => [ - { key: '24h' as const, label: translations.window24h }, - { key: '7d' as const, label: translations.window7d }, { key: '30d' as const, label: translations.window30d }, + { key: '7d' as const, label: translations.window7d }, + { key: '24h' as const, label: translations.window24h }, ], [translations.window24h, translations.window7d, translations.window30d] ) diff --git a/src/components/home/HomeTagInsights.tsx b/src/components/home/HomeTagInsights.tsx index 1d035fb..a331469 100644 --- a/src/components/home/HomeTagInsights.tsx +++ b/src/components/home/HomeTagInsights.tsx @@ -1,5 +1,4 @@ import Link from 'next/link' -import type { HomeCategoryDistribution } from '@/hooks/useHome' interface HomeTagInsightsProps { locale: string @@ -10,13 +9,8 @@ interface HomeTagInsightsProps { slug: string projectCount: number }> - categories: HomeCategoryDistribution[] translations: { sectionTitle: string - topTagsTitle: string - categoryDistributionTitle: string - tagsUnit: string - projectsUnit: string noTagData: string viewAllProjects: string } @@ -30,10 +24,10 @@ function formatNumber(value: number, locale: string): string { export function HomeTagInsights({ locale, topTags, - categories, translations, }: HomeTagInsightsProps) { - const maxAssociations = Math.max(1, ...categories.map((category) => category.projectAssociationCount)) + const marqueeItems = [...topTags, ...topTags] + const animationDurationSeconds = Math.max(18, topTags.length * 4) return (
@@ -41,16 +35,18 @@ export function HomeTagInsights({

{translations.sectionTitle}

-
-
-

{translations.topTagsTitle}

- {topTags.length > 0 ? ( -
- {topTags.map((tag) => ( +
+ {topTags.length > 0 ? ( +
+
+ {marqueeItems.map((tag, index) => ( {locale === 'en' && tag.nameEn ? tag.nameEn : tag.name} @@ -59,67 +55,20 @@ export function HomeTagInsights({ ))}
- ) : ( -

{translations.noTagData}

- )} - -
- - {translations.viewAllProjects} -
-
+ ) : ( +

{translations.noTagData}

+ )} -
-

{translations.categoryDistributionTitle}

- {categories.length > 0 ? ( -
- {categories.map((category) => { - const categoryName = - locale === 'en' ? category.nameEn : category.name - const widthPercent = Math.max( - 6, - Math.round((category.projectAssociationCount / maxAssociations) * 100) - ) - - return ( -
-
-

{categoryName}

-

- {formatNumber(category.tagCount, locale)} {translations.tagsUnit} ·{' '} - {formatNumber(category.projectAssociationCount, locale)} {translations.projectsUnit} -

-
-
- - {category.topTag && ( - - {locale === 'en' && category.topTag.nameEn - ? category.topTag.nameEn - : category.topTag.name} - - )} -
- ) - })} -
- ) : ( -

{translations.noTagData}

- )} -
-
+
+ + {translations.viewAllProjects} + +
+
) } diff --git a/src/hooks/useHome.ts b/src/hooks/useHome.ts index 9572d43..84b03fe 100644 --- a/src/hooks/useHome.ts +++ b/src/hooks/useHome.ts @@ -1,5 +1,5 @@ import { prisma } from '@/lib/prisma' -import { getTagCategoryGroups, getTopTags } from '@/hooks/useProjects' +import { getTopTags } from '@/hooks/useProjects' import { Prisma } from '@prisma/client' const ONE_DAY_MS = 24 * 60 * 60 * 1000 @@ -24,28 +24,12 @@ export type HomeProjectSummary = { }> } -export type HomeCategoryDistribution = { - category: string - name: string - nameEn: string - tagCount: number - projectAssociationCount: number - topTag: { - id: string - name: string - nameEn: string | null - slug: string - projectCount: number - } | null -} - export type HomePageData = { overview: { totalProjects: number - activeProjects: number - archivedProjects: number - totalTags: number + newProjects30d: number newProjects7d: number + newProjects24h: number } rankings: { latestByWindow: { @@ -63,7 +47,6 @@ export type HomePageData = { slug: string projectCount: number }> - categoryDistribution: HomeCategoryDistribution[] } timeline: HomeProjectSummary[] } @@ -162,29 +145,23 @@ export async function getHomePageData(): Promise { const [ totalProjects, - activeProjects, - archivedProjects, - totalTags, + newProjects30d, newProjects7d, + newProjects24h, latest24h, latest7d, latest30d, topStars, timeline, topTags, - tagCategoryGroups, ] = await Promise.all([ safeQuery('countTotalProjects', 0, () => prisma.project.count()), - safeQuery('countActiveProjects', 0, () => prisma.project.count({ where: { status: 'ACTIVE' } })), - safeQuery('countArchivedProjects', 0, () => prisma.project.count({ where: { status: 'ARCHIVED' } })), - safeQuery('countTotalTags', 0, () => - prisma.tag.count({ + safeQuery('countNewProjects30d', 0, () => + prisma.project.count({ where: { - category: { - not: 'FIXED_PROJECT_TYPE', - }, - projects: { - some: {}, + status: 'ACTIVE', + createdAt: { + gte: last30Days, }, }, }) @@ -199,44 +176,30 @@ export async function getHomePageData(): Promise { }, }) ), + safeQuery('countNewProjects24h', 0, () => + prisma.project.count({ + where: { + status: 'ACTIVE', + createdAt: { + gte: last24Hours, + }, + }, + }) + ), getLatestProjects(DEFAULT_RANKING_LIMIT, last24Hours), getLatestProjects(DEFAULT_RANKING_LIMIT, last7Days), getLatestProjects(DEFAULT_RANKING_LIMIT, last30Days), getTopStarsProjects(DEFAULT_RANKING_LIMIT), getLatestProjects(DEFAULT_TIMELINE_LIMIT), getTopTags(DEFAULT_TOP_TAG_LIMIT), - getTagCategoryGroups(), ]) - const categoryDistribution: HomeCategoryDistribution[] = tagCategoryGroups.map((group) => { - const projectAssociationCount = group.tags.reduce((sum, tag) => sum + tag._count.projects, 0) - const leadingTag = group.tags[0] - - return { - category: group.category, - name: group.name, - nameEn: group.nameEn, - tagCount: group.tags.length, - projectAssociationCount, - topTag: leadingTag - ? { - id: leadingTag.id, - name: leadingTag.name, - nameEn: leadingTag.nameEn, - slug: leadingTag.slug, - projectCount: leadingTag._count.projects, - } - : null, - } - }) - return { overview: { totalProjects, - activeProjects, - archivedProjects, - totalTags, + newProjects30d, newProjects7d, + newProjects24h, }, rankings: { latestByWindow: { @@ -254,7 +217,6 @@ export async function getHomePageData(): Promise { slug: tag.slug, projectCount: tag._count.projects, })), - categoryDistribution, }, timeline, } diff --git a/src/messages/en.json b/src/messages/en.json index d5cf535..f39cbf1 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -22,15 +22,15 @@ "projectCount": "projects" }, "home": { - "title": "AI Project Navigator", + "title": "Agent Project Navigator", "subtitle": "Discover and explore AI projects", "featuredProjects": "Featured Projects", "browseByTag": "Browse by Tag", "searchPlaceholder": "Search AI projects...", "aiSearchPlaceholder": "Describe what you're looking for, e.g.: AI tools that can generate videos...", - "metaTitle": "Agent Park - AI Project Navigator", + "metaTitle": "Agent Park - Agent Project Navigator", "metaDescription": "Discover and explore quality AI projects from across the web", - "heroTitle": "AI PROJECT", + "heroTitle": "AGENT PROJECT", "heroTitle2": "NAVIGATOR", "heroDescription": "Discover and explore high-quality AI projects from across the web. Curated for developers and enthusiasts.", "browseByTagsSection": "BROWSE BY TAGS", @@ -41,6 +41,8 @@ "statsTotalProjects": "Total Projects", "statsActiveProjects": "Active Projects", "statsArchivedProjects": "Archived Projects", + "statsNewProjects30d": "New in 30 Days", + "statsNewProjects24h": "New in 24h", "statsTotalTags": "Total Tags", "statsNewProjects7d": "New in 7 Days", "rankingsSection": "Project Rankings", @@ -53,8 +55,8 @@ "noStarsProjects": "No stars data available", "viewAllLatest": "View all latest projects", "viewAllByStars": "View all by stars", - "tagInsightsSection": "Tag Popularity & Distribution", - "topTagsTitle": "Top Tags", + "tagInsightsSection": "Top Tags", + "topTagsTitle": "Top Tags Carousel", "categoryDistributionTitle": "Category Distribution", "tagsUnit": "tags", "projectsUnit": "projects", diff --git a/src/messages/zh.json b/src/messages/zh.json index 70d9b3b..42bc72d 100644 --- a/src/messages/zh.json +++ b/src/messages/zh.json @@ -22,15 +22,15 @@ "projectCount": "个项目" }, "home": { - "title": "AI 项目导航", + "title": "Agent 项目导航", "subtitle": "发现和探索全网优质 AI 项目", "featuredProjects": "精选项目", "browseByTag": "按标签浏览", "searchPlaceholder": "搜索 AI 项目...", "aiSearchPlaceholder": "描述你想要的项目,如:能生成视频的 AI 工具...", - "metaTitle": "Agent Park - AI 项目导航", + "metaTitle": "Agent Park - Agent 项目导航", "metaDescription": "发现和探索全网优质 AI 项目", - "heroTitle": "AI 项目", + "heroTitle": "Agent 项目", "heroTitle2": "导航", "heroDescription": "发现和探索来自全网的高质量 AI 项目。为开发者和爱好者精心策划。", "browseByTagsSection": "按标签浏览", @@ -41,6 +41,8 @@ "statsTotalProjects": "项目总数", "statsActiveProjects": "活跃项目", "statsArchivedProjects": "归档项目", + "statsNewProjects30d": "近30天新增", + "statsNewProjects24h": "近24小时新增", "statsTotalTags": "标签总数", "statsNewProjects7d": "近7天新增", "rankingsSection": "项目榜单", @@ -53,8 +55,8 @@ "noStarsProjects": "暂无可展示的 Stars 数据", "viewAllLatest": "查看全部最新项目", "viewAllByStars": "查看全部 Stars 排序", - "tagInsightsSection": "标签热度与分布", - "topTagsTitle": "热门标签", + "tagInsightsSection": "热门标签", + "topTagsTitle": "热门标签轮播", "categoryDistributionTitle": "分类分布", "tagsUnit": "个标签", "projectsUnit": "个项目",