|
| 1 | +import { |
| 2 | + ArrowRight, |
| 3 | + Brain, |
| 4 | + CreditCard, |
| 5 | + GitBranch, |
| 6 | + GraduationCap, |
| 7 | + Link2, |
| 8 | + LucideIcon, |
| 9 | + MessageSquare, |
| 10 | + Settings, |
| 11 | + Shield, |
| 12 | + Slack, |
| 13 | + Users, |
| 14 | + Zap, |
| 15 | +} from "lucide-react" |
| 16 | +import type { Metadata } from "next" |
| 17 | + |
| 18 | +import { Button } from "@/components/ui" |
| 19 | +import { AnimatedBackground } from "@/components/homepage" |
| 20 | +import { SEO } from "@/lib/seo" |
| 21 | +import { ogImageUrl } from "@/lib/og" |
| 22 | +import { EXTERNAL_LINKS } from "@/lib/constants" |
| 23 | + |
| 24 | +const TITLE = "Roo Code for Slack" |
| 25 | +const DESCRIPTION = |
| 26 | + "Mention @Roomote in any channel to explain code, plan features, or ship a PR, all without leaving the conversation." |
| 27 | +const OG_DESCRIPTION = "Your AI Team in Slack" |
| 28 | +const PATH = "/slack" |
| 29 | + |
| 30 | +export const metadata: Metadata = { |
| 31 | + title: TITLE, |
| 32 | + description: DESCRIPTION, |
| 33 | + alternates: { |
| 34 | + canonical: `${SEO.url}${PATH}`, |
| 35 | + }, |
| 36 | + openGraph: { |
| 37 | + title: TITLE, |
| 38 | + description: DESCRIPTION, |
| 39 | + url: `${SEO.url}${PATH}`, |
| 40 | + siteName: SEO.name, |
| 41 | + images: [ |
| 42 | + { |
| 43 | + url: ogImageUrl(TITLE, OG_DESCRIPTION), |
| 44 | + width: 1200, |
| 45 | + height: 630, |
| 46 | + alt: TITLE, |
| 47 | + }, |
| 48 | + ], |
| 49 | + locale: SEO.locale, |
| 50 | + type: "website", |
| 51 | + }, |
| 52 | + twitter: { |
| 53 | + card: SEO.twitterCard, |
| 54 | + title: TITLE, |
| 55 | + description: DESCRIPTION, |
| 56 | + images: [ogImageUrl(TITLE, OG_DESCRIPTION)], |
| 57 | + }, |
| 58 | + keywords: [ |
| 59 | + ...SEO.keywords, |
| 60 | + "slack integration", |
| 61 | + "slack bot", |
| 62 | + "AI in slack", |
| 63 | + "code assistant slack", |
| 64 | + "@Roomote", |
| 65 | + "team collaboration", |
| 66 | + ], |
| 67 | +} |
| 68 | + |
| 69 | +// Invalidate cache when a request comes in, at most once every hour. |
| 70 | +export const revalidate = 3600 |
| 71 | + |
| 72 | +interface ValueProp { |
| 73 | + icon: LucideIcon |
| 74 | + title: string |
| 75 | + description: string |
| 76 | +} |
| 77 | + |
| 78 | +const VALUE_PROPS: ValueProp[] = [ |
| 79 | + { |
| 80 | + icon: GitBranch, |
| 81 | + title: "From discussion to shipped feature.", |
| 82 | + description: |
| 83 | + "Your team discusses a feature in Slack. @Roomote turns the discussion into a plan. Then builds it. All without leaving the conversation.", |
| 84 | + }, |
| 85 | + { |
| 86 | + icon: Brain, |
| 87 | + title: "The agent knows the thread.", |
| 88 | + description: |
| 89 | + '@Roomote reads the full conversation before responding, so follow-up questions like "why is this happening?" just work.', |
| 90 | + }, |
| 91 | + { |
| 92 | + icon: Link2, |
| 93 | + title: "Chain agents for complex work.", |
| 94 | + description: |
| 95 | + "Start with a Planner to spec it out. Then call the Coder to build it. Multi-step workflows, one Slack thread.", |
| 96 | + }, |
| 97 | + { |
| 98 | + icon: Users, |
| 99 | + title: "Anyone can contribute.", |
| 100 | + description: |
| 101 | + "PMs, CSMs, and Sales can ask @Roomote to explain code or investigate issues. Engineering gets pulled in only when truly needed.", |
| 102 | + }, |
| 103 | + { |
| 104 | + icon: GraduationCap, |
| 105 | + title: "Team learning, built in.", |
| 106 | + description: "Public channel mentions show everyone how to leverage agents. Learn by watching.", |
| 107 | + }, |
| 108 | + { |
| 109 | + icon: Shield, |
| 110 | + title: "Safe by design.", |
| 111 | + description: "Agents never touch main/master directly. They produce branches and PRs. You approve.", |
| 112 | + }, |
| 113 | +] |
| 114 | + |
| 115 | +interface WorkflowStep { |
| 116 | + step: number |
| 117 | + title: string |
| 118 | + description: string |
| 119 | + code?: string |
| 120 | +} |
| 121 | + |
| 122 | +const WORKFLOW_STEPS: WorkflowStep[] = [ |
| 123 | + { |
| 124 | + step: 1, |
| 125 | + title: "Turn the discussion into a plan", |
| 126 | + description: "Your team discusses a feature. When it gets complex, summon the Planner agent.", |
| 127 | + code: "@Roomote plan out a dark mode feature based on our discussion. Include the toggle, persistence, and system preference detection.", |
| 128 | + }, |
| 129 | + { |
| 130 | + step: 2, |
| 131 | + title: "Refine the plan in the thread", |
| 132 | + description: |
| 133 | + "The team reviews the spec in the thread, suggests changes, asks questions. Mention @Roomote again to refine.", |
| 134 | + }, |
| 135 | + { |
| 136 | + step: 3, |
| 137 | + title: "Build the plan", |
| 138 | + description: "Once the plan looks good, hand it off to the Coder agent to implement.", |
| 139 | + code: "@Roomote implement this plan in the frontend-web repo.", |
| 140 | + }, |
| 141 | + { |
| 142 | + step: 4, |
| 143 | + title: "Review and ship", |
| 144 | + description: "The Coder creates a branch and opens a PR. The team reviews, and the feature ships.", |
| 145 | + }, |
| 146 | +] |
| 147 | + |
| 148 | +interface OnboardingStep { |
| 149 | + icon: LucideIcon |
| 150 | + title: string |
| 151 | + description: string |
| 152 | + link?: { |
| 153 | + href: string |
| 154 | + text: string |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +const ONBOARDING_STEPS: OnboardingStep[] = [ |
| 159 | + { |
| 160 | + icon: CreditCard, |
| 161 | + title: "1. Team Plan", |
| 162 | + description: "Slack requires a Team plan.", |
| 163 | + link: { |
| 164 | + href: EXTERNAL_LINKS.CLOUD_APP_TEAM_TRIAL, |
| 165 | + text: "Start a free trial", |
| 166 | + }, |
| 167 | + }, |
| 168 | + { |
| 169 | + icon: Settings, |
| 170 | + title: "2. Connect", |
| 171 | + description: 'Sign in to Roo Code Cloud and go to Settings. Click "Connect" next to Slack.', |
| 172 | + }, |
| 173 | + { |
| 174 | + icon: Slack, |
| 175 | + title: "3. Authorize", |
| 176 | + description: "Authorize the Roo Code app to access your Slack workspace.", |
| 177 | + }, |
| 178 | + { |
| 179 | + icon: MessageSquare, |
| 180 | + title: "4. Add to channels", |
| 181 | + description: "Add @Roomote to the channels where you want it available.", |
| 182 | + }, |
| 183 | +] |
| 184 | + |
| 185 | +export default function SlackPage() { |
| 186 | + return ( |
| 187 | + <> |
| 188 | + {/* Hero Section */} |
| 189 | + <section className="relative flex pt-32 pb-20 items-center overflow-hidden"> |
| 190 | + <AnimatedBackground /> |
| 191 | + <div className="container relative flex flex-col items-center h-full z-10 mx-auto px-4 sm:px-6 lg:px-8"> |
| 192 | + <div className="text-center max-w-4xl mx-auto mb-12"> |
| 193 | + <div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-violet-100 dark:bg-violet-900/30 text-violet-700 dark:text-violet-300 text-sm font-medium mb-6"> |
| 194 | + <Slack className="size-4" /> |
| 195 | + Powered by Roo Code Cloud |
| 196 | + </div> |
| 197 | + <h1 className="text-4xl font-bold tracking-tight mb-6 md:text-5xl lg:text-6xl"> |
| 198 | + <span className="text-violet-500">@Roomote:</span> Your AI Team in Slack |
| 199 | + </h1> |
| 200 | + <p className="text-xl text-muted-foreground mb-8 max-w-2xl mx-auto"> |
| 201 | + Mention @Roomote in any channel to explain code, plan features, or ship a PR, all without |
| 202 | + leaving the conversation. |
| 203 | + </p> |
| 204 | + <div className="flex flex-col sm:flex-row gap-4 justify-center"> |
| 205 | + <Button |
| 206 | + size="xl" |
| 207 | + className="bg-violet-600 hover:bg-violet-700 text-white transition-all duration-300 shadow-lg hover:shadow-violet-500/25" |
| 208 | + asChild> |
| 209 | + <a |
| 210 | + href={EXTERNAL_LINKS.CLOUD_APP_SIGNUP} |
| 211 | + target="_blank" |
| 212 | + rel="noopener noreferrer" |
| 213 | + className="flex items-center justify-center"> |
| 214 | + Get Started |
| 215 | + <ArrowRight className="ml-2 size-5" /> |
| 216 | + </a> |
| 217 | + </Button> |
| 218 | + <Button variant="outline" size="xl" className="backdrop-blur-sm" asChild> |
| 219 | + <a |
| 220 | + href={EXTERNAL_LINKS.SLACK_DOCS} |
| 221 | + target="_blank" |
| 222 | + rel="noopener noreferrer" |
| 223 | + className="flex items-center justify-center"> |
| 224 | + Read the Docs |
| 225 | + </a> |
| 226 | + </Button> |
| 227 | + </div> |
| 228 | + </div> |
| 229 | + </div> |
| 230 | + </section> |
| 231 | + |
| 232 | + {/* Value Props Section */} |
| 233 | + <section className="py-24 bg-muted/30"> |
| 234 | + <div className="container mx-auto px-4 sm:px-6 lg:px-8 relative"> |
| 235 | + <div className="absolute inset-y-0 left-1/2 h-full w-full max-w-[1200px] -translate-x-1/2 z-1"> |
| 236 | + <div className="absolute left-1/2 top-1/2 h-[800px] w-full -translate-x-1/2 -translate-y-1/2 rounded-full bg-violet-500/10 dark:bg-violet-700/20 blur-[140px]" /> |
| 237 | + </div> |
| 238 | + <div className="text-center mb-16"> |
| 239 | + <h2 className="text-3xl font-bold tracking-tight sm:text-4xl mb-4"> |
| 240 | + Why your team will love using Roo Code in Slack |
| 241 | + </h2> |
| 242 | + <p className="text-xl text-muted-foreground max-w-2xl mx-auto"> |
| 243 | + AI agents that understand context, chain together for complex work, and keep humans in |
| 244 | + control. |
| 245 | + </p> |
| 246 | + </div> |
| 247 | + <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto relative"> |
| 248 | + {VALUE_PROPS.map((prop, index) => { |
| 249 | + const Icon = prop.icon |
| 250 | + return ( |
| 251 | + <div |
| 252 | + key={index} |
| 253 | + className="bg-background p-8 rounded-2xl border border-border hover:shadow-lg transition-all duration-300"> |
| 254 | + <div className="bg-violet-100 dark:bg-violet-900/20 w-12 h-12 rounded-lg flex items-center justify-center mb-6"> |
| 255 | + <Icon className="size-6 text-violet-600 dark:text-violet-400" /> |
| 256 | + </div> |
| 257 | + <h3 className="text-xl font-semibold mb-3">{prop.title}</h3> |
| 258 | + <p className="text-muted-foreground leading-relaxed">{prop.description}</p> |
| 259 | + </div> |
| 260 | + ) |
| 261 | + })} |
| 262 | + </div> |
| 263 | + </div> |
| 264 | + </section> |
| 265 | + |
| 266 | + {/* Featured Workflow Section */} |
| 267 | + <section className="relative overflow-hidden border-t border-border py-32"> |
| 268 | + <div className="container relative z-10 mx-auto px-4 sm:px-6 lg:px-8"> |
| 269 | + <div className="absolute inset-y-0 left-1/2 h-full w-full max-w-[1200px] -translate-x-1/2 z-1"> |
| 270 | + <div className="absolute left-1/2 top-1/2 h-[400px] w-full -translate-x-1/2 -translate-y-1/2 rounded-full bg-blue-500/10 dark:bg-blue-700/20 blur-[140px]" /> |
| 271 | + </div> |
| 272 | + |
| 273 | + <div className="mx-auto mb-12 md:mb-24 max-w-5xl text-center"> |
| 274 | + <div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 text-sm font-medium mb-6"> |
| 275 | + <Zap className="size-4" /> |
| 276 | + Featured Workflow |
| 277 | + </div> |
| 278 | + <h2 className="text-3xl font-bold tracking-tight sm:text-5xl mb-4"> |
| 279 | + Thread to Shipped Feature |
| 280 | + </h2> |
| 281 | + <p className="text-xl text-muted-foreground max-w-2xl mx-auto"> |
| 282 | + Turn Slack discussions into working code. No context lost, no meetings needed. |
| 283 | + </p> |
| 284 | + </div> |
| 285 | + |
| 286 | + <div className="relative mx-auto md:max-w-[1000px]"> |
| 287 | + {/* Workflow Steps */} |
| 288 | + <div className="grid grid-cols-1 md:grid-cols-2 gap-6 lg:gap-8"> |
| 289 | + {WORKFLOW_STEPS.map((step) => ( |
| 290 | + <div |
| 291 | + key={step.step} |
| 292 | + className="relative border border-border rounded-2xl bg-background p-8 transition-all duration-300 hover:shadow-lg"> |
| 293 | + <div className="flex items-center gap-3 mb-4"> |
| 294 | + <div className="bg-blue-100 dark:bg-blue-900/30 w-10 h-10 rounded-full flex items-center justify-center text-blue-700 dark:text-blue-300 font-bold"> |
| 295 | + {step.step} |
| 296 | + </div> |
| 297 | + <h3 className="text-xl font-semibold text-foreground">{step.title}</h3> |
| 298 | + </div> |
| 299 | + <p className="leading-relaxed font-light text-muted-foreground mb-4"> |
| 300 | + {step.description} |
| 301 | + </p> |
| 302 | + {step.code && ( |
| 303 | + <div className="bg-muted/50 rounded-lg p-4 font-mono text-sm text-foreground/80 border border-border/50"> |
| 304 | + {step.code} |
| 305 | + </div> |
| 306 | + )} |
| 307 | + </div> |
| 308 | + ))} |
| 309 | + </div> |
| 310 | + </div> |
| 311 | + </div> |
| 312 | + </section> |
| 313 | + |
| 314 | + {/* Onboarding Section */} |
| 315 | + <section className="py-24 bg-muted/30"> |
| 316 | + <div className="container mx-auto px-4 sm:px-6 lg:px-8"> |
| 317 | + <div className="text-center mb-16"> |
| 318 | + <h2 className="text-3xl font-bold tracking-tight sm:text-4xl mb-4">Get started in minutes</h2> |
| 319 | + <p className="text-xl text-muted-foreground max-w-2xl mx-auto"> |
| 320 | + Connect your Slack workspace and start working with AI agents. |
| 321 | + </p> |
| 322 | + </div> |
| 323 | + <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 max-w-5xl mx-auto"> |
| 324 | + {ONBOARDING_STEPS.map((step, index) => { |
| 325 | + const Icon = step.icon |
| 326 | + return ( |
| 327 | + <div key={index} className="text-center"> |
| 328 | + <div className="bg-violet-100 dark:bg-violet-900/20 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-6"> |
| 329 | + <Icon className="size-8 text-violet-600 dark:text-violet-400" /> |
| 330 | + </div> |
| 331 | + <h3 className="text-lg font-semibold mb-2">{step.title}</h3> |
| 332 | + <p className="text-muted-foreground"> |
| 333 | + {step.description} |
| 334 | + {step.link && ( |
| 335 | + <> |
| 336 | + {" "} |
| 337 | + <a |
| 338 | + href={step.link.href} |
| 339 | + target="_blank" |
| 340 | + rel="noopener noreferrer" |
| 341 | + className="text-violet-600 dark:text-violet-400 hover:underline"> |
| 342 | + {step.link.text} → |
| 343 | + </a> |
| 344 | + </> |
| 345 | + )} |
| 346 | + </p> |
| 347 | + </div> |
| 348 | + ) |
| 349 | + })} |
| 350 | + </div> |
| 351 | + </div> |
| 352 | + </section> |
| 353 | + |
| 354 | + {/* CTA Section */} |
| 355 | + <section className="py-24"> |
| 356 | + <div className="container mx-auto px-4 sm:px-6 lg:px-8"> |
| 357 | + <div className="mx-auto max-w-4xl rounded-3xl border border-border/50 bg-gradient-to-br from-violet-500/10 via-purple-500/5 to-blue-500/5 p-8 text-center shadow-2xl backdrop-blur-xl dark:border-white/10 sm:p-16"> |
| 358 | + <h2 className="mb-6 text-3xl font-bold tracking-tight sm:text-4xl"> |
| 359 | + Start using Roo Code in Slack |
| 360 | + </h2> |
| 361 | + <p className="mx-auto mb-10 max-w-2xl text-lg text-muted-foreground"> |
| 362 | + Start your Team plan trial. No credit card required. |
| 363 | + </p> |
| 364 | + <div className="flex flex-col justify-center space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0"> |
| 365 | + <Button |
| 366 | + size="lg" |
| 367 | + className="bg-foreground text-background hover:bg-foreground/90 transition-all duration-300" |
| 368 | + asChild> |
| 369 | + <a |
| 370 | + href={EXTERNAL_LINKS.CLOUD_APP_TEAM_TRIAL} |
| 371 | + target="_blank" |
| 372 | + rel="noopener noreferrer" |
| 373 | + className="flex items-center justify-center"> |
| 374 | + Start free trial |
| 375 | + <ArrowRight className="ml-2 h-4 w-4" /> |
| 376 | + </a> |
| 377 | + </Button> |
| 378 | + </div> |
| 379 | + </div> |
| 380 | + </div> |
| 381 | + </section> |
| 382 | + </> |
| 383 | + ) |
| 384 | +} |
0 commit comments