mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat(web): bias Google Sitelinks toward Extension, Cloud, Docs, Pricing
- Add /extension canonical page with metadata and BreadcrumbList JSON-LD - Header: change 'Extension' to link /extension (desktop & mobile) - Home hero: add above-the-fold Docs/Pricing links - Footer: add Cloud and Pricing under Product - Sitemap: prioritize /extension (0.9), /cloud & /pricing (0.8); fix additionalPaths; reduce /enterprise - Robots: publish roocode.com and docs.roocode.com sitemaps - Structured data: add SiteNavigationElement; per-page BreadcrumbList - Ensure explicit metadata on Cloud/Pricing/Extension; fix rel for target=_blank
This commit is contained in:
parent
f30caf277c
commit
f0802f1bec
9 changed files with 197 additions and 29 deletions
|
|
@ -33,9 +33,18 @@ module.exports = {
|
|||
if (path === '/') {
|
||||
priority = 1.0;
|
||||
changefreq = 'yearly';
|
||||
} else if (path === '/enterprise' || path === '/evals') {
|
||||
} else if (path === '/extension') {
|
||||
priority = 0.9;
|
||||
changefreq = 'monthly';
|
||||
} else if (path === '/cloud' || path === '/pricing') {
|
||||
priority = 0.8;
|
||||
changefreq = 'monthly';
|
||||
} else if (path === '/enterprise') {
|
||||
priority = 0.5;
|
||||
changefreq = 'yearly';
|
||||
} else if (path === '/evals') {
|
||||
priority = 0.6;
|
||||
changefreq = 'monthly';
|
||||
} else if (path === '/privacy' || path === '/terms') {
|
||||
priority = 0.5;
|
||||
changefreq = 'yearly';
|
||||
|
|
@ -50,24 +59,20 @@ module.exports = {
|
|||
};
|
||||
},
|
||||
additionalPaths: async (config) => {
|
||||
// Add any additional paths that might not be automatically discovered
|
||||
// This is useful for dynamic routes or API-generated pages
|
||||
// Add the /evals page since it's a dynamic route
|
||||
return [{
|
||||
loc: '/evals',
|
||||
changefreq: 'monthly',
|
||||
priority: 0.8,
|
||||
lastmod: new Date().toISOString(),
|
||||
}];
|
||||
|
||||
// Add the /evals page since it's a dynamic route
|
||||
result.push({
|
||||
loc: '/evals',
|
||||
changefreq: 'monthly',
|
||||
priority: 0.8,
|
||||
lastmod: new Date().toISOString(),
|
||||
});
|
||||
|
||||
return result;
|
||||
// Explicitly include dynamic or non-file-system paths
|
||||
return [
|
||||
{
|
||||
loc: '/evals',
|
||||
changefreq: 'monthly',
|
||||
priority: 0.6,
|
||||
lastmod: new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
loc: '/extension',
|
||||
changefreq: 'monthly',
|
||||
priority: 0.9,
|
||||
lastmod: new Date().toISOString(),
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
|
@ -119,8 +119,17 @@ const cloudFeatures: Feature[] = [
|
|||
import screenshotDark from "/public/heroes/cloud-screen.png"
|
||||
|
||||
export default function CloudPage() {
|
||||
const breadcrumbLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{ "@type": "ListItem", position: 1, name: "Home", item: SEO.url },
|
||||
{ "@type": "ListItem", position: 2, name: "Cloud", item: `${SEO.url}${PATH}` },
|
||||
],
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbLd) }} />
|
||||
<section className="relative flex md:h-[calc(80vh-theme(spacing.12))] items-center overflow-hidden">
|
||||
<AnimatedBackground />
|
||||
<div className="container relative flex items-center h-full z-10 mx-auto px-4 sm:px-6 lg:px-8">
|
||||
|
|
|
|||
102
apps/web-roo-code/src/app/extension/page.tsx
Normal file
102
apps/web-roo-code/src/app/extension/page.tsx
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
import { ArrowRight } from "lucide-react"
|
||||
import type { Metadata } from "next"
|
||||
import Link from "next/link"
|
||||
|
||||
import { Button } from "@/components/ui"
|
||||
import { AnimatedBackground } from "@/components/homepage"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { EXTERNAL_LINKS } from "@/lib/constants"
|
||||
|
||||
const TITLE = "Roo Code Extension"
|
||||
const DESCRIPTION = "Open-source VS Code extension that turns your editor into an AI dev team. Works with any model."
|
||||
const PATH = "/extension"
|
||||
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, "VS Code extension", "Roo Code extension"],
|
||||
}
|
||||
|
||||
export default function ExtensionPage() {
|
||||
const breadcrumbLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{ "@type": "ListItem", position: 1, name: "Home", item: SEO.url },
|
||||
{ "@type": "ListItem", position: 2, name: "Extension", item: `${SEO.url}${PATH}` },
|
||||
],
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbLd) }} />
|
||||
<section className="relative flex md:h-[calc(80vh-theme(spacing.12))] items-center overflow-hidden">
|
||||
<AnimatedBackground />
|
||||
<div className="container relative flex items-center h-full z-10 mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid h-full relative gap-8 lg:grid-cols-2">
|
||||
<div className="flex flex-col px-4 justify-center space-y-6 sm:space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold tracking-tight mt-8 text-center md:text-left md:text-4xl lg:text-5xl lg:mt-0">
|
||||
Roo Code Extension
|
||||
</h1>
|
||||
<p className="mt-4 max-w-md text-lg text-muted-foreground text-center md:text-left sm:mt-6">
|
||||
Open-source AI coding agent that lives in VS Code. Multi-step, project‑wide context,
|
||||
and works with any model.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-3 sm:flex-row sm:space-x-4 sm:space-y-0">
|
||||
<Button
|
||||
size="lg"
|
||||
className="w-full hover:bg-gray-200 dark:bg-white dark:text-black sm:w-auto">
|
||||
<a
|
||||
href={EXTERNAL_LINKS.MARKETPLACE}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex w-full items-center justify-center">
|
||||
Install VS Code Extension
|
||||
<ArrowRight className="ml-2" />
|
||||
</a>
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="w-full sm:w-auto bg-white/20 dark:bg-white/10 backdrop-blur-sm border border-black/40 dark:border-white/30 hover:border-blue-400 hover:bg-white/30 dark:hover:bg-white/20 hover:shadow-[0_0_20px_rgba(59,130,246,0.5)] transition-all duration-300">
|
||||
<a
|
||||
href={EXTERNAL_LINKS.DOCUMENTATION}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex w-full items-center justify-center">
|
||||
Docs
|
||||
<ArrowRight className="ml-2" />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground text-center md:text-left">
|
||||
<Link href="/pricing" className="underline underline-offset-4 hover:text-foreground">
|
||||
Pricing
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from "@/components/homepage"
|
||||
import { EXTERNAL_LINKS } from "@/lib/constants"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { StructuredData } from "@/components/structured-data"
|
||||
|
||||
// Invalidate cache when a request comes in, at most once every hour.
|
||||
|
|
@ -64,6 +65,19 @@ export default async function Home() {
|
|||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground text-center md:text-left">
|
||||
<a
|
||||
href={EXTERNAL_LINKS.DOCUMENTATION}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline underline-offset-4 hover:text-foreground">
|
||||
Docs
|
||||
</a>
|
||||
<span className="mx-2">•</span>
|
||||
<Link href="/pricing" className="underline underline-offset-4 hover:text-foreground">
|
||||
Pricing
|
||||
</Link>
|
||||
</div>
|
||||
<CompanyLogos />
|
||||
</div>
|
||||
<div className="relative flex items-center mx-auto h-full mt-8 lg:mt-0">
|
||||
|
|
|
|||
|
|
@ -132,9 +132,18 @@ const pricingTiers: PricingTier[] = [
|
|||
]
|
||||
|
||||
export default function PricingPage() {
|
||||
const breadcrumbLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{ "@type": "ListItem", position: 1, name: "Home", item: SEO.url },
|
||||
{ "@type": "ListItem", position: 2, name: "Pricing", item: `${SEO.url}${PATH}` },
|
||||
],
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<AnimatedBackground />
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbLd) }} />
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative overflow-hidden pt-16 pb-12">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export default function robots(): MetadataRoute.Robots {
|
|||
userAgent: "*",
|
||||
allow: "/",
|
||||
},
|
||||
sitemap: `${SEO.url}/sitemap.xml`,
|
||||
sitemap: [`${SEO.url}/sitemap.xml`, "https://docs.roocode.com/sitemap.xml"],
|
||||
host: SEO.url,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,20 @@ export function Footer() {
|
|||
Docs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href="/cloud"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Cloud
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href="/pricing"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Pricing
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.CHANGELOG}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ export function NavBar({ stars, downloads }: NavBarProps) {
|
|||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="grow ml-6 hidden text-sm font-medium md:flex md:items-center">
|
||||
<ScrollButton
|
||||
targetId="product"
|
||||
<Link
|
||||
href="/extension"
|
||||
className="text-muted-foreground px-4 py-6 transition-transform duration-200 hover:scale-105 hover:text-foreground max-lg:hidden">
|
||||
Extension
|
||||
</ScrollButton>
|
||||
</Link>
|
||||
<Link
|
||||
href="/cloud"
|
||||
className="text-muted-foreground px-4 py-6 transition-transform duration-200 hover:scale-105 hover:text-foreground">
|
||||
|
|
@ -141,12 +141,12 @@ export function NavBar({ stars, downloads }: NavBarProps) {
|
|||
<nav className="flex flex-col justify-between h-full pb-16 overflow-y-auto bg-background pointer-events-auto">
|
||||
{/* Main navigation items */}
|
||||
<div className="grow-1 py-4 font-semibold text-lg">
|
||||
<ScrollButton
|
||||
targetId="product"
|
||||
<Link
|
||||
href="/extension"
|
||||
className="block w-full p-5 py-3 text-left text-foreground active:opacity-50"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
Extension
|
||||
</ScrollButton>
|
||||
</Link>
|
||||
<Link
|
||||
href="/cloud"
|
||||
className="block w-full p-5 text-left text-foreground active:opacity-50"
|
||||
|
|
|
|||
|
|
@ -47,9 +47,17 @@ interface SoftwareApplication {
|
|||
publisher: { "@id": string }
|
||||
}
|
||||
|
||||
interface SiteNavigationElement {
|
||||
"@type": "SiteNavigationElement"
|
||||
name: string
|
||||
url: string
|
||||
}
|
||||
|
||||
type GraphNode = Organization | WebSite | SoftwareApplication | SiteNavigationElement
|
||||
|
||||
interface StructuredDataGraph {
|
||||
"@context": "https://schema.org"
|
||||
"@graph": [Organization, WebSite, SoftwareApplication]
|
||||
"@graph": GraphNode[]
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -115,9 +123,16 @@ export function getStructuredData(): StructuredDataGraph {
|
|||
publisher: { "@id": orgId },
|
||||
}
|
||||
|
||||
const siteNavigation: SiteNavigationElement[] = [
|
||||
{ "@type": "SiteNavigationElement", name: "Extension", url: `${SEO.url}/extension` },
|
||||
{ "@type": "SiteNavigationElement", name: "Cloud", url: `${SEO.url}/cloud` },
|
||||
{ "@type": "SiteNavigationElement", name: "Docs", url: EXTERNAL_LINKS.DOCUMENTATION },
|
||||
{ "@type": "SiteNavigationElement", name: "Pricing", url: `${SEO.url}/pricing` },
|
||||
]
|
||||
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [organization, website, softwareApplication],
|
||||
"@graph": [organization, website, softwareApplication, ...siteNavigation],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue