mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
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.
This commit is contained in:
@@ -1,60 +1,17 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import Changelog from '@/app/(landing)/changelog/changelog'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/changelog`
|
||||
const TITLE = 'Changelog | Sim, the AI Workspace'
|
||||
const DESCRIPTION =
|
||||
'Every new feature, improvement, and fix in Sim, the open-source AI workspace, with release notes straight from GitHub.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'Changelog | Sim, the AI Workspace',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: {
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
alt: 'Changelog | Sim, the AI Workspace',
|
||||
},
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
path: '/changelog',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <Changelog />
|
||||
|
||||
@@ -1,60 +1,17 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import Demo from '@/app/(landing)/demo/demo'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/demo`
|
||||
const TITLE = 'Book a Demo | Sim, the AI Workspace'
|
||||
const DESCRIPTION =
|
||||
'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.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'Book a Demo | Sim, the AI Workspace',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: {
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
alt: 'Book a Demo | Sim, the AI Workspace',
|
||||
},
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
path: '/demo',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <Demo />
|
||||
|
||||
@@ -1,59 +1,20 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import EnterprisePage from '@/app/(landing)/enterprise/enterprise'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/enterprise`
|
||||
const TITLE = 'Enterprise AI Agent Platform | Sim AI'
|
||||
const DESCRIPTION =
|
||||
'Build, deploy, and govern enterprise AI agents in one workspace with security, approvals, observability, and collaboration.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/enterprise',
|
||||
keywords:
|
||||
'enterprise ai agents, enterprise ai agent, enterprise ai agent platform, enterprise workflow agents',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: TITLE,
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
twitterImageAlt: 'Sim',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <EnterprisePage />
|
||||
|
||||
@@ -1,54 +1,20 @@
|
||||
import { ChipLink } from '@sim/emcn'
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/partners`
|
||||
const TITLE = 'Partner Program | Sim'
|
||||
const DESCRIPTION =
|
||||
"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."
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/partners',
|
||||
keywords:
|
||||
'Sim partner program, AI agent partners, AI workspace partners, Sim Academy certification, AI agent reseller, co-marketing',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: TITLE,
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
twitterImageAlt: 'Sim',
|
||||
})
|
||||
|
||||
const partnersJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
|
||||
@@ -1,64 +1,21 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SearchParams } from 'nuqs/server'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import Pricing from '@/app/(landing)/pricing/pricing'
|
||||
import { pricingSearchParamsCache } from '@/app/(landing)/pricing/search-params'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/pricing`
|
||||
const TITLE = 'Pricing | Sim, the AI Workspace'
|
||||
const DESCRIPTION =
|
||||
'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.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/pricing',
|
||||
keywords:
|
||||
'Sim pricing, AI workspace pricing, AI agent platform pricing, build AI agents, Pro plan, Max plan, Enterprise plan, open-source AI agents, LLM pricing',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'Pricing | Sim, the AI Workspace',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: {
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
alt: 'Pricing | Sim, the AI Workspace',
|
||||
},
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
})
|
||||
|
||||
export default async function Page({ searchParams }: { searchParams: Promise<SearchParams> }) {
|
||||
await pricingSearchParamsCache.parse(searchParams)
|
||||
|
||||
@@ -1,60 +1,17 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import Privacy from '@/app/(landing)/privacy/privacy'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/privacy`
|
||||
const TITLE = 'Privacy Policy | Sim, the AI Workspace'
|
||||
const DESCRIPTION =
|
||||
'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.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'Privacy Policy | Sim, the AI Workspace',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: {
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
alt: 'Privacy Policy | Sim, the AI Workspace',
|
||||
},
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
path: '/privacy',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <Privacy />
|
||||
|
||||
@@ -1,59 +1,20 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import ComplianceSolution from '@/app/(landing)/solutions/compliance/compliance'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/solutions/compliance`
|
||||
const TITLE = 'AI Agents for Continuous Compliance & Audit | Sim'
|
||||
const DESCRIPTION =
|
||||
'Compliance teams use Sim, the open-source AI workspace, to build and deploy AI agents that automate evidence collection, control monitoring, and reporting.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/solutions/compliance',
|
||||
keywords:
|
||||
'AI workspace, AI agents for compliance, compliance automation, evidence collection, control monitoring, audit readiness, open-source AI agent platform',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'AI Agents for Continuous Compliance & Audit | Sim',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
twitterImageAlt: 'Sim',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <ComplianceSolution />
|
||||
|
||||
@@ -1,59 +1,20 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import EngineeringSolution from '@/app/(landing)/solutions/engineering/engineering'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/solutions/engineering`
|
||||
const TITLE = 'AI Agents for Code Review & On-Call | Sim'
|
||||
const DESCRIPTION =
|
||||
'Engineering teams use Sim, the open-source AI workspace, to build and deploy AI agents that automate code review, on-call triage, and documentation.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/solutions/engineering',
|
||||
keywords:
|
||||
'AI workspace, AI agents for engineering, automated code review, on-call automation, CI/CD agents, developer automation, open-source AI agent platform',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'AI Agents for Code Review & On-Call | Sim',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
twitterImageAlt: 'Sim',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <EngineeringSolution />
|
||||
|
||||
@@ -1,59 +1,20 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import FinanceSolution from '@/app/(landing)/solutions/finance/finance'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/solutions/finance`
|
||||
const TITLE = 'AI Agents for Invoice Processing & Reconciliation | Sim'
|
||||
const DESCRIPTION =
|
||||
'Finance teams use Sim, the open-source AI workspace, to build and deploy AI agents that automate reconciliation, invoice processing, and reporting.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/solutions/finance',
|
||||
keywords:
|
||||
'AI workspace, AI agents for finance, finance automation, invoice processing, account reconciliation, financial reporting, open-source AI agent platform',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'AI Agents for Invoice Processing & Reconciliation | Sim',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
twitterImageAlt: 'Sim',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <FinanceSolution />
|
||||
|
||||
@@ -1,59 +1,20 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import HrSolution from '@/app/(landing)/solutions/hr/hr'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/solutions/hr`
|
||||
const TITLE = 'AI Agents for Onboarding & People Operations | Sim'
|
||||
const DESCRIPTION =
|
||||
'HR teams use Sim, the open-source AI workspace, to build and deploy AI agents that automate onboarding, employee questions, and approvals.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/solutions/hr',
|
||||
keywords:
|
||||
'AI workspace, AI agents for HR, HR automation, employee onboarding, people operations, HRIS automation, open-source AI agent platform',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'AI Agents for Onboarding & People Operations | Sim',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
twitterImageAlt: 'Sim',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <HrSolution />
|
||||
|
||||
@@ -1,59 +1,20 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import ItSolution from '@/app/(landing)/solutions/it/it'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/solutions/it`
|
||||
const TITLE = 'AI Agents for Ticket Triage & Access | Sim'
|
||||
const DESCRIPTION =
|
||||
'IT teams use Sim, the open-source AI workspace, to build and deploy AI agents that automate ticket triage, access provisioning, and monitoring.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/solutions/it',
|
||||
keywords:
|
||||
'AI workspace, IT automation, AI agents for IT, IT service desk automation, access provisioning, infrastructure monitoring, open-source AI agent platform',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'AI Agents for Ticket Triage & Access | Sim',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: { url: '/logo/426-240/reverse/small.png', alt: 'Sim' },
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
twitterImageAlt: 'Sim',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <ItSolution />
|
||||
|
||||
@@ -1,60 +1,17 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import Terms from '@/app/(landing)/terms/terms'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/terms`
|
||||
const TITLE = 'Terms of Service | Sim, the AI Workspace'
|
||||
const DESCRIPTION =
|
||||
'The terms and conditions for using Sim, the open-source AI workspace: subscription plans, data ownership, acceptable use, and your rights.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'Terms of Service | Sim, the AI Workspace',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: {
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
alt: 'Terms of Service | Sim, the AI Workspace',
|
||||
},
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
path: '/terms',
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <Terms />
|
||||
|
||||
@@ -1,62 +1,19 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import Workflows from '@/app/(landing)/workflows/workflows'
|
||||
|
||||
export const revalidate = 3600
|
||||
|
||||
const PAGE_URL = `${SITE_URL}/workflows`
|
||||
const TITLE = 'Workflows | The Visual Builder in Sim, the AI Workspace'
|
||||
const DESCRIPTION =
|
||||
'Workflows is the visual builder in Sim, the open-source AI workspace. Connect blocks, every major LLM, and 1,000+ integrations into agent logic.'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: TITLE },
|
||||
export const metadata = buildLandingMetadata({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: '/workflows',
|
||||
keywords:
|
||||
'AI workspace, visual workflow builder, build AI agents, AI agent workflow builder, LLM orchestration, AI integrations, open-source AI agent platform, agentic workflows',
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
type: 'website',
|
||||
url: PAGE_URL,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
width: 2130,
|
||||
height: 1200,
|
||||
alt: 'Workflows | The Visual Builder in Sim, the AI Workspace',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: {
|
||||
url: '/logo/426-240/reverse/small.png',
|
||||
alt: 'Workflows | The Visual Builder in Sim, the AI Workspace',
|
||||
},
|
||||
},
|
||||
alternates: {
|
||||
canonical: PAGE_URL,
|
||||
languages: { 'en-US': PAGE_URL, 'x-default': PAGE_URL },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
})
|
||||
|
||||
export default function Page() {
|
||||
return <Workflows />
|
||||
|
||||
+39
-2
@@ -1,3 +1,30 @@
|
||||
import {
|
||||
CREDIT_TIERS,
|
||||
CREDITS_PER_DOLLAR,
|
||||
DAILY_REFRESH_RATE,
|
||||
DEFAULT_FREE_CREDITS,
|
||||
} from '@/lib/billing/constants'
|
||||
|
||||
/**
|
||||
* Looks up a credit tier by name, so a column binds to the right tier even if
|
||||
* {@link CREDIT_TIERS} is reordered or a tier is inserted.
|
||||
*/
|
||||
function tierByName(name: (typeof CREDIT_TIERS)[number]['name']) {
|
||||
const tier = CREDIT_TIERS.find((t) => t.name === name)
|
||||
if (!tier) throw new Error(`comparison-data: no credit tier named "${name}"`)
|
||||
return tier
|
||||
}
|
||||
|
||||
const PRO_TIER = tierByName('Pro')
|
||||
const MAX_TIER = tierByName('Max')
|
||||
|
||||
/** Formats a credit count with thousands separators (e.g. 25000 → "25,000"). */
|
||||
const formatCredits = (credits: number): string => credits.toLocaleString('en-US')
|
||||
|
||||
/** Daily refresh credits for a plan: 1% of plan dollars/day, in credits. */
|
||||
const dailyRefreshCredits = (dollars: number): number =>
|
||||
Math.round(dollars * DAILY_REFRESH_RATE * CREDITS_PER_DOLLAR)
|
||||
|
||||
/** A brand icon rendered in a cell instead of a check/em-dash/text. */
|
||||
export interface CellIcon {
|
||||
/** Icon identifier resolved to a component by the table renderer. */
|
||||
@@ -58,11 +85,21 @@ export const COMPARISON_SECTIONS: ComparisonSection[] = [
|
||||
rows: [
|
||||
{
|
||||
label: 'Monthly credits',
|
||||
values: ['1,000', '6,000', '25,000', 'Custom'],
|
||||
values: [
|
||||
formatCredits(DEFAULT_FREE_CREDITS * CREDITS_PER_DOLLAR),
|
||||
formatCredits(PRO_TIER.credits),
|
||||
formatCredits(MAX_TIER.credits),
|
||||
'Custom',
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Daily refresh',
|
||||
values: [false, '+50', '+200', 'Custom'],
|
||||
values: [
|
||||
false,
|
||||
`+${formatCredits(dailyRefreshCredits(PRO_TIER.dollars))}`,
|
||||
`+${formatCredits(dailyRefreshCredits(MAX_TIER.dollars))}`,
|
||||
'Custom',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -50,6 +50,12 @@ export const CREDIT_TIERS = [
|
||||
|
||||
export type CreditTier = (typeof CREDIT_TIERS)[number]
|
||||
|
||||
/**
|
||||
* Credits granted per dollar of plan spend. A credit is $0.005, so a dollar
|
||||
* buys 200 — the conversion behind both free-tier and daily-refresh credits.
|
||||
*/
|
||||
export const CREDITS_PER_DOLLAR = 200
|
||||
|
||||
/**
|
||||
* Daily refresh rate: 1% of plan cost per day.
|
||||
* E.g. $25 plan => $0.25/day => 50 credits/day included usage.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
|
||||
/** Shared OpenGraph/Twitter card image for landing pages. */
|
||||
const OG_IMAGE_URL = '/logo/426-240/reverse/small.png'
|
||||
const OG_IMAGE_WIDTH = 2130
|
||||
const OG_IMAGE_HEIGHT = 1200
|
||||
|
||||
interface LandingMetadataInput {
|
||||
/** Absolute `<title>`, rendered as-is (no site template applied). */
|
||||
title: string
|
||||
description: string
|
||||
/** Path under the site root, e.g. `/pricing`. Use `''` for the home page. */
|
||||
path: string
|
||||
/** Optional comma-separated keywords; omitted from the output when absent. */
|
||||
keywords?: string
|
||||
/** OpenGraph image alt text. Defaults to {@link title}. */
|
||||
imageAlt?: string
|
||||
/** Twitter card image alt text. Defaults to {@link imageAlt}. */
|
||||
twitterImageAlt?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the canonical metadata for a static landing page — the single source of
|
||||
* truth for the OpenGraph/Twitter/robots/canonical chrome shared across the
|
||||
* landing family, so per-page files declare only what actually varies (title,
|
||||
* description, keywords, path, and any non-default image alt).
|
||||
*
|
||||
* Note: dynamic and image-bearing routes that resolve their card from a sibling
|
||||
* `opengraph-image` (integrations, models) and the blog family (`buildPostMetadata`
|
||||
* in `lib/blog/seo`) intentionally do not use this helper.
|
||||
*/
|
||||
export function buildLandingMetadata({
|
||||
title,
|
||||
description,
|
||||
path,
|
||||
keywords,
|
||||
imageAlt,
|
||||
twitterImageAlt,
|
||||
}: LandingMetadataInput): Metadata {
|
||||
const url = `${SITE_URL}${path}`
|
||||
const ogAlt = imageAlt ?? title
|
||||
const twitterAlt = twitterImageAlt ?? ogAlt
|
||||
|
||||
return {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: { absolute: title },
|
||||
description,
|
||||
...(keywords ? { keywords } : {}),
|
||||
authors: [{ name: 'Sim' }],
|
||||
creator: 'Sim',
|
||||
publisher: 'Sim',
|
||||
openGraph: {
|
||||
title,
|
||||
description,
|
||||
type: 'website',
|
||||
url,
|
||||
siteName: 'Sim',
|
||||
locale: 'en_US',
|
||||
images: [
|
||||
{
|
||||
url: OG_IMAGE_URL,
|
||||
width: OG_IMAGE_WIDTH,
|
||||
height: OG_IMAGE_HEIGHT,
|
||||
alt: ogAlt,
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@simdotai',
|
||||
creator: '@simdotai',
|
||||
title,
|
||||
description,
|
||||
images: { url: OG_IMAGE_URL, alt: twitterAlt },
|
||||
},
|
||||
alternates: {
|
||||
canonical: url,
|
||||
languages: { 'en-US': url, 'x-default': url },
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
|
||||
},
|
||||
category: 'technology',
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user