Skip to content

Commit 24c6ad2

Browse files
ericyangpanclaude
andcommitted
refactor(templates): introduce entity-based template architecture with reusable sections
- Created entity template hierarchy: EntityDetailTemplate, ModelDetailTemplate, OrganizationDetailTemplate, VendorEntityDetailTemplate - Created reusable section components: EntityBenchmarks, EntityCommunityLinks, EntityModelsGrid, EntityPlatformLinks, EntityProductsGrid, EntitySpecifications - Refactored models, model-providers, and vendors detail pages to use new templates - Simplified ProductDetailTemplate to use VendorEntityDetailTemplate as base 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 9fceb64 commit 24c6ad2

17 files changed

+1186
-490
lines changed
Lines changed: 48 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import { notFound } from 'next/navigation'
22
import { getTranslations } from 'next-intl/server'
3-
import { BackToNavigation } from '@/components/controls/BackToNavigation'
4-
import { Breadcrumb } from '@/components/controls/Breadcrumb'
5-
import Footer from '@/components/Footer'
6-
import Header from '@/components/Header'
7-
import { JsonLd } from '@/components/JsonLd'
8-
import { LinkCardGrid, ProductHero } from '@/components/product'
93
import type { Locale } from '@/i18n/config'
104
import { getModelProvider } from '@/lib/data/fetchers'
115
import { providersData as providers } from '@/lib/generated'
126
import { generateSoftwareDetailMetadata } from '@/lib/metadata'
7+
import { OrganizationDetailTemplate } from '@/templates'
138

149
export const revalidate = 3600
1510

