mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(landing): rename /comparison route to /comparisons for naming consistency (#5651)
Aligns with the /integrations/[slug] convention (plural category, singular item). Adds a 301 redirect (both the bare hub page and every competitor detail page) so previously indexed URLs keep working, and updates every internal reference: footer nav, sitemap generation, and all import specifiers/canonical URLs/breadcrumb JSON-LD within the route itself.
This commit is contained in:
+10
-10
@@ -4,10 +4,10 @@ import type { CompetitorProfile } from '@/lib/compare/data'
|
||||
import { simProfile } from '@/lib/compare/data'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import { COMPARISON_SECTIONS, getFactGroup } from '@/app/(landing)/comparison/comparison-sections'
|
||||
import { BrandIconTile, SimIconTile } from '@/app/(landing)/comparison/components/brand-icon-tile'
|
||||
import { ComparisonCards } from '@/app/(landing)/comparison/components/comparison-cards'
|
||||
import { ComparisonTable } from '@/app/(landing)/comparison/components/comparison-table'
|
||||
import { COMPARISON_SECTIONS, getFactGroup } from '@/app/(landing)/comparisons/comparison-sections'
|
||||
import { BrandIconTile, SimIconTile } from '@/app/(landing)/comparisons/components/brand-icon-tile'
|
||||
import { ComparisonCards } from '@/app/(landing)/comparisons/components/comparison-cards'
|
||||
import { ComparisonTable } from '@/app/(landing)/comparisons/components/comparison-table'
|
||||
import {
|
||||
ALL_COMPETITORS,
|
||||
buildBottomLine,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
getCompetitorBySlug,
|
||||
getLatestVerifiedDate,
|
||||
SIM_LATEST_VERIFIED,
|
||||
} from '@/app/(landing)/comparison/utils'
|
||||
} from '@/app/(landing)/comparisons/utils'
|
||||
import { BackLink } from '@/app/(landing)/components'
|
||||
import { Cta } from '@/app/(landing)/components/cta/cta'
|
||||
import { JsonLd } from '@/app/(landing)/components/json-ld'
|
||||
@@ -57,7 +57,7 @@ export async function generateMetadata({
|
||||
return buildLandingMetadata({
|
||||
title: `Sim vs ${competitor.name} | Sim, the AI Workspace`,
|
||||
description: `Compare Sim, the open-source AI workspace, to ${competitor.name} on platform, AI, integrations, pricing, security, and support. Sourced and dated facts.`,
|
||||
path: `/comparison/${competitor.id}`,
|
||||
path: `/comparisons/${competitor.id}`,
|
||||
keywords: [
|
||||
`Sim vs ${competitor.name}`,
|
||||
`${competitor.name} alternative`,
|
||||
@@ -91,12 +91,12 @@ export default async function ComparisonProviderPage({
|
||||
'@type': 'BreadcrumbList',
|
||||
itemListElement: [
|
||||
{ '@type': 'ListItem', position: 1, name: 'Home', item: baseUrl },
|
||||
{ '@type': 'ListItem', position: 2, name: 'Comparison', item: `${baseUrl}/comparison` },
|
||||
{ '@type': 'ListItem', position: 2, name: 'Comparisons', item: `${baseUrl}/comparisons` },
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 3,
|
||||
name: `Sim vs ${competitor.name}`,
|
||||
item: `${baseUrl}/comparison/${competitor.id}`,
|
||||
item: `${baseUrl}/comparisons/${competitor.id}`,
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -110,7 +110,7 @@ export default async function ComparisonProviderPage({
|
||||
'@type': 'ItemList',
|
||||
name: `Sim vs ${competitor.name}`,
|
||||
description: `Feature and pricing comparison between Sim and ${competitor.name}.`,
|
||||
url: `${baseUrl}/comparison/${competitor.id}`,
|
||||
url: `${baseUrl}/comparisons/${competitor.id}`,
|
||||
dateModified: latestVerified.toISOString().slice(0, 10),
|
||||
numberOfItems: 2,
|
||||
itemListElement: [
|
||||
@@ -163,7 +163,7 @@ export default async function ComparisonProviderPage({
|
||||
<main id='main-content' className='bg-[var(--bg)]'>
|
||||
<div className='mx-auto w-full max-w-[1446px] px-12 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
|
||||
<div className='mb-6'>
|
||||
<BackLink href='/comparison' label='Back to comparisons' />
|
||||
<BackLink href='/comparisons' label='Back to comparisons' />
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-4'>
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import type { FactSource } from '@/lib/compare/data'
|
||||
import { SourceLink } from '@/app/(landing)/comparison/components/source-info'
|
||||
import { SourceLink } from '@/app/(landing)/comparisons/components/source-info'
|
||||
|
||||
interface ComparisonCardItem {
|
||||
title: string
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { cn } from '@sim/emcn'
|
||||
import type { CompetitorProfile } from '@/lib/compare/data'
|
||||
import { COMPARISON_SECTIONS, getFactGroup } from '@/app/(landing)/comparison/comparison-sections'
|
||||
import { BrandIconTile, SimIconTile } from '@/app/(landing)/comparison/components/brand-icon-tile'
|
||||
import { FactValue } from '@/app/(landing)/comparison/components/fact-value'
|
||||
import { COMPARISON_SECTIONS, getFactGroup } from '@/app/(landing)/comparisons/comparison-sections'
|
||||
import { BrandIconTile, SimIconTile } from '@/app/(landing)/comparisons/components/brand-icon-tile'
|
||||
import { FactValue } from '@/app/(landing)/comparisons/components/fact-value'
|
||||
|
||||
export interface ComparisonTableProps {
|
||||
sim: CompetitorProfile
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { Check, X } from '@sim/emcn/icons'
|
||||
import type { Fact } from '@/lib/compare/data'
|
||||
import { SourceLink } from '@/app/(landing)/comparison/components/source-info'
|
||||
import { parseFactValue } from '@/app/(landing)/comparison/fact-status'
|
||||
import { SourceLink } from '@/app/(landing)/comparisons/components/source-info'
|
||||
import { parseFactValue } from '@/app/(landing)/comparisons/fact-status'
|
||||
|
||||
export interface FactValueProps {
|
||||
fact: Fact
|
||||
+1
-1
@@ -18,7 +18,7 @@ export default function ComparisonNotFound() {
|
||||
<p className='text-[var(--text-muted)] text-lg'>
|
||||
The comparison you're looking for doesn't exist or has been moved.
|
||||
</p>
|
||||
<ChipLink variant='primary' href='/comparison' className='mt-3'>
|
||||
<ChipLink variant='primary' href='/comparisons' className='mt-3'>
|
||||
Browse comparisons
|
||||
</ChipLink>
|
||||
</main>
|
||||
+7
-7
@@ -3,8 +3,8 @@ import Link from 'next/link'
|
||||
import { simProfile } from '@/lib/compare/data'
|
||||
import { SITE_URL } from '@/lib/core/utils/urls'
|
||||
import { buildLandingMetadata } from '@/lib/landing/seo'
|
||||
import { BrandIconTile } from '@/app/(landing)/comparison/components/brand-icon-tile'
|
||||
import { ALL_COMPETITORS, ensurePeriod, lowercaseFirst } from '@/app/(landing)/comparison/utils'
|
||||
import { BrandIconTile } from '@/app/(landing)/comparisons/components/brand-icon-tile'
|
||||
import { ALL_COMPETITORS, ensurePeriod, lowercaseFirst } from '@/app/(landing)/comparisons/utils'
|
||||
import { ChevronArrow } from '@/app/(landing)/components/chevron-arrow'
|
||||
import { JsonLd } from '@/app/(landing)/components/json-ld'
|
||||
import { LandingFAQ } from '@/app/(landing)/components/landing-faq'
|
||||
@@ -47,7 +47,7 @@ export const metadata: Metadata = buildLandingMetadata({
|
||||
title: 'Sim Comparisons | Sim, the AI Workspace',
|
||||
description:
|
||||
'Compare Sim, the open-source AI workspace, to n8n, Zapier, Make, and other workflow automation and AI agent platforms. Sourced, dated, fact-checked.',
|
||||
path: '/comparison',
|
||||
path: '/comparisons',
|
||||
keywords: [
|
||||
'Sim comparison',
|
||||
'Sim vs n8n',
|
||||
@@ -65,7 +65,7 @@ export default function ComparisonHubPage() {
|
||||
'@type': 'BreadcrumbList',
|
||||
itemListElement: [
|
||||
{ '@type': 'ListItem', position: 1, name: 'Home', item: baseUrl },
|
||||
{ '@type': 'ListItem', position: 2, name: 'Comparison', item: `${baseUrl}/comparison` },
|
||||
{ '@type': 'ListItem', position: 2, name: 'Comparisons', item: `${baseUrl}/comparisons` },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -74,12 +74,12 @@ export default function ComparisonHubPage() {
|
||||
'@type': 'ItemList',
|
||||
name: 'Sim Comparisons',
|
||||
description: 'Directory of Sim comparison pages against AI agent and workflow platforms.',
|
||||
url: `${baseUrl}/comparison`,
|
||||
url: `${baseUrl}/comparisons`,
|
||||
numberOfItems: ALL_COMPETITORS.length,
|
||||
itemListElement: ALL_COMPETITORS.map((competitor, index) => ({
|
||||
'@type': 'ListItem',
|
||||
position: index + 1,
|
||||
url: `${baseUrl}/comparison/${competitor.id}`,
|
||||
url: `${baseUrl}/comparisons/${competitor.id}`,
|
||||
name: `Sim vs ${competitor.name}`,
|
||||
})),
|
||||
}
|
||||
@@ -144,7 +144,7 @@ export default function ComparisonHubPage() {
|
||||
return (
|
||||
<div key={competitor.id}>
|
||||
<Link
|
||||
href={`/comparison/${competitor.id}`}
|
||||
href={`/comparisons/${competitor.id}`}
|
||||
className='group/link flex items-center gap-4 px-6 py-4 transition-colors hover-hover:bg-[var(--surface-hover)]'
|
||||
aria-label={`Sim vs ${competitor.name} comparison`}
|
||||
>
|
||||
@@ -41,7 +41,7 @@ const PRODUCT_LINKS: FooterItem[] = [
|
||||
const RESOURCES_LINKS: FooterItem[] = [
|
||||
{ label: 'Blog', href: '/blog' },
|
||||
{ label: 'Docs', href: 'https://docs.sim.ai', external: true },
|
||||
{ label: 'Compare', href: '/comparison' },
|
||||
{ label: 'Compare', href: '/comparisons' },
|
||||
{ label: 'Careers', href: '/careers' },
|
||||
{ label: 'Changelog', href: '/changelog' },
|
||||
{ label: 'Contact', href: '/contact' },
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ALL_COMPETITORS,
|
||||
getLatestVerifiedDate,
|
||||
SIM_LATEST_VERIFIED,
|
||||
} from '@/app/(landing)/comparison/utils'
|
||||
} from '@/app/(landing)/comparisons/utils'
|
||||
import { ALL_CATALOG_MODELS, MODEL_PROVIDERS_WITH_CATALOGS } from '@/app/(landing)/models/utils'
|
||||
|
||||
/** One sitemap entry per author, timestamped by their most recently updated post. */
|
||||
@@ -172,9 +172,9 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
: SIM_LATEST_VERIFIED
|
||||
|
||||
const comparisonPages: MetadataRoute.Sitemap = [
|
||||
{ url: `${baseUrl}/comparison`, lastModified: comparisonLastModified },
|
||||
{ url: `${baseUrl}/comparisons`, lastModified: comparisonLastModified },
|
||||
...ALL_COMPETITORS.map((competitor) => ({
|
||||
url: `${baseUrl}/comparison/${competitor.id}`,
|
||||
url: `${baseUrl}/comparisons/${competitor.id}`,
|
||||
lastModified: competitorLastModified(competitor),
|
||||
})),
|
||||
]
|
||||
|
||||
@@ -455,6 +455,25 @@ const nextConfig: NextConfig = {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* The comparison route was renamed from `/comparison` to `/comparisons`
|
||||
* for naming consistency with `/integrations/[slug]` (plural category,
|
||||
* singular item). Preserve previously indexed URLs for the hub page and
|
||||
* every competitor detail page.
|
||||
*/
|
||||
redirects.push(
|
||||
{
|
||||
source: '/comparison',
|
||||
destination: '/comparisons',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/comparison/:path*',
|
||||
destination: '/comparisons/:path*',
|
||||
permanent: true,
|
||||
}
|
||||
)
|
||||
|
||||
return redirects
|
||||
},
|
||||
async rewrites() {
|
||||
|
||||
Reference in New Issue
Block a user