Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit ac656da

Browse files
committed
feat(web): add install modal with multi-editor options
1 parent 0cd257a commit ac656da

3 files changed

Lines changed: 166 additions & 17 deletions

File tree

apps/web-roo-code/src/components/chromes/nav-bar.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { EXTERNAL_LINKS } from "@/lib/constants"
1313
import { useLogoSrc } from "@/lib/hooks/use-logo-src"
1414
import { ScrollButton } from "@/components/ui"
1515
import ThemeToggle from "@/components/chromes/theme-toggle"
16+
import { InstallModal } from "@/components/homepage/install-modal"
1617
import { Brain, Cloud, Puzzle, Slack, X } from "lucide-react"
1718
import {
1819
NavigationMenu,
@@ -40,6 +41,7 @@ interface NavBarProps {
4041

4142
export function NavBar({ stars, downloads }: NavBarProps) {
4243
const [isMenuOpen, setIsMenuOpen] = useState(false)
44+
const [isInstallModalOpen, setIsInstallModalOpen] = useState(false)
4345
const logoSrc = useLogoSrc()
4446

4547
return (
@@ -202,16 +204,15 @@ export function NavBar({ stars, downloads }: NavBarProps) {
202204
className="hidden items-center gap-1.5 rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground transition-all duration-200 hover:shadow-lg hover:scale-105 md:flex">
203205
Sign Up
204206
</a>
205-
<Link
206-
href={EXTERNAL_LINKS.MARKETPLACE}
207-
target="_blank"
207+
<button
208+
onClick={() => setIsInstallModalOpen(true)}
208209
className="hidden items-center gap-1.5 rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground transition-all duration-200 hover:shadow-lg hover:scale-105 md:flex whitespace-nowrap">
209210
<VscVscode className="-mr-[2px] mt-[1px] h-4 w-4" />
210211
<span>
211212
Install <span className="font-black max-lg:text-xs">&middot;</span>
212213
</span>
213214
{downloads !== null && <span>{downloads}</span>}
214-
</Link>
215+
</button>
215216
</div>
216217

217218
{/* Mobile Menu Button */}
@@ -332,14 +333,15 @@ export function NavBar({ stars, downloads }: NavBarProps) {
332333
<div className="flex items-center rounded-md p-3 transition-colors hover:bg-accent">
333334
<ThemeToggle />
334335
</div>
335-
<Link
336-
href={EXTERNAL_LINKS.MARKETPLACE}
337-
target="_blank"
338-
className="inline-flex items-center gap-2 rounded-md p-3 text-sm transition-colors hover:bg-accent hover:text-foreground"
339-
onClick={() => setIsMenuOpen(false)}>
336+
<button
337+
onClick={() => {
338+
setIsMenuOpen(false)
339+
setIsInstallModalOpen(true)
340+
}}
341+
className="inline-flex items-center gap-2 rounded-md p-3 text-sm transition-colors hover:bg-accent hover:text-foreground">
340342
<VscVscode className="h-6 w-6" />
341343
{downloads !== null && <span>{downloads}</span>}
342-
</Link>
344+
</button>
343345
</div>
344346
<div className="flex gap-2 px-4 pb-4">
345347
<a
@@ -362,6 +364,9 @@ export function NavBar({ stars, downloads }: NavBarProps) {
362364
</div>
363365
</nav>
364366
</div>
367+
368+
{/* Install Modal */}
369+
<InstallModal open={isInstallModalOpen} onOpenChange={setIsInstallModalOpen} />
365370
</header>
366371
)
367372
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
"use client"
2+
3+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/modal"
4+
import { motion } from "framer-motion"
5+
6+
interface Editor {
7+
name: string
8+
icon: React.ReactNode
9+
href: string
10+
}
11+
12+
// VS Code icon
13+
const VSCodeIcon = () => (
14+
<svg viewBox="0 0 100 100" className="w-full h-full" fill="none" xmlns="http://www.w3.org/2000/svg">
15+
<path
16+
d="M74.5 13.5L39.5 45L21.5 30.5L13.5 34V66L21.5 69.5L39.5 55L74.5 86.5L86.5 81.5V18.5L74.5 13.5Z"
17+
fill="#007ACC"
18+
/>
19+
<path d="M74.5 13.5L39.5 45L21.5 30.5L13.5 34V66L21.5 69.5L39.5 55L74.5 86.5" fill="#1F9CF0" />
20+
<path d="M21.5 30.5L13.5 34V66L21.5 69.5V30.5Z" fill="#0065A9" />
21+
<path d="M74.5 13.5L86.5 18.5V81.5L74.5 86.5V13.5Z" fill="#0065A9" />
22+
</svg>
23+
)
24+
25+
// VS Code Insiders icon
26+
const VSCodeInsidersIcon = () => (
27+
<svg viewBox="0 0 100 100" className="w-full h-full" fill="none" xmlns="http://www.w3.org/2000/svg">
28+
<path
29+
d="M74.5 13.5L39.5 45L21.5 30.5L13.5 34V66L21.5 69.5L39.5 55L74.5 86.5L86.5 81.5V18.5L74.5 13.5Z"
30+
fill="#24BFA5"
31+
/>
32+
<path d="M74.5 13.5L39.5 45L21.5 30.5L13.5 34V66L21.5 69.5L39.5 55L74.5 86.5" fill="#3DC9A9" />
33+
<path d="M21.5 30.5L13.5 34V66L21.5 69.5V30.5Z" fill="#1A9E82" />
34+
<path d="M74.5 13.5L86.5 18.5V81.5L74.5 86.5V13.5Z" fill="#1A9E82" />
35+
</svg>
36+
)
37+
38+
// Cursor icon
39+
const CursorIcon = () => (
40+
<svg viewBox="0 0 100 100" className="w-full h-full" fill="none" xmlns="http://www.w3.org/2000/svg">
41+
<rect width="100" height="100" rx="12" fill="#1E1E1E" />
42+
<path d="M30 25L70 50L30 75V25Z" fill="none" stroke="#FFFFFF" strokeWidth="6" strokeLinejoin="round" />
43+
</svg>
44+
)
45+
46+
// Windsurf icon
47+
const WindsurfIcon = () => (
48+
<svg viewBox="0 0 100 100" className="w-full h-full" fill="none" xmlns="http://www.w3.org/2000/svg">
49+
<rect width="100" height="100" rx="12" fill="#0F0F0F" />
50+
<path
51+
d="M25 65L40 35L55 55L75 25"
52+
fill="none"
53+
stroke="#06B6D4"
54+
strokeWidth="6"
55+
strokeLinecap="round"
56+
strokeLinejoin="round"
57+
/>
58+
<path
59+
d="M25 75L50 50L75 75"
60+
fill="none"
61+
stroke="#8B5CF6"
62+
strokeWidth="6"
63+
strokeLinecap="round"
64+
strokeLinejoin="round"
65+
/>
66+
</svg>
67+
)
68+
69+
const editors: Editor[] = [
70+
{
71+
name: "VS Code",
72+
icon: <VSCodeIcon />,
73+
href: "vscode:extension/RooVeterinaryInc.roo-cline",
74+
},
75+
{
76+
name: "VS Code Insiders",
77+
icon: <VSCodeInsidersIcon />,
78+
href: "vscode-insiders:extension/RooVeterinaryInc.roo-cline",
79+
},
80+
{
81+
name: "Cursor",
82+
icon: <CursorIcon />,
83+
href: "cursor:extension/RooVeterinaryInc.roo-cline",
84+
},
85+
{
86+
name: "Windsurf",
87+
icon: <WindsurfIcon />,
88+
href: "windsurf:extension/RooVeterinaryInc.roo-cline",
89+
},
90+
]
91+
92+
interface InstallModalProps {
93+
open: boolean
94+
onOpenChange: (open: boolean) => void
95+
}
96+
97+
export function InstallModal({ open, onOpenChange }: InstallModalProps) {
98+
return (
99+
<Dialog open={open} onOpenChange={onOpenChange}>
100+
<DialogContent className="sm:max-w-[500px] p-6">
101+
<DialogHeader className="text-center pb-4">
102+
<DialogTitle className="text-2xl font-bold text-center">Install Roo Code</DialogTitle>
103+
<DialogDescription className="text-center text-muted-foreground">Select your IDE</DialogDescription>
104+
</DialogHeader>
105+
106+
<div className="space-y-2 max-h-[60vh] overflow-y-auto pr-2 scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-transparent">
107+
{editors.map((editor, index) => (
108+
<motion.div
109+
key={editor.name}
110+
initial={{ opacity: 0, y: 10 }}
111+
animate={{ opacity: 1, y: 0 }}
112+
transition={{ delay: index * 0.05, duration: 0.3 }}
113+
className="group relative">
114+
<div className="relative flex items-center gap-3 p-2.5 bg-muted/30 border border-border/50 rounded-lg hover:bg-muted/50 hover:border-border transition-colors duration-150">
115+
<div className="relative flex-shrink-0">
116+
<div className="w-12 h-12 bg-background shadow-sm border border-border/50 rounded-lg p-2 overflow-hidden">
117+
{editor.icon}
118+
</div>
119+
</div>
120+
<div className="flex-grow min-w-0">
121+
<h3 className="text-base font-semibold text-foreground">{editor.name}</h3>
122+
</div>
123+
<div className="flex items-center">
124+
<a
125+
href={editor.href}
126+
target={editor.href.startsWith("http") ? "_blank" : undefined}
127+
rel={editor.href.startsWith("http") ? "noopener noreferrer" : undefined}
128+
className="px-4 py-2 bg-primary hover:bg-primary/90 active:bg-primary/80 text-primary-foreground text-xs font-semibold rounded-md transition-colors duration-150 shadow-sm">
129+
Install
130+
</a>
131+
</div>
132+
</div>
133+
</motion.div>
134+
))}
135+
</div>
136+
</DialogContent>
137+
</Dialog>
138+
)
139+
}

apps/web-roo-code/src/components/homepage/install-section.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
"use client"
22

3+
import { useState } from "react"
34
import { VscVscode } from "react-icons/vsc"
4-
import Link from "next/link"
55
import { motion } from "framer-motion"
6+
import { InstallModal } from "./install-modal"
67

78
interface InstallSectionProps {
89
downloads: string | null
910
}
1011

1112
export function InstallSection({ downloads }: InstallSectionProps) {
13+
const [isModalOpen, setIsModalOpen] = useState(false)
14+
1215
const backgroundVariants = {
1316
hidden: {
1417
opacity: 0,
@@ -57,16 +60,15 @@ export function InstallSection({ downloads }: InstallSectionProps) {
5760
</p>
5861

5962
<div className="mt-12 flex flex-col items-center justify-center gap-6">
60-
{/* Enhanced VSCode Marketplace button */}
61-
<Link
62-
href="https://marketplace.visualstudio.com/items?itemName=RooVeterinaryInc.roo-cline"
63-
target="_blank"
63+
{/* Install button that opens modal */}
64+
<button
65+
onClick={() => setIsModalOpen(true)}
6466
className="group relative inline-flex w-full items-center justify-center gap-3 rounded-xl bg-gradient-to-r from-blue-600 to-cyan-600 px-6 py-4 text-lg font-medium text-white shadow-lg transition-all duration-300 hover:from-blue-700 hover:to-cyan-700 hover:shadow-xl hover:shadow-blue-500/25 dark:from-blue-500 dark:to-cyan-500 dark:hover:from-blue-600 dark:hover:to-cyan-600 sm:w-auto sm:px-8 sm:text-xl">
6567
<div className="absolute -inset-px rounded-xl bg-gradient-to-r from-blue-400 via-cyan-400 to-blue-400 opacity-0 blur transition-opacity duration-500 group-hover:opacity-70" />
6668
<div className="relative flex flex-col md:flex-row items-center md:gap-3">
6769
<VscVscode className="h-6 w-6 shrink-0" />
6870
<span className="flex flex-col md:flex-row items-center md:gap-2">
69-
<span>From VS Code Marketplace</span>
71+
<span>Install Roo Code</span>
7072
{downloads !== null && (
7173
<>
7274
<span className="font-black opacity-60 hidden md:inline">
@@ -77,7 +79,7 @@ export function InstallSection({ downloads }: InstallSectionProps) {
7779
)}
7880
</span>
7981
</div>
80-
</Link>
82+
</button>
8183

8284
{/* Enhanced CLI install section */}
8385
<div className="group relative w-full max-w-xl">
@@ -100,6 +102,9 @@ export function InstallSection({ downloads }: InstallSectionProps) {
100102
</div>
101103
</div>
102104
</div>
105+
106+
{/* Install Modal */}
107+
<InstallModal open={isModalOpen} onOpenChange={setIsModalOpen} />
103108
</section>
104109
)
105110
}

0 commit comments

Comments
 (0)