@@ -59,126 +54,53 @@ export default async function ProviderPage({
5954
const t = await getTranslations({ locale, namespace: 'pages.modelProviderDetail' })
6055
const tGlobal = await getTranslations({ locale })
6156

62-
const websiteUrl = provider.websiteUrl
63-
const docsUrl = provider.docsUrl || undefined
64-
65-
// Configuration for AI platform links
66-
const AI_PLATFORM_LINKS = [
67-
{
68-
key: 'huggingface',
69-
title: t('aiPlatforms.huggingface.title'),
70-
description: t('aiPlatforms.huggingface.description'),
71-
},
72-
{
73-
key: 'artificialAnalysis',
74-
title: t('aiPlatforms.artificialAnalysis.title'),
75-
description: t('aiPlatforms.artificialAnalysis.description'),
76-
},
77-
{
78-
key: 'openrouter',
79-
title: t('aiPlatforms.openrouter.title'),
80-
description: t('aiPlatforms.openrouter.description'),
81-
},
82-
]
83-
84-
// Configuration for community links
85-
const COMMUNITY_LINKS = [
86-
{
87-
key: 'linkedin',
88-
title: t('community.linkedin.title'),
89-
description: t('community.linkedin.description'),
90-
},
91-
{
92-
key: 'twitter',
93-
title: t('community.twitter.title'),
94-
description: t('community.twitter.description'),
95-
},
96-
{
97-
key: 'github',
98-
title: t('community.github.title'),
99-
description: t('community.github.description'),
100-
},
101-
{
102-
key: 'youtube',
103-
title: t('community.youtube.title'),
104-
description: t('community.youtube.description'),
105-
},
106-
{
107-
key: 'discord',
108-
title: t('community.discord.title'),
109-
description: t('community.discord.description'),
110-
},
111-
{
112-
key: 'reddit',
113-
title: t('community.reddit.title'),
114-
description: t('community.reddit.description'),
115-
},
116-
]
117-
118-
// Schema.org structured data
119-
const organizationSchema = {
120-
'@context': 'https://schema.org',
121-
'@type': 'Organization',
122-
name: provider.name,
123-
description: provider.description,
124-
url: provider.websiteUrl,
125-
}
126-
12757
return (
128-
<>
129-
<JsonLd data={organizationSchema} />
130-
<Header />
131-
132-
<Breadcrumb
133-
items={[
134-
{ name: tGlobal('shared.common.aiCodingStack'), href: '/ai-coding-stack' },
135-
{ name: tGlobal('shared.stacks.modelProviders'), href: 'model-providers' },
136-
{ name: provider.name, href: `model-providers/${provider.id}` },
137-
]}
138-
/>
139-
140-
{/* Hero Section */}
141-
<ProductHero
142-
name={provider.name}
143-
description={provider.description}
144-
category="PROVIDER"
145-
categoryLabel={t('categoryLabel')}
146-
verified={provider.verified ?? false}
147-
type={provider.type}
148-
websiteUrl={websiteUrl}
149-
docsUrl={docsUrl}
150-
applyKeyUrl={provider.applyKeyUrl}
151-
labels={{
152-
type: t('type'),
153-
typeValue: provider.type ? t(`providerTypes.${provider.type}`) : undefined,
154-
visitWebsite: t('visitWebsite'),
155-
documentation: t('documentation'),
156-
getApiKey: t('getApiKey'),
157-
}}
158-
/>
159-
160-
{/* Find on AI Platforms */}
161-
<LinkCardGrid
162-
title={t('findOnAiPlatforms')}
163-
links={AI_PLATFORM_LINKS}
164-
urls={provider.platformUrls || {}}
165-
layout="horizontal"
166-
gridCols="grid-cols-1 md:grid-cols-3"
167-
/>
168-
169-
{/* Community Links */}
170-
<LinkCardGrid
171-
title={t('communityLinks')}
172-
links={COMMUNITY_LINKS}
173-
urls={provider.communityUrls || {}}
174-
layout="vertical"
175-
gridCols="grid-cols-2 md:grid-cols-4"
176-
/>
177-
178-
{/* Navigation */}
179-
<BackToNavigation href="/model-providers" title={t('allModelProviders')} />
180-
181-
<Footer />
182-
</>
58+
<OrganizationDetailTemplate
59+
organization={{
60+
...provider,
61+
type: provider.type,
62+
applyKeyUrl: provider.applyKeyUrl,
63+
platformUrls: provider.platformUrls,
64+
communityUrls: provider.communityUrls,
65+
}}
66+
locale={locale}
67+
breadcrumbs={[
68+
{ name: tGlobal('shared.common.aiCodingStack'), href: '/ai-coding-stack' },
69+
{ name: tGlobal('shared.stacks.modelProviders'), href: '/model-providers' },
70+
{ name: provider.name, href: `model-providers/${provider.id}` },
71+
]}
72+
backToHref="/model-providers"
73+
backToTitle={t('allModelProviders')}
74+
categoryLabel={t('categoryLabel')}
75+
translations={{
76+
type: t('type'),
77+
typeValue: provider.type ? t(`providerTypes.${provider.type}`) : undefined,
78+
visitWebsite: t('visitWebsite'),
79+
documentation: t('documentation'),
80+
getApiKey: t('getApiKey'),
81+
platformLinksTitle: t('findOnAiPlatforms'),
82+
huggingfaceTitle: t('aiPlatforms.huggingface.title'),
83+
huggingfaceDesc: t('aiPlatforms.huggingface.description'),
84+
artificialAnalysisTitle: t('aiPlatforms.artificialAnalysis.title'),
85+
artificialAnalysisDesc: t('aiPlatforms.artificialAnalysis.description'),
86+
openrouterTitle: t('aiPlatforms.openrouter.title'),
87+
openrouterDesc: t('aiPlatforms.openrouter.description'),
88+
communityLinksTitle: t('communityLinks'),
89+
linkedinTitle: t('community.linkedin.title'),
90+
linkedinDesc: t('community.linkedin.description'),
91+
twitterTitle: t('community.twitter.title'),
92+
twitterDesc: t('community.twitter.description'),
93+
githubTitle: t('community.github.title'),
94+
githubDesc: t('community.github.description'),
95+
youtubeTitle: t('community.youtube.title'),
96+
youtubeDesc: t('community.youtube.description'),
97+
discordTitle: t('community.discord.title'),
98+
discordDesc: t('community.discord.description'),
99+
redditTitle: t('community.reddit.title'),
100+
redditDesc: t('community.reddit.description'),
101+
}}
102+
showPlatformLinks={true}
103+
showCommunityLinks={true}
104+
/>
183105
)
184106
}

0 commit comments

Comments
 (0)