diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx
index 279bf83..ae51ac8 100644
--- a/src/app/[locale]/page.tsx
+++ b/src/app/[locale]/page.tsx
@@ -12,6 +12,7 @@ interface HomePageProps {
export default async function HomePage({ params }: HomePageProps) {
const { locale } = await params
const t = await getTranslations('home')
+ const tCommon = await getTranslations('common')
const [projectsData, tags] = await Promise.all([
getProjects({ limit: 6 }),
@@ -33,7 +34,11 @@ export default async function HomePage({ params }: HomePageProps) {
Discover and explore high-quality AI projects from across the web. Curated for developers and enthusiasts.
diff --git a/src/app/api/webhook/projects/route.ts b/src/app/api/webhook/projects/route.ts
index ddb1844..6141298 100644
--- a/src/app/api/webhook/projects/route.ts
+++ b/src/app/api/webhook/projects/route.ts
@@ -28,7 +28,11 @@ async function findExistingProject(projectData: ProjectInput) {
url: githubLink.url,
},
include: {
- project: true,
+ project: {
+ include: {
+ links: true,
+ },
+ },
},
})
@@ -51,7 +55,11 @@ async function findExistingProject(projectData: ProjectInput) {
url: websiteLink.url,
},
include: {
- project: true,
+ project: {
+ include: {
+ links: true,
+ },
+ },
},
})
@@ -70,6 +78,9 @@ async function findExistingProject(projectData: ProjectInput) {
const existingBySlug = await prisma.project.findUnique({
where: { slug },
+ include: {
+ links: true,
+ },
})
if (existingBySlug) {
diff --git a/src/components/locale/LocaleSwitcher.tsx b/src/components/locale/LocaleSwitcher.tsx
index dfe5e82..bee6c26 100644
--- a/src/components/locale/LocaleSwitcher.tsx
+++ b/src/components/locale/LocaleSwitcher.tsx
@@ -1,6 +1,5 @@
'use client'
-import { usePathname } from 'next/navigation'
import Link from 'next/link'
const locales = ['zh', 'en'] as const
@@ -9,30 +8,12 @@ const localeNames: Record
= {
en: 'EN'
}
-export function LocaleSwitcher({ currentLocale }: { currentLocale: string }) {
- const pathname = usePathname()
-
- // 移除当前语言前缀,获取基础路径
- const getBasePathname = () => {
- const segments = pathname.split('/').filter(Boolean)
- if (segments[0] && locales.includes(segments[0] as any)) {
- return '/' + segments.slice(1).join('/')
- }
- return pathname
- }
-
- const basePathname = getBasePathname()
-
- const switchLocale = (newLocale: string) => {
- // 切换到另一种语言
- return `/${newLocale}${basePathname}`
- }
-
+export function LocaleSwitcher({ currentLocale, switchUrl }: { currentLocale: string; switchUrl: string }) {
const otherLocale = currentLocale === 'zh' ? 'en' : 'zh'
return (
{localeNames[currentLocale]} / {localeNames[otherLocale]}
diff --git a/src/components/project/ExternalLinkCard.tsx b/src/components/project/ExternalLinkCard.tsx
index 398a9b4..c998b2b 100644
--- a/src/components/project/ExternalLinkCard.tsx
+++ b/src/components/project/ExternalLinkCard.tsx
@@ -1,26 +1,39 @@
-import { ExternalLink } from '@prisma/client'
+import { ExternalLink, LinkType } from '@prisma/client'
+import { getTranslations } from 'next-intl/server'
interface ExternalLinkCardProps {
links: ExternalLink[]
+ locale: string
}
-const linkTypeNames = {
- WEBSITE: '官网',
- GITHUB: 'GitHub',
- HUGGINGFACE: 'HuggingFace',
- PAPER: '论文',
-}
+export async function ExternalLinkCard({ links, locale }: ExternalLinkCardProps) {
+ const t = await getTranslations('project')
-export function ExternalLinkCard({ links }: ExternalLinkCardProps) {
if (links.length === 0) {
return null
}
+ // Build type map for all link types
+ const typeMap: Record = {
+ WEBSITE: t('website'),
+ GITHUB: t('github'),
+ HUGGINGFACE: t('huggingface'),
+ PAPER: t('paper'),
+ }
+
+ // Pre-resolve all link names
+ const linkItems = await Promise.all(
+ links.map(async (link) => ({
+ ...link,
+ displayName: link.title || typeMap[link.type]
+ }))
+ )
+
return (
-
外部链接
+
{t('externalLinks')}
@@ -71,7 +78,7 @@ export function ProjectCard({ project, locale, featured = false }: ProjectCardPr
href={`/${locale}/projects/${project.slug}`}
className="inline-flex items-center font-display font-bold text-sm uppercase hover:text-secondary dark:hover:text-primary group"
>
- VIEW DETAILS{' '}
+ {t('viewDetails')}{' '}
→
@@ -80,21 +87,22 @@ export function ProjectCard({ project, locale, featured = false }: ProjectCardPr
}
// Special card for "Submit Your Project" CTA
-export function SubmitProjectCard({ locale }: { locale: string }) {
+export async function SubmitProjectCard({ locale }: { locale: string }) {
+ const t = await getTranslations('project')
return (
+
- Submit Your Project
+ {t('submitProjectTitle')}
- Have an AI tool worth sharing? Add it to Agent Park.
+ {t('submitProjectDescription')}
- SUBMIT NOW
+ {t('submitNow')}
)
diff --git a/src/components/project/ProjectDetail.tsx b/src/components/project/ProjectDetail.tsx
index 2c3f9c5..1e834f7 100644
--- a/src/components/project/ProjectDetail.tsx
+++ b/src/components/project/ProjectDetail.tsx
@@ -1,7 +1,6 @@
-'use client'
-
import Link from 'next/link'
import { MarkdownContent } from './MarkdownContent'
+import { ShareButtons } from './ShareButtons'
interface ProjectDetailProps {
project: {
@@ -31,14 +30,22 @@ interface ProjectDetailProps {
locale: string
}
-// Helper function to format date
+// Helper function to format date - using ISO format for consistency
function formatDate(date: Date | string, locale: string): string {
const dateObj = typeof date === 'string' ? new Date(date) : date
- const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'short', day: 'numeric' }
- return dateObj.toLocaleDateString(locale === 'en' ? 'en-US' : 'zh-CN', options)
+ const year = dateObj.getFullYear()
+ const month = dateObj.getMonth() + 1
+ const day = dateObj.getDate()
+
+ if (locale === 'en') {
+ const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+ return `${monthNames[month - 1]} ${day}, ${year}`
+ } else {
+ return `${year}年${month}月${day}日`
+ }
}
-export function ProjectDetail({ project, locale }: ProjectDetailProps) {
+export async function ProjectDetail({ project, locale }: ProjectDetailProps) {
const displayName = locale === 'en' && project.nameEn ? project.nameEn : project.name
const displayDescription =
locale === 'en' && project.descriptionEn ? project.descriptionEn : project.description
@@ -49,20 +56,6 @@ export function ProjectDetail({ project, locale }: ProjectDetailProps) {
const categoryEn = project.tags[0]?.nameEn || project.tags[0]?.name || 'AI Agent'
const displayCategory = locale === 'en' ? categoryEn : category
- const handleShare = () => {
- if (typeof window !== 'undefined') {
- const url = encodeURIComponent(window.location.href)
- const text = encodeURIComponent(`Check out ${displayName} on Agent Park`)
- window.open(`https://twitter.com/intent/tweet?url=${url}&text=${text}`, '_blank')
- }
- }
-
- const handleCopyLink = () => {
- if (typeof window !== 'undefined') {
- navigator.clipboard.writeText(window.location.href)
- }
- }
-
return (
<>
{/* Header Section */}
@@ -153,31 +146,8 @@ npm install`}
)}
- {/* Share and Feedback Section */}
-
-
-
-
-
-
- DID THIS AGENT HELP YOU?
-
-
-
+ {/* Share and Feedback Section - Temporarily disabled for debugging */}
+ {/* */}
>
)
}
diff --git a/src/components/project/ProjectList.tsx b/src/components/project/ProjectList.tsx
index 44f4f71..50ca0e6 100644
--- a/src/components/project/ProjectList.tsx
+++ b/src/components/project/ProjectList.tsx
@@ -1,4 +1,5 @@
import { ProjectCard, SubmitProjectCard } from './ProjectCard'
+import { getTranslations } from 'next-intl/server'
interface ProjectListProps {
projects: Array<{
@@ -19,11 +20,13 @@ interface ProjectListProps {
featured?: boolean
}
-export function ProjectList({ projects, locale, featured = false }: ProjectListProps) {
+export async function ProjectList({ projects, locale, featured = false }: ProjectListProps) {
+ const t = await getTranslations('common')
+
if (projects.length === 0) {
return (
-
暂无项目
+
{t('noProjects')}
)
}
diff --git a/src/components/project/ShareButtons.tsx b/src/components/project/ShareButtons.tsx
new file mode 100644
index 0000000..ce96d3c
--- /dev/null
+++ b/src/components/project/ShareButtons.tsx
@@ -0,0 +1,52 @@
+'use client'
+
+interface ShareButtonsProps {
+ displayName: string
+}
+
+export function ShareButtons({ displayName }: ShareButtonsProps) {
+ const handleShare = () => {
+ const url = encodeURIComponent(window.location.href)
+ const text = encodeURIComponent(`Check out ${displayName} on Agent Park`)
+ window.open(`https://twitter.com/intent/tweet?url=${url}&text=${text}`, '_blank')
+ }
+
+ const handleCopyLink = () => {
+ navigator.clipboard.writeText(window.location.href)
+ }
+
+ return (
+
+
+
+
+
+
+ DID THIS AGENT HELP YOU?
+
+
+
+ )
+}
diff --git a/src/components/search/SearchBar.tsx b/src/components/search/SearchBar.tsx
index 933a47f..8c11a05 100644
--- a/src/components/search/SearchBar.tsx
+++ b/src/components/search/SearchBar.tsx
@@ -5,9 +5,11 @@ import { useRouter, useSearchParams } from 'next/navigation'
interface SearchBarProps {
locale: string
+ searchPlaceholder: string
+ searchLabel: string
}
-export function SearchBar({ locale }: SearchBarProps) {
+export function SearchBar({ locale, searchPlaceholder, searchLabel }: SearchBarProps) {
const router = useRouter()
const searchParams = useSearchParams()
const [query, setQuery] = useState(searchParams.get('search') || '')
@@ -36,7 +38,7 @@ export function SearchBar({ locale }: SearchBarProps) {
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
- placeholder="Search AI projects..."
+ placeholder={searchPlaceholder}
className="block w-full pl-12 pr-32 py-4 bg-surface-light dark:bg-surface-dark border-2 border-black dark:border-gray-600 text-text-light dark:text-text-dark placeholder-gray-500 focus:ring-0 focus:border-black dark:focus:border-primary font-display shadow-neo transition-all"
/>
@@ -45,7 +47,7 @@ export function SearchBar({ locale }: SearchBarProps) {
type="submit"
className="absolute inset-y-2 right-2 px-4 bg-primary text-black font-bold font-display text-sm border-2 border-black hover:bg-yellow-400 transition-colors shadow-neo-sm active:shadow-none active:translate-x-[2px] active:translate-y-[2px]"
>
- SEARCH
+ {searchLabel}