Browse Source

feat(web): fill missing SEO-related values (#7096)

Co-authored-by: Matt Rubens <[email protected]>
Dicha Zelianivan Arkana 6 months ago
parent
commit
62d023d016

+ 48 - 0
apps/web-roo-code/src/app/enterprise/page.tsx

@@ -5,6 +5,54 @@ import { AnimatedText } from "@/components/animated-text"
 import { AnimatedBackground } from "@/components/homepage"
 import { ContactForm } from "@/components/enterprise/contact-form"
 import { EXTERNAL_LINKS } from "@/lib/constants"
+import type { Metadata } from "next"
+import { SEO } from "@/lib/seo"
+
+const TITLE = "Enterprise Solution"
+const DESCRIPTION =
+	"The control-plane for AI-powered software development. Gain visibility, governance, and control over your AI coding initiatives."
+const PATH = "/enterprise"
+const OG_IMAGE = SEO.ogImage
+
+export const metadata: Metadata = {
+	title: TITLE,
+	description: DESCRIPTION,
+	alternates: {
+		canonical: `${SEO.url}${PATH}`,
+	},
+	openGraph: {
+		title: TITLE,
+		description: DESCRIPTION,
+		url: `${SEO.url}${PATH}`,
+		siteName: SEO.name,
+		images: [
+			{
+				url: OG_IMAGE.url,
+				width: OG_IMAGE.width,
+				height: OG_IMAGE.height,
+				alt: OG_IMAGE.alt,
+			},
+		],
+		locale: SEO.locale,
+		type: "website",
+	},
+	twitter: {
+		card: SEO.twitterCard,
+		title: TITLE,
+		description: DESCRIPTION,
+		images: [OG_IMAGE.url],
+	},
+	keywords: [
+		...SEO.keywords,
+		"Enterprise AI",
+		"AI governance",
+		"AI control-plane",
+		"developer productivity",
+		"SAML",
+		"SCIM",
+		"cost management",
+	],
+}
 
 export default async function Enterprise() {
 	return (

+ 30 - 10
apps/web-roo-code/src/app/evals/page.tsx

@@ -1,25 +1,45 @@
 import type { Metadata } from "next"
 
 import { getEvalRuns } from "@/actions/evals"
+import { SEO } from "@/lib/seo"
 
 import { Evals } from "./evals"
 
 export const revalidate = 300
 export const dynamic = "force-dynamic"
 
+const TITLE = "Evals"
+const DESCRIPTION = "Explore quantitative evals of LLM coding skills across tasks and providers."
+const PATH = "/evals"
+const IMAGE = {
+	url: "https://i.imgur.com/ijP7aZm.png",
+	width: 1954,
+	height: 1088,
+	alt: "Roo Code Evals – LLM coding benchmarks",
+}
+
 export const metadata: Metadata = {
-	title: "Roo Code Evals",
+	title: TITLE,
+	description: DESCRIPTION,
+	alternates: {
+		canonical: `${SEO.url}${PATH}`,
+	},
 	openGraph: {
-		title: "Roo Code Evals",
-		description: "Quantitative evals of LLM coding skills.",
-		url: "https://roocode.com/evals",
-		siteName: "Roo Code",
-		images: {
-			url: "https://i.imgur.com/ijP7aZm.png",
-			width: 1954,
-			height: 1088,
-		},
+		title: TITLE,
+		description: DESCRIPTION,
+		url: `${SEO.url}${PATH}`,
+		siteName: SEO.name,
+		images: [IMAGE],
+		locale: SEO.locale,
+		type: "website",
+	},
+	twitter: {
+		card: SEO.twitterCard,
+		title: TITLE,
+		description: DESCRIPTION,
+		images: [IMAGE.url],
 	},
+	keywords: [...SEO.keywords, "benchmarks", "LLM evals", "coding evaluations", "model comparison"],
 }
 
 export default async function Page() {

+ 46 - 6
apps/web-roo-code/src/app/layout.tsx

@@ -2,6 +2,7 @@ import React from "react"
 import type { Metadata } from "next"
 import { Inter } from "next/font/google"
 import Script from "next/script"
+import { SEO } from "@/lib/seo"
 
 import { Providers } from "@/components/providers"
 
@@ -12,11 +13,14 @@ import "./globals.css"
 const inter = Inter({ subsets: ["latin"] })
 
 export const metadata: Metadata = {
-	title: "Roo Code – Your AI-Powered Dev Team in VS Code",
-	description:
-		"Roo Code puts an entire AI dev team right in your editor, outpacing closed tools with deep project-wide context, multi-step agentic coding, and unmatched developer-centric flexibility.",
+	metadataBase: new URL(SEO.url),
+	title: {
+		template: "%s | Roo Code",
+		default: SEO.title,
+	},
+	description: SEO.description,
 	alternates: {
-		canonical: "https://roocode.com",
+		canonical: SEO.url,
 	},
 	icons: {
 		icon: [
@@ -40,6 +44,42 @@ export const metadata: Metadata = {
 			},
 		],
 	},
+	openGraph: {
+		title: SEO.title,
+		description: SEO.description,
+		url: SEO.url,
+		siteName: SEO.name,
+		images: [
+			{
+				url: SEO.ogImage.url,
+				width: SEO.ogImage.width,
+				height: SEO.ogImage.height,
+				alt: SEO.ogImage.alt,
+			},
+		],
+		locale: SEO.locale,
+		type: "website",
+	},
+	twitter: {
+		card: SEO.twitterCard,
+		title: SEO.title,
+		description: SEO.description,
+		images: [SEO.ogImage.url],
+	},
+	robots: {
+		index: true,
+		follow: true,
+		googleBot: {
+			index: true,
+			follow: true,
+			"max-snippet": -1,
+			"max-image-preview": "large",
+			"max-video-preview": -1,
+		},
+	},
+	keywords: [...SEO.keywords],
+	applicationName: SEO.name,
+	category: SEO.category,
 }
 
 export default function RootLayout({ children }: { children: React.ReactNode }) {
@@ -64,8 +104,8 @@ export default function RootLayout({ children }: { children: React.ReactNode })
 					`}
 				</Script>
 				<div itemScope itemType="https://schema.org/WebSite">
-					<link itemProp="url" href="https://roocode.com" />
-					<meta itemProp="name" content="Roo Code" />
+					<link itemProp="url" href={SEO.url} />
+					<meta itemProp="name" content={SEO.name} />
 				</div>
 				<Providers>
 					<Shell>{children}</Shell>

+ 36 - 4
apps/web-roo-code/src/app/privacy/page.tsx

@@ -1,9 +1,41 @@
-import { Metadata } from "next"
+import type { Metadata } from "next"
+import { SEO } from "@/lib/seo"
+
+const TITLE = "Privacy Policy"
+const DESCRIPTION =
+	"Privacy policy for Roo Code Cloud and marketing website. Learn how we handle your data and protect your privacy."
+const PATH = "/privacy"
+const OG_IMAGE = SEO.ogImage
 
 export const metadata: Metadata = {
-	title: "Privacy Policy - Roo Code",
-	description:
-		"Privacy policy for Roo Code Cloud and marketing website. Learn how we handle your data and protect your privacy.",
+	title: TITLE,
+	description: DESCRIPTION,
+	alternates: {
+		canonical: `${SEO.url}${PATH}`,
+	},
+	openGraph: {
+		title: TITLE,
+		description: DESCRIPTION,
+		url: `${SEO.url}${PATH}`,
+		siteName: SEO.name,
+		images: [
+			{
+				url: OG_IMAGE.url,
+				width: OG_IMAGE.width,
+				height: OG_IMAGE.height,
+				alt: OG_IMAGE.alt,
+			},
+		],
+		locale: SEO.locale,
+		type: "article",
+	},
+	twitter: {
+		card: SEO.twitterCard,
+		title: TITLE,
+		description: DESCRIPTION,
+		images: [OG_IMAGE.url],
+	},
+	keywords: [...SEO.keywords, "privacy", "data protection", "GDPR", "security"],
 }
 
 export default function Privacy() {

+ 13 - 0
apps/web-roo-code/src/app/robots.ts

@@ -0,0 +1,13 @@
+import type { MetadataRoute } from "next"
+import { SEO } from "@/lib/seo"
+
+export default function robots(): MetadataRoute.Robots {
+	return {
+		rules: {
+			userAgent: "*",
+			allow: "/",
+		},
+		sitemap: `${SEO.url}/sitemap.xml`,
+		host: SEO.url,
+	}
+}

+ 36 - 4
apps/web-roo-code/src/app/terms/page.tsx

@@ -1,9 +1,41 @@
-import { Metadata } from "next"
+import type { Metadata } from "next"
+import { SEO } from "@/lib/seo"
+
+const TITLE = "Terms of Service"
+const DESCRIPTION =
+	"Terms of Service for Roo Code Cloud. Learn about our service terms, commercial conditions, and legal framework."
+const PATH = "/terms"
+const OG_IMAGE = SEO.ogImage
 
 export const metadata: Metadata = {
-	title: "Terms of Service - Roo Code",
-	description:
-		"Terms of Service for Roo Code Cloud. Learn about our service terms, commercial conditions, and legal framework.",
+	title: TITLE,
+	description: DESCRIPTION,
+	alternates: {
+		canonical: `${SEO.url}${PATH}`,
+	},
+	openGraph: {
+		title: TITLE,
+		description: DESCRIPTION,
+		url: `${SEO.url}${PATH}`,
+		siteName: SEO.name,
+		images: [
+			{
+				url: OG_IMAGE.url,
+				width: OG_IMAGE.width,
+				height: OG_IMAGE.height,
+				alt: OG_IMAGE.alt,
+			},
+		],
+		locale: SEO.locale,
+		type: "article",
+	},
+	twitter: {
+		card: SEO.twitterCard,
+		title: TITLE,
+		description: DESCRIPTION,
+		images: [OG_IMAGE.url],
+	},
+	keywords: [...SEO.keywords, "terms of service", "legal", "agreement", "subscription"],
 }
 
 export default function Terms() {

+ 30 - 0
apps/web-roo-code/src/lib/seo.ts

@@ -0,0 +1,30 @@
+const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://roocode.com"
+
+export const SEO = {
+	url: SITE_URL,
+	name: "Roo Code",
+	title: "Roo Code – Your AI-Powered Dev Team in VS Code",
+	description:
+		"Roo Code puts an entire AI dev team right in your editor, outpacing closed tools with deep project-wide context, multi-step agentic coding, and unmatched developer-centric flexibility.",
+	locale: "en_US",
+	ogImage: {
+		url: "/android-chrome-512x512.png",
+		width: 512,
+		height: 512,
+		alt: "Roo Code Logo",
+	},
+	keywords: [
+		"Roo Code",
+		"AI coding agent",
+		"VS Code extension",
+		"AI pair programmer",
+		"software development",
+		"agentic coding",
+		"code refactoring",
+		"debugging",
+	],
+	category: "technology",
+	twitterCard: "summary_large_image" as const,
+} as const
+
+export type SeoConfig = typeof SEO