Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions apps/web-roo-code/next-sitemap.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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(),
},
Comment on lines +71 to +75
Copy link

Copilot AI Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Since /extension is now a file-system route, it will be auto-discovered by next-sitemap. Keeping it in additionalPaths can create duplicate entries in the sitemap; consider removing this block and relying on transform() to set its priority.

Copilot uses AI. Check for mistakes.
];
},
};
9 changes: 9 additions & 0 deletions apps/web-roo-code/src/app/cloud/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
102 changes: 102 additions & 0 deletions apps/web-roo-code/src/app/extension/page.tsx
Original file line number Diff line number Diff line change
@@ -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"
Copy link

Copilot AI Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using target="_blank", also include rel="noopener" to prevent the new page from gaining access to window.opener. Update to rel="noopener noreferrer".

Copilot uses AI. Check for mistakes.
className="flex w-full items-center justify-center">
Install VS Code Extension
<ArrowRight className="ml-2" />
</a>
Comment on lines +68 to +75
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These external links should use rel="noopener noreferrer" instead of just rel="noreferrer" to prevent the opened page from accessing window.opener, which is a security best practice. This pattern is consistently used throughout the codebase (see page.tsx:72, cloud/page.tsx:155, pricing/page.tsx:244).

</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"
Copy link

Copilot AI Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add rel="noopener" alongside noreferrer for external links opened with target="_blank" to mitigate reverse tabnabbing (use rel="noopener noreferrer").

Copilot uses AI. Check for mistakes.
className="flex w-full items-center justify-center">
Docs
<ArrowRight className="ml-2" />
</a>
</Button>
Comment on lines +65 to +89
Copy link

Copilot AI Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid nesting interactive elements ( inside a button). This is invalid HTML and problematic for screen readers/keyboard nav. Prefer rendering the anchor as the button via an asChild prop or wrapping the Button around a Link/anchor that renders as the clickable element (e.g., <a ... />), or make the outer element the anchor styled like a button.

Copilot uses AI. Check for mistakes.
</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 changes: 14 additions & 0 deletions apps/web-roo-code/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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">
Expand Down
9 changes: 9 additions & 0 deletions apps/web-roo-code/src/app/pricing/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
2 changes: 1 addition & 1 deletion apps/web-roo-code/src/app/robots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
14 changes: 14 additions & 0 deletions apps/web-roo-code/src/components/chromes/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
12 changes: 6 additions & 6 deletions apps/web-roo-code/src/components/chromes/nav-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down Expand Up @@ -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"
Expand Down
19 changes: 17 additions & 2 deletions apps/web-roo-code/src/lib/structured-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
}

/**
Expand Down Expand Up @@ -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],
}
}

Expand Down
Loading