Skip to content

Commit 8c8e4b7

Browse files
authored
refactor(landing): DRY page metadata via buildLandingMetadata + derive pricing credits (#5299)
* refactor(landing): buildLandingMetadata helper + derive pricing credit cells - Add lib/landing/seo.ts buildLandingMetadata(), the single source of truth for the shared landing OpenGraph/Twitter/robots/canonical chrome; migrate 13 static landing pages to it (drop ~470 lines of duplicated literals). Output is identical per page (verified: rendered head tags unchanged, render mode unchanged); partners additionally gains the standard authors/creator/publisher it was missing. - Drop the now-dead PAGE_URL const + SITE_URL import from the 12 migrated pages that no longer reference them (partners keeps both for its JSON-LD). - comparison-data.ts: derive monthly/daily credit cells from CREDIT_TIERS, DEFAULT_FREE_CREDITS, DAILY_REFRESH_RATE and a new CREDITS_PER_DOLLAR constant instead of hardcoding, so they can't drift (values byte-identical). * refactor(billing): bind comparison columns to credit tiers by name Look up Pro/Max tiers by name instead of array position so the comparison table can't silently bind to the wrong tier if CREDIT_TIERS is reordered or a tier is inserted (addresses Greptile P2). Values unchanged.
1 parent c17c003 commit 8c8e4b7

16 files changed

Lines changed: 206 additions & 600 deletions

File tree

apps/sim/app/(landing)/changelog/page.tsx

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,17 @@
1-
import type { Metadata } from 'next'
2-
import { SITE_URL } from '@/lib/core/utils/urls'
1+
import { buildLandingMetadata } from '@/lib/landing/seo'
32
import Changelog from '@/app/(landing)/changelog/changelog'
43

54
export const revalidate = 3600
65

7-
const PAGE_URL = `${SITE_URL}/changelog`
86
const TITLE = 'Changelog | Sim, the AI Workspace'
97
const DESCRIPTION =
108
'Every new feature, improvement, and fix in Sim, the open-source AI workspace, with release notes straight from GitHub.'
119

12-
export const metadata: Metadata = {
13-
metadataBase: new URL(SITE_URL),
14-
title: { absolute: TITLE },
10+
export const metadata = buildLandingMetadata({
11+
title: TITLE,
1512
description: DESCRIPTION,
16-
authors: [{ name: 'Sim' }],
17-
creator: 'Sim',
18-
publisher: 'Sim',
19-
openGraph: {
20-
title: TITLE,
21-
description: DESCRIPTION,
22-
type: 'website',
23-
url: PAGE_URL,
24-
siteName: 'Sim',
25-
locale: 'en_US',
26-
images: [
27-
{
28-
url: '/logo/426-240/reverse/small.png',
29-
width: 2130,
30-
height: 1200,
31-
alt: 'Changelog | Sim, the AI Workspace',
32-
type: 'image/png',
33-
},
34-
],
35-
},
36-
twitter: {
37-
card: 'summary_large_image',
38-
site: '@simdotai',
39-
creator: '@simdotai',
40-
title: TITLE,
41-
description: DESCRIPTION,
42-
images: {
43-
url: '/logo/426-240/reverse/small.png',
44-
alt: 'Changelog | Sim, the AI Workspace',
45-
},
46-
},
47-
alternates: {
48-
canonical: PAGE_URL,
49-
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
50-
},
51-
robots: {
52-
index: true,
53-
follow: true,
54-
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
55-
},
56-
category: 'technology',
57-
}
13+
path: '/changelog',
14+
})
5815

5916
export default function Page() {
6017
return <Changelog />

apps/sim/app/(landing)/demo/page.tsx

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,17 @@
1-
import type { Metadata } from 'next'
2-
import { SITE_URL } from '@/lib/core/utils/urls'
1+
import { buildLandingMetadata } from '@/lib/landing/seo'
32
import Demo from '@/app/(landing)/demo/demo'
43

54
export const revalidate = 3600
65

7-
const PAGE_URL = `${SITE_URL}/demo`
86
const TITLE = 'Book a Demo | Sim, the AI Workspace'
97
const DESCRIPTION =
108
'Book a demo of Sim, the AI agent workspace where teams build, deploy, and manage AI agents and workflows that connect 1,000+ integrations and every major LLM.'
119

12-
export const metadata: Metadata = {
13-
metadataBase: new URL(SITE_URL),
14-
title: { absolute: TITLE },
10+
export const metadata = buildLandingMetadata({
11+
title: TITLE,
1512
description: DESCRIPTION,
16-
authors: [{ name: 'Sim' }],
17-
creator: 'Sim',
18-
publisher: 'Sim',
19-
openGraph: {
20-
title: TITLE,
21-
description: DESCRIPTION,
22-
type: 'website',
23-
url: PAGE_URL,
24-
siteName: 'Sim',
25-
locale: 'en_US',
26-
images: [
27-
{
28-
url: '/logo/426-240/reverse/small.png',
29-
width: 2130,
30-
height: 1200,
31-
alt: 'Book a Demo | Sim, the AI Workspace',
32-
type: 'image/png',
33-
},
34-
],
35-
},
36-
twitter: {
37-
card: 'summary_large_image',
38-
site: '@simdotai',
39-
creator: '@simdotai',
40-
title: TITLE,
41-
description: DESCRIPTION,
42-
images: {
43-
url: '/logo/426-240/reverse/small.png',
44-
alt: 'Book a Demo | Sim, the AI Workspace',
45-
},
46-
},
47-
alternates: {
48-
canonical: PAGE_URL,
49-
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
50-
},
51-
robots: {
52-
index: true,
53-
follow: true,
54-
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
55-
},
56-
category: 'technology',
57-
}
13+
path: '/demo',
14+
})
5815

5916
export default function Page() {
6017
return <Demo />

apps/sim/app/(landing)/enterprise/page.tsx

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,20 @@
1-
import type { Metadata } from 'next'
2-
import { SITE_URL } from '@/lib/core/utils/urls'
1+
import { buildLandingMetadata } from '@/lib/landing/seo'
32
import EnterprisePage from '@/app/(landing)/enterprise/enterprise'
43

54
export const revalidate = 3600
65

7-
const PAGE_URL = `${SITE_URL}/enterprise`
86
const TITLE = 'Enterprise AI Agent Platform | Sim AI'
97
const DESCRIPTION =
108
'Build, deploy, and govern enterprise AI agents in one workspace with security, approvals, observability, and collaboration.'
119

12-
export const metadata: Metadata = {
13-
metadataBase: new URL(SITE_URL),
14-
title: { absolute: TITLE },
10+
export const metadata = buildLandingMetadata({
11+
title: TITLE,
1512
description: DESCRIPTION,
13+
path: '/enterprise',
1614
keywords:
1715
'enterprise ai agents, enterprise ai agent, enterprise ai agent platform, enterprise workflow agents',
18-
authors: [{ name: 'Sim' }],
19-
creator: 'Sim',
20-
publisher: 'Sim',
21-
openGraph: {
22-
title: TITLE,
23-
description: DESCRIPTION,
24-
type: 'website',
25-
url: PAGE_URL,
26-
siteName: 'Sim',
27-
locale: 'en_US',
28-
images: [
29-
{
30-
url: '/logo/426-240/reverse/small.png',
31-
width: 2130,
32-
height: 1200,
33-
alt: TITLE,
34-
type: 'image/png',
35-
},
36-
],
37-
},
38-
twitter: {
39-
card: 'summary_large_image',
40-
site: '@simdotai',
41-
creator: '@simdotai',
42-
title: TITLE,
43-
description: DESCRIPTION,
44-
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
45-
},
46-
alternates: {
47-
canonical: PAGE_URL,
48-
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
49-
},
50-
robots: {
51-
index: true,
52-
follow: true,
53-
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
54-
},
55-
category: 'technology',
56-
}
16+
twitterImageAlt: 'Sim',
17+
})
5718

5819
export default function Page() {
5920
return <EnterprisePage />

apps/sim/app/(landing)/partners/page.tsx

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,20 @@
11
import { ChipLink } from '@sim/emcn'
2-
import type { Metadata } from 'next'
32
import { SITE_URL } from '@/lib/core/utils/urls'
3+
import { buildLandingMetadata } from '@/lib/landing/seo'
44

55
const PAGE_URL = `${SITE_URL}/partners`
66
const TITLE = 'Partner Program | Sim'
77
const DESCRIPTION =
88
"Join the Sim partner program. Build, deploy, and sell AI agent solutions powered by Sim's AI workspace, and earn your certification through Sim Academy."
99

10-
export const metadata: Metadata = {
11-
metadataBase: new URL(SITE_URL),
12-
title: { absolute: TITLE },
10+
export const metadata = buildLandingMetadata({
11+
title: TITLE,
1312
description: DESCRIPTION,
13+
path: '/partners',
1414
keywords:
1515
'Sim partner program, AI agent partners, AI workspace partners, Sim Academy certification, AI agent reseller, co-marketing',
16-
openGraph: {
17-
title: TITLE,
18-
description: DESCRIPTION,
19-
type: 'website',
20-
url: PAGE_URL,
21-
siteName: 'Sim',
22-
locale: 'en_US',
23-
images: [
24-
{
25-
url: '/logo/426-240/reverse/small.png',
26-
width: 2130,
27-
height: 1200,
28-
alt: TITLE,
29-
type: 'image/png',
30-
},
31-
],
32-
},
33-
twitter: {
34-
card: 'summary_large_image',
35-
site: '@simdotai',
36-
creator: '@simdotai',
37-
title: TITLE,
38-
description: DESCRIPTION,
39-
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
40-
},
41-
alternates: {
42-
canonical: PAGE_URL,
43-
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
44-
},
45-
robots: {
46-
index: true,
47-
follow: true,
48-
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
49-
},
50-
category: 'technology',
51-
}
16+
twitterImageAlt: 'Sim',
17+
})
5218

5319
const partnersJsonLd = {
5420
'@context': 'https://schema.org',

apps/sim/app/(landing)/pricing/page.tsx

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,21 @@
1-
import type { Metadata } from 'next'
21
import type { SearchParams } from 'nuqs/server'
3-
import { SITE_URL } from '@/lib/core/utils/urls'
2+
import { buildLandingMetadata } from '@/lib/landing/seo'
43
import Pricing from '@/app/(landing)/pricing/pricing'
54
import { pricingSearchParamsCache } from '@/app/(landing)/pricing/search-params'
65

76
export const revalidate = 3600
87

9-
const PAGE_URL = `${SITE_URL}/pricing`
108
const TITLE = 'Pricing | Sim, the AI Workspace'
119
const DESCRIPTION =
1210
'Pricing for Sim, the open-source AI workspace for building, deploying, and managing AI agents. Compare the Free, Pro, Max, and Enterprise plans. Start free.'
1311

14-
export const metadata: Metadata = {
15-
metadataBase: new URL(SITE_URL),
16-
title: { absolute: TITLE },
12+
export const metadata = buildLandingMetadata({
13+
title: TITLE,
1714
description: DESCRIPTION,
15+
path: '/pricing',
1816
keywords:
1917
'Sim pricing, AI workspace pricing, AI agent platform pricing, build AI agents, Pro plan, Max plan, Enterprise plan, open-source AI agents, LLM pricing',
20-
authors: [{ name: 'Sim' }],
21-
creator: 'Sim',
22-
publisher: 'Sim',
23-
openGraph: {
24-
title: TITLE,
25-
description: DESCRIPTION,
26-
type: 'website',
27-
url: PAGE_URL,
28-
siteName: 'Sim',
29-
locale: 'en_US',
30-
images: [
31-
{
32-
url: '/logo/426-240/reverse/small.png',
33-
width: 2130,
34-
height: 1200,
35-
alt: 'Pricing | Sim, the AI Workspace',
36-
type: 'image/png',
37-
},
38-
],
39-
},
40-
twitter: {
41-
card: 'summary_large_image',
42-
site: '@simdotai',
43-
creator: '@simdotai',
44-
title: TITLE,
45-
description: DESCRIPTION,
46-
images: {
47-
url: '/logo/426-240/reverse/small.png',
48-
alt: 'Pricing | Sim, the AI Workspace',
49-
},
50-
},
51-
alternates: {
52-
canonical: PAGE_URL,
53-
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
54-
},
55-
robots: {
56-
index: true,
57-
follow: true,
58-
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
59-
},
60-
category: 'technology',
61-
}
18+
})
6219

6320
export default async function Page({ searchParams }: { searchParams: Promise<SearchParams> }) {
6421
await pricingSearchParamsCache.parse(searchParams)

apps/sim/app/(landing)/privacy/page.tsx

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,17 @@
1-
import type { Metadata } from 'next'
2-
import { SITE_URL } from '@/lib/core/utils/urls'
1+
import { buildLandingMetadata } from '@/lib/landing/seo'
32
import Privacy from '@/app/(landing)/privacy/privacy'
43

54
export const revalidate = 3600
65

7-
const PAGE_URL = `${SITE_URL}/privacy`
86
const TITLE = 'Privacy Policy | Sim, the AI Workspace'
97
const DESCRIPTION =
108
'How Sim, the open-source AI workspace, collects, uses, and protects your data, including data obtained from Google APIs, and the controls you have over it.'
119

12-
export const metadata: Metadata = {
13-
metadataBase: new URL(SITE_URL),
14-
title: { absolute: TITLE },
10+
export const metadata = buildLandingMetadata({
11+
title: TITLE,
1512
description: DESCRIPTION,
16-
authors: [{ name: 'Sim' }],
17-
creator: 'Sim',
18-
publisher: 'Sim',
19-
openGraph: {
20-
title: TITLE,
21-
description: DESCRIPTION,
22-
type: 'website',
23-
url: PAGE_URL,
24-
siteName: 'Sim',
25-
locale: 'en_US',
26-
images: [
27-
{
28-
url: '/logo/426-240/reverse/small.png',
29-
width: 2130,
30-
height: 1200,
31-
alt: 'Privacy Policy | Sim, the AI Workspace',
32-
type: 'image/png',
33-
},
34-
],
35-
},
36-
twitter: {
37-
card: 'summary_large_image',
38-
site: '@simdotai',
39-
creator: '@simdotai',
40-
title: TITLE,
41-
description: DESCRIPTION,
42-
images: {
43-
url: '/logo/426-240/reverse/small.png',
44-
alt: 'Privacy Policy | Sim, the AI Workspace',
45-
},
46-
},
47-
alternates: {
48-
canonical: PAGE_URL,
49-
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
50-
},
51-
robots: {
52-
index: true,
53-
follow: true,
54-
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
55-
},
56-
category: 'technology',
57-
}
13+
path: '/privacy',
14+
})
5815

5916
export default function Page() {
6017
return <Privacy />

0 commit comments

Comments
 (0)