refactor: remove ArticleFeed, keep only CommunityFeed

- Remove ArticleFeed and ArticleFeedClient components
- Update template types to remove ArticleFeed
- Update default template configuration
- Update app/page.tsx to remove ArticleFeed
- Keep only CommunityFeed for blog updates (latest 3 posts)
- All blog content now uses CommunityFeed

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
Haitao Pan 2025-11-11 12:55:23 +08:00
parent ae1c77aada
commit 851c82ea7b
6 changed files with 1 additions and 127 deletions

View File

@ -1,6 +1,5 @@
export const dynamic = 'error'
import ArticleFeed from '@components/home/ArticleFeed'
import ProductMatrix from '@components/home/ProductMatrix'
import Sidebar from '@components/home/Sidebar'
import CommunityFeedServer from '@components/home/CommunityFeedServer'
@ -21,7 +20,6 @@ export default function HomePage() {
<HomePageTemplate
slots={{
ProductMatrix,
ArticleFeed: ArticleFeed,
CommunityFeed: CommunityFeedServer,
Sidebar,
}}

View File

@ -1,8 +0,0 @@
import { getHomepagePosts } from '@cms/content'
import ArticleFeedClient from './ArticleFeedClient'
export default async function ArticleFeed() {
const posts = await getHomepagePosts()
return <ArticleFeedClient posts={posts} />
}

View File

@ -1,112 +0,0 @@
'use client'
import Link from 'next/link'
import { useMemo } from 'react'
import type { HomepagePost } from '@cms/content'
import { useLanguage } from '@i18n/LanguageProvider'
import { translations } from '@i18n/translations'
type ArticleFeedClientProps = {
posts: HomepagePost[]
}
function formatDate(value: string | undefined, locale: string) {
if (!value) return undefined
const date = new Date(value)
if (Number.isNaN(date.getTime())) {
return value
}
return new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'short',
day: 'numeric',
}).format(date)
}
export default function ArticleFeedClient({ posts }: ArticleFeedClientProps) {
const { language } = useLanguage()
const marketing = translations[language].marketing.home
const { articleFeed } = marketing
const articleOverrides = marketing.articleOverrides
const mappedPosts = useMemo(
() =>
posts.map((post) => {
const override = articleOverrides?.[post.slug]
return {
...post,
title: override?.title ?? post.title,
author: override?.author ?? post.author,
readingTime: override?.readingTime ?? post.readingTime,
excerpt: override?.excerpt ?? post.excerpt,
tags: override?.tags ?? post.tags,
formattedDate: formatDate(post.date, articleFeed.dateLocale),
}
}),
[articleFeed.dateLocale, articleOverrides, posts],
)
return (
<section className="space-y-8 text-brand-heading">
<header className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
<div className="space-y-2">
<p className="text-xs font-semibold uppercase tracking-[0.32em] text-brand">{articleFeed.eyebrow}</p>
<h2 className="text-2xl font-semibold text-brand-navy sm:text-[26px]">{articleFeed.title}</h2>
</div>
<Link
href="/docs"
className="text-sm font-medium text-brand transition hover:text-brand-light"
>
{articleFeed.viewAll}
</Link>
</header>
<div className="space-y-8">
{!mappedPosts.length ? (
<p className="rounded-2xl border border-dashed border-brand-border bg-white p-8 text-center text-sm text-brand-heading/70">
{articleFeed.empty}
</p>
) : null}
{mappedPosts.map((post) => (
<article
key={post.slug}
className="group rounded-2xl border border-brand-border bg-white p-6 text-brand-heading shadow-[0_4px_20px_rgba(0,0,0,0.04)] transition hover:-translate-y-1 hover:border-brand hover:shadow-[0_6px_24px_rgba(51,102,255,0.2)] sm:p-8"
>
<div className="flex flex-wrap items-center gap-2 text-xs text-brand-heading/60 sm:text-sm">
{post.formattedDate ? <span>{post.formattedDate}</span> : null}
{post.author ? (
<span className="flex items-center gap-2">
<span className="hidden h-1 w-1 rounded-full bg-brand-border sm:inline" aria-hidden />
<span>{post.author}</span>
</span>
) : null}
{post.readingTime ? (
<span className="flex items-center gap-2">
<span className="hidden h-1 w-1 rounded-full bg-brand-border sm:inline" aria-hidden />
<span>{post.readingTime}</span>
</span>
) : null}
</div>
<h3 className="mt-4 text-lg font-medium text-brand-heading transition group-hover:text-brand sm:text-xl">
{post.title}
</h3>
{post.excerpt ? <p className="mt-3 text-sm text-brand-heading/80 sm:text-base">{post.excerpt}</p> : null}
{post.tags.length ? (
<div className="mt-5 flex flex-wrap gap-2">
{post.tags.map((tag) => (
<span
key={tag}
className="inline-flex items-center rounded-full border border-brand-border bg-brand-surface px-3 py-1 text-xs font-medium text-brand-heading"
>
#{tag}
</span>
))}
</div>
) : null}
</article>
))}
</div>
</section>
)
}

View File

@ -18,7 +18,6 @@ export const defaultHomeLayoutConfig: CommonHomeLayoutConfig = {
contentClassName: 'mx-auto w-full max-w-6xl',
gridClassName: 'grid gap-8 lg:grid-cols-[minmax(0,1fr)_360px] lg:items-start lg:gap-12',
slots: [
{ key: 'ArticleFeed' },
{ key: 'CommunityFeed' },
{ key: 'Sidebar' },
],

View File

@ -1,4 +1,3 @@
import ArticleFeed from '@components/home/ArticleFeed'
import ProductMatrix from '@components/home/ProductMatrix'
import Sidebar from '@components/home/Sidebar'
@ -9,7 +8,6 @@ import type { TemplateDefinition } from '../types'
const DefaultHomePageTemplate = createCommonHomeTemplate(defaultHomeLayoutConfig, {
ProductMatrix,
ArticleFeed,
Sidebar,
})

View File

@ -13,12 +13,11 @@ export type TemplateComponent<TSlots extends TemplateSlots = TemplateSlots> = Co
export interface HomePageTemplateSlots extends TemplateSlots {
ProductMatrix: ComponentType
ArticleFeed: ComponentType
CommunityFeed: ComponentType
Sidebar: ComponentType
}
export type HomePageSlotKey = 'ProductMatrix' | 'ArticleFeed' | 'CommunityFeed' | 'Sidebar'
export type HomePageSlotKey = 'ProductMatrix' | 'CommunityFeed' | 'Sidebar'
export type HomePageTemplateProps = TemplateRenderProps<HomePageTemplateSlots>