Skip to content
Draft
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
8 changes: 8 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
50% { opacity: 0.8; }
}

/* Hero grid background */
.hero-grid {
background-image:
linear-gradient(rgba(240, 246, 252, 0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(240, 246, 252, 0.035) 1px, transparent 1px);
background-size: 44px 44px;
}

:root {
--background: oklch(0.95 0 0);
--foreground: oklch(0.15 0 0);
Expand Down
143 changes: 79 additions & 64 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,26 @@ export default async function HomePage({
</header>

<main>
<section className="border-b border-[#30363D] bg-[linear-gradient(180deg,#0B0F14_0%,#101722_100%)]">
<div className="mx-auto max-w-7xl px-4 pb-16 pt-10 sm:px-6 lg:pb-20 lg:pt-14">
{/* Hero — full viewport, grid background */}
<section className="hero-grid relative flex min-h-[calc(100vh-57px)] items-center border-b border-[#30363D] bg-[#0B0F14]">
{/* radial fade to hide grid edges */}
<div
aria-hidden
className="pointer-events-none absolute inset-0"
style={{
background:
'radial-gradient(ellipse 80% 60% at 50% 50%, transparent 40%, #0B0F14 100%)',
}}
/>
<div className="relative z-10 mx-auto w-full max-w-4xl px-4 py-24 sm:px-6">
<HeroChat />
</div>
</section>

<div className="mt-14 grid gap-12 lg:grid-cols-[0.92fr_1.08fr] lg:items-center">
{/* Scan demo section */}
<section id="scan" className="border-b border-[#30363D] bg-[linear-gradient(180deg,#0B0F14_0%,#101722_100%)]">
<div className="mx-auto max-w-7xl px-4 pb-16 pt-14 sm:px-6 lg:pb-20">
<div className="grid gap-12 lg:grid-cols-[0.92fr_1.08fr] lg:items-center">
<div>
<div className="mb-6 inline-flex items-center gap-2 rounded-full border border-[#F59E0B]/30 bg-[#F59E0B]/10 px-3 py-1.5 text-xs font-mono font-semibold text-[#FBBF24]">
<Zap className="h-3.5 w-3.5" />
Expand Down Expand Up @@ -221,78 +236,78 @@ export default async function HomePage({
</div>
</div>

<div id="scan" className="relative">
<div className="rounded-2xl border border-[#30363D] bg-[#111827] shadow-2xl shadow-black/50">
<div className="flex items-center gap-2 border-b border-[#30363D] bg-[#0D1117] px-4 py-3">
<span className="h-3 w-3 rounded-full bg-[#F85149]" />
<span className="h-3 w-3 rounded-full bg-[#F59E0B]" />
<span className="h-3 w-3 rounded-full bg-[#10B981]" />
<span className="ml-3 font-mono text-xs text-[#8B949E]">RepoFuse Opportunity Scan</span>
<span className="ml-auto inline-flex items-center gap-1.5 rounded-full bg-[#10B981]/10 px-2 py-1 text-[11px] font-mono text-[#3FB950]">
<span className="h-1.5 w-1.5 rounded-full bg-[#3FB950]" />
live
</span>
</div>

<div className="p-5 sm:p-6">
<div className="mb-5 flex items-center gap-4 rounded-xl border border-[#30363D] bg-[#0B0F14] p-4">
<Image
src="/repofuse-logo-3d.jpg"
alt="RepoFuse logo"
width={64}
height={64}
className="h-14 w-14 rounded-xl object-cover"
priority
/>
<div>
<div className="font-mono text-sm font-bold text-[#F0F6FC]">DealPatrol workspace</div>
<div className="mt-1 text-xs text-[#8B949E]">Analyzing 14 repos, 43 services, 2,813 files</div>
</div>
<div className="relative">
<div className="rounded-2xl border border-[#30363D] bg-[#111827] shadow-2xl shadow-black/50">
<div className="flex items-center gap-2 border-b border-[#30363D] bg-[#0D1117] px-4 py-3">
<span className="h-3 w-3 rounded-full bg-[#F85149]" />
<span className="h-3 w-3 rounded-full bg-[#F59E0B]" />
<span className="h-3 w-3 rounded-full bg-[#10B981]" />
<span className="ml-3 font-mono text-xs text-[#8B949E]">RepoFuse Opportunity Scan</span>
<span className="ml-auto inline-flex items-center gap-1.5 rounded-full bg-[#10B981]/10 px-2 py-1 text-[11px] font-mono text-[#3FB950]">
<span className="h-1.5 w-1.5 rounded-full bg-[#3FB950]" />
live
</span>
</div>

<div className="mb-5 rounded-xl border border-[#30363D] bg-[#0B0F14] p-4 font-mono text-sm">
<div className="flex gap-3 text-[#8B949E]">
<Terminal className="mt-0.5 h-4 w-4 text-[#06B6D4]" />
<span className="text-[#F0F6FC]">repofuse scan --find-subscription-products</span>
<div className="p-5 sm:p-6">
<div className="mb-5 flex items-center gap-4 rounded-xl border border-[#30363D] bg-[#0B0F14] p-4">
<Image
src="/repofuse-logo-3d.jpg"
alt="RepoFuse logo"
width={64}
height={64}
className="h-14 w-14 rounded-xl object-cover"
priority
/>
<div>
<div className="font-mono text-sm font-bold text-[#F0F6FC]">DealPatrol workspace</div>
<div className="mt-1 text-xs text-[#8B949E]">Analyzing 14 repos, 43 services, 2,813 files</div>
</div>
</div>
<div className="mt-3 space-y-2 pl-7 text-xs text-[#8B949E]">
<div>Connected with read-only access</div>
<div className="text-[#06B6D4]">Mapped reusable billing, auth, and analytics logic</div>
<div className="text-[#F59E0B]">Detected 3 monetizable product wedges</div>

<div className="mb-5 rounded-xl border border-[#30363D] bg-[#0B0F14] p-4 font-mono text-sm">
<div className="flex gap-3 text-[#8B949E]">
<Terminal className="mt-0.5 h-4 w-4 text-[#06B6D4]" />
<span className="text-[#F0F6FC]">repofuse scan --find-subscription-products</span>
</div>
<div className="mt-3 space-y-2 pl-7 text-xs text-[#8B949E]">
<div>Connected with read-only access</div>
<div className="text-[#06B6D4]">Mapped reusable billing, auth, and analytics logic</div>
<div className="text-[#F59E0B]">Detected 3 monetizable product wedges</div>
</div>
</div>
</div>

<div className="space-y-3">
{scanFindings.map((finding) => (
<div key={finding.title} className="rounded-xl border border-[#30363D] bg-[#161B22] p-4">
<div className="flex items-start justify-between gap-4">
<div>
<h3 className="font-mono text-sm font-bold text-[#F0F6FC]">{finding.title}</h3>
<p className="mt-1 text-xs text-[#8B949E]">Found in {finding.source}</p>
</div>
<span
className="rounded-lg px-2.5 py-1 font-mono text-xs font-black"
style={{ backgroundColor: `${finding.color}1A`, color: finding.color }}
>
{finding.score}%
</span>
</div>
<div className="mt-3 flex items-center justify-between gap-3">
<span className="text-xs font-semibold text-[#D0D7DE]">{finding.revenue}</span>
<span className="h-2 flex-1 overflow-hidden rounded-full bg-[#30363D]">
<div className="space-y-3">
{scanFindings.map((finding) => (
<div key={finding.title} className="rounded-xl border border-[#30363D] bg-[#161B22] p-4">
<div className="flex items-start justify-between gap-4">
<div>
<h3 className="font-mono text-sm font-bold text-[#F0F6FC]">{finding.title}</h3>
<p className="mt-1 text-xs text-[#8B949E]">Found in {finding.source}</p>
</div>
<span
className="block h-full rounded-full"
style={{ width: `${finding.score}%`, backgroundColor: finding.color }}
/>
</span>
className="rounded-lg px-2.5 py-1 font-mono text-xs font-black"
style={{ backgroundColor: `${finding.color}1A`, color: finding.color }}
>
{finding.score}%
</span>
</div>
<div className="mt-3 flex items-center justify-between gap-3">
<span className="text-xs font-semibold text-[#D0D7DE]">{finding.revenue}</span>
<span className="h-2 flex-1 overflow-hidden rounded-full bg-[#30363D]">
<span
className="block h-full rounded-full"
style={{ width: `${finding.score}%`, backgroundColor: finding.color }}
/>
</span>
</div>
</div>
</div>
))}
))}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>

Expand Down
138 changes: 93 additions & 45 deletions components/hero-chat.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import { useState } from 'react'
import { ArrowRight, Github, Loader2, MessageSquareText, ShieldCheck, Sparkles } from 'lucide-react'
import { ArrowRight, Code2, Globe, Loader2, Smartphone, Sparkles, Zap } from 'lucide-react'

type AuthResponse = {
authenticated?: boolean
Expand All @@ -14,10 +14,33 @@ function ideaParam(idea: string) {
return encodeURIComponent(idea.trim())
}

const categories = [
{ id: 'fullstack', icon: Code2, label: 'Full Stack App' },
{ id: 'mobile', icon: Smartphone, label: 'Mobile App' },
{ id: 'landing', icon: Globe, label: 'Landing Page' },
{ id: 'brainstorm', icon: Sparkles, label: 'Brainstorm' },
]

const exampleCards = [
{
title: 'Task Manager',
description: 'Build me a task manager with team collaboration, priorities, and deadline tracking',
},
{
title: 'Real Estate CRM',
description: 'Build a CRM for managing property listings, client contacts, and deal pipelines',
},
{
title: 'SaaS Dashboard',
description: 'Build a SaaS analytics dashboard with subscription billing and usage metrics',
},
]

export function HeroChat() {
const [message, setMessage] = useState('')
const [submitted, setSubmitted] = useState(false)
const [error, setError] = useState<string | null>(null)
const [activeCategory, setActiveCategory] = useState<string | null>(null)

async function handleSubmit() {
const idea = message.trim()
Expand Down Expand Up @@ -63,68 +86,93 @@ export function HeroChat() {
}

return (
<section className="mx-auto w-full max-w-4xl text-center">
<div className="mb-5 inline-flex items-center gap-2 rounded-full border border-[#F59E0B]/30 bg-[#F59E0B]/10 px-3 py-1.5 text-xs font-mono font-semibold text-[#FBBF24]">
<Sparkles className="h-3.5 w-3.5" />
AI product discovery from your repositories
<section className="mx-auto w-full max-w-3xl text-center">
{/* Badge */}
<div className="mb-7 inline-flex items-center gap-2 rounded-full border border-[#10B981]/30 bg-[#10B981]/10 px-4 py-2 text-sm font-semibold text-[#10B981]">
<Zap className="h-4 w-4" />
Start Experimenting
</div>

<h1 className="mx-auto max-w-3xl font-mono text-4xl font-black leading-[1.05] tracking-normal text-[#F0F6FC] sm:text-5xl lg:text-6xl">
What should your code become next?
{/* Headline */}
<h1 className="mx-auto font-mono text-5xl font-black leading-[1.06] tracking-tight text-[#F0F6FC] sm:text-6xl lg:text-7xl">
What will you{' '}
<span className="bg-gradient-to-r from-[#F0F6FC] via-[#67E8F9] to-[#06B6D4] bg-clip-text text-transparent">
build today?
</span>
</h1>

<p className="mx-auto mt-5 max-w-2xl text-base leading-7 text-[#AEB8C5] sm:text-lg">
Type an idea, then RepoFuse matches it against your GitHub, GitLab, or Bitbucket repos to find reusable code, launch angles, and subscription-ready opportunities.
</p>

<div className="mx-auto mt-8 max-w-3xl rounded-2xl border border-[#30363D] bg-[#111827] p-3 text-left shadow-2xl shadow-black/40">
<div className="flex items-center gap-2 border-b border-[#30363D] px-2 pb-3">
<MessageSquareText className="h-4 w-4 text-[#06B6D4]" />
<span className="font-mono text-xs font-semibold text-[#8B949E]">RepoFuse AI idea prompt</span>
<span className="ml-auto rounded-full bg-[#10B981]/10 px-2 py-1 text-[11px] font-mono text-[#3FB950]">
read-only scan
</span>
</div>
{/* Category tabs */}
<div className="mt-9 flex flex-wrap justify-center gap-2">
{categories.map(({ id, icon: Icon, label }) => (
<button
key={id}
type="button"
onClick={() => setActiveCategory(id === activeCategory ? null : id)}
className={`inline-flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium transition-all ${
activeCategory === id
? 'border-[#06B6D4] bg-[#06B6D4]/15 text-[#06B6D4]'
: 'border-[#30363D] bg-[#111827] text-[#8B949E] hover:border-[#8B949E] hover:text-[#F0F6FC]'
}`}
>
<Icon className="h-3.5 w-3.5" />
{label}
</button>
))}
</div>

<div className="flex flex-col gap-3 pt-3 sm:flex-row">
<textarea
value={message}
onChange={(event) => setMessage(event.target.value)}
onKeyDown={handleKeyDown}
placeholder="Example: I want to turn my internal billing tools into a self-serve SaaS..."
rows={3}
autoFocus
className="min-h-24 flex-1 resize-none rounded-xl border border-[#30363D] bg-[#0B0F14] px-4 py-3 text-sm leading-6 text-[#F0F6FC] outline-none transition-colors placeholder:text-[#6E7681] focus:border-[#06B6D4]"
/>
{/* Input card */}
<div className="mx-auto mt-5 overflow-hidden rounded-2xl border border-[#30363D] bg-[#111827] shadow-2xl shadow-black/60">
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Build me an app to manage bookings, payments and customer relationships..."
rows={4}
autoFocus
className="w-full resize-none bg-transparent px-5 pt-5 pb-3 text-base leading-7 text-[#F0F6FC] outline-none placeholder:text-[#6E7681]"
/>

{/* Toolbar */}
<div className="flex items-center gap-2 border-t border-[#30363D] px-4 py-3">
<div className="flex items-center gap-1.5 rounded-lg border border-[#30363D] bg-[#0B0F14] px-3 py-1.5">
<Sparkles className="h-3.5 w-3.5 text-[#F59E0B]" />
<span className="font-mono text-xs text-[#8B949E]">Claude 4.7 Opus</span>
</div>
<div className="flex items-center gap-1.5 rounded-lg border border-[#30363D] bg-[#0B0F14] px-3 py-1.5">
<Globe className="h-3.5 w-3.5 text-[#8B949E]" />
<span className="font-mono text-xs text-[#8B949E]">Public</span>
</div>
<button
type="button"
onClick={() => void handleSubmit()}
disabled={!message.trim() || submitted}
className="inline-flex min-h-14 items-center justify-center gap-2 rounded-xl bg-[#06B6D4] px-6 py-4 text-sm font-black text-[#061018] transition-all hover:bg-[#22D3EE] disabled:cursor-not-allowed disabled:opacity-50 sm:w-48"
className="ml-auto inline-flex h-9 w-9 items-center justify-center rounded-full bg-[#10B981] text-white transition-all hover:bg-[#059669] disabled:cursor-not-allowed disabled:opacity-40"
>
{submitted ? (
<>
<Loader2 className="h-4 w-4 animate-spin" />
Checking
</>
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<>
Generate
<ArrowRight className="h-4 w-4" />
</>
<ArrowRight className="h-4 w-4" />
)}
</button>
</div>

{error && <p className="px-2 pt-3 text-sm text-red-300">{error}</p>}
{error && (
<p className="border-t border-[#30363D] px-5 py-3 text-left text-sm text-red-300">{error}</p>
)}
</div>

<div className="mt-5 flex flex-wrap justify-center gap-x-5 gap-y-2 text-sm text-[#8B949E]">
{['Sign in with GitHub, GitLab, or Bitbucket', 'No credit card for the first scan', 'Source code is not stored'].map((item) => (
<span key={item} className="inline-flex items-center gap-1.5">
{item.startsWith('Sign') ? <Github className="h-4 w-4 text-[#06B6D4]" /> : <ShieldCheck className="h-4 w-4 text-[#10B981]" />}
{item}
</span>
{/* Example cards */}
<div className="mt-5 grid grid-cols-1 gap-3 sm:grid-cols-3">
{exampleCards.map(({ title, description }) => (
<button
key={title}
type="button"
onClick={() => setMessage(description)}
className="rounded-xl border border-[#30363D] bg-[#0D1117] p-4 text-left transition-all hover:border-[#8B949E] hover:bg-[#161B22]"
>
<div className="font-mono text-xs font-bold text-[#F0F6FC]">{title}</div>
<p className="mt-1.5 line-clamp-2 text-xs leading-5 text-[#8B949E]">{description}</p>
</button>
))}
</div>
</section>
Expand Down
Loading