Skip to content
Open
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
16 changes: 8 additions & 8 deletions frontend/src/components/bounty/BountyCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ export function BountyCard({ bounty }: BountyCardProps) {
initial="rest"
whileHover="hover"
onClick={() => navigate(`/bounties/${bounty.id}`)}
className="relative rounded-xl border border-border bg-forge-900 p-5 cursor-pointer transition-colors duration-200 overflow-hidden group"
className="relative rounded-xl border border-border bg-forge-900 p-4 sm:p-5 cursor-pointer transition-colors duration-200 overflow-hidden group"
>
{/* Row 1: Repo + Tier */}
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2 min-w-0">
<div className="flex items-center justify-between text-sm gap-2">
<div className="flex items-center gap-2 min-w-0 flex-1">
{bounty.org_avatar_url && (
<img src={bounty.org_avatar_url} className="w-5 h-5 rounded-full flex-shrink-0" alt="" />
)}
Expand All @@ -78,7 +78,7 @@ export function BountyCard({ bounty }: BountyCardProps) {
</div>

{/* Row 2: Title */}
<h3 className="mt-3 font-sans text-base font-semibold text-text-primary leading-snug line-clamp-2">
<h3 className="mt-3 font-sans text-sm sm:text-base font-semibold text-text-primary leading-snug line-clamp-2">
{bounty.title}
</h3>

Expand All @@ -101,17 +101,17 @@ export function BountyCard({ bounty }: BountyCardProps) {
<div className="mt-4 border-t border-border/50" />

{/* Row 4: Reward + Meta */}
<div className="flex items-center justify-between mt-3">
<span className="font-mono text-lg font-semibold text-emerald">
<div className="flex items-center justify-between mt-3 gap-2">
<span className="font-mono text-base sm:text-lg font-semibold text-emerald">
{formatCurrency(bounty.reward_amount, bounty.reward_token)}
</span>
<div className="flex items-center gap-3 text-xs text-text-muted">
<div className="flex items-center gap-2 sm:gap-3 text-xs text-text-muted">
<span className="inline-flex items-center gap-1">
<GitPullRequest className="w-3.5 h-3.5" />
{bounty.submission_count} PRs
</span>
{bounty.deadline && (
<span className="inline-flex items-center gap-1">
<span className="hidden sm:inline-flex items-center gap-1">
<Clock className="w-3.5 h-3.5" />
{timeLeft(bounty.deadline)}
</span>
Expand Down
32 changes: 16 additions & 16 deletions frontend/src/components/bounty/BountyDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,31 @@ export function BountyDetail({ bounty }: BountyDetailProps) {
};

return (
<motion.div variants={fadeIn} initial="initial" animate="animate" className="max-w-4xl mx-auto px-4 py-8">
<motion.div variants={fadeIn} initial="initial" animate="animate" className="max-w-4xl mx-auto px-4 py-6 sm:py-8">
{/* Back link */}
<Link to="/" className="inline-flex items-center gap-2 text-sm text-text-muted hover:text-text-secondary transition-colors mb-6">
<ArrowLeft className="w-4 h-4" /> Back to Bounties
</Link>

<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6">
{/* Main content */}
<div className="lg:col-span-2 space-y-6">
<div className="lg:col-span-2 space-y-4 sm:space-y-6">
{/* Title + meta */}
<div className="rounded-xl border border-border bg-forge-900 p-6">
<div className="flex items-start justify-between gap-4 mb-4">
<div className="flex-1">
<div className="rounded-xl border border-border bg-forge-900 p-4 sm:p-6">
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-4">
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-3 text-xs font-mono text-text-muted">
{bounty.org_avatar_url && (
<img src={bounty.org_avatar_url} alt="" className="w-4 h-4 rounded-full" />
)}
<span>{bounty.org_name}/{bounty.repo_name}</span>
<span className="truncate">{bounty.org_name}/{bounty.repo_name}</span>
{bounty.issue_number && <span>#{bounty.issue_number}</span>}
</div>
<h1 className="font-sans text-2xl font-semibold text-text-primary">{bounty.title}</h1>
<h1 className="font-sans text-xl sm:text-2xl font-semibold text-text-primary">{bounty.title}</h1>
</div>
<button
onClick={copyLink}
className="flex-shrink-0 p-2 rounded-lg bg-forge-800 border border-border hover:border-border-hover text-text-muted hover:text-text-primary transition-colors duration-150"
className="flex-shrink-0 self-start p-2 rounded-lg bg-forge-800 border border-border hover:border-border-hover text-text-muted hover:text-text-primary transition-colors duration-150"
>
{copied ? <Check className="w-4 h-4 text-emerald" /> : <Copy className="w-4 h-4" />}
</button>
Expand Down Expand Up @@ -84,8 +84,8 @@ export function BountyDetail({ bounty }: BountyDetailProps) {
</div>

{/* Description / requirements */}
<div className="rounded-xl border border-border bg-forge-900 p-6">
<h2 className="font-sans text-lg font-semibold text-text-primary mb-4">Requirements</h2>
<div className="rounded-xl border border-border bg-forge-900 p-4 sm:p-6">
<h2 className="font-sans text-base sm:text-lg font-semibold text-text-primary mb-4">Requirements</h2>
<p className="text-sm text-text-secondary leading-relaxed">
Submit a working solution that addresses the bounty requirements above.
All submissions are reviewed by our AI pipeline (3 LLMs, pass threshold 7.0/10).
Expand All @@ -94,8 +94,8 @@ export function BountyDetail({ bounty }: BountyDetailProps) {

{/* Submission form */}
{bounty.status === 'open' || bounty.status === 'funded' ? (
<div className="rounded-xl border border-border bg-forge-900 p-6">
<h2 className="font-sans text-lg font-semibold text-text-primary mb-4">Submit Your Solution</h2>
<div className="rounded-xl border border-border bg-forge-900 p-4 sm:p-6">
<h2 className="font-sans text-base sm:text-lg font-semibold text-text-primary mb-4">Submit Your Solution</h2>
{isAuthenticated ? (
<SubmissionForm bounty={bounty} />
) : (
Expand All @@ -116,15 +116,15 @@ export function BountyDetail({ bounty }: BountyDetailProps) {
{/* Sidebar */}
<div className="space-y-4">
{/* Reward card */}
<div className="rounded-xl border border-emerald-border bg-emerald-bg/50 p-5">
<div className="rounded-xl border border-emerald-border bg-emerald-bg/50 p-4 sm:p-5">
<p className="text-xs text-text-muted font-mono mb-1">Reward</p>
<p className="font-mono text-3xl font-bold text-emerald">
<p className="font-mono text-2xl sm:text-3xl font-bold text-emerald">
{formatCurrency(bounty.reward_amount, bounty.reward_token)}
</p>
</div>

{/* Info card */}
<div className="rounded-xl border border-border bg-forge-900 p-5 space-y-4">
<div className="rounded-xl border border-border bg-forge-900 p-4 sm:p-5 space-y-3 sm:space-y-4">
<div className="flex items-center justify-between text-sm">
<span className="text-text-muted">Status</span>
<span className={`font-medium ${bounty.status === 'open' ? 'text-emerald' : 'text-magenta'}`}>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/bounty/BountyGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ export function BountyGrid() {

{/* Loading state */}
{isLoading && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-5">
{Array.from({ length: 6 }).map((_, i) => (
<div
key={i}
className="h-52 rounded-xl border border-border bg-forge-900 overflow-hidden"
className="h-48 sm:h-52 rounded-xl border border-border bg-forge-900 overflow-hidden"
>
<div className="h-full bg-gradient-to-r from-forge-900 via-forge-800 to-forge-900 bg-[length:200%_100%] animate-shimmer" />
</div>
Expand Down Expand Up @@ -109,7 +109,7 @@ export function BountyGrid() {
initial="initial"
whileInView="animate"
viewport={{ once: true, margin: '-50px' }}
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5"
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-5"
>
{allBounties.map((bounty) => (
<motion.div key={bounty.id} variants={staggerItem}>
Expand Down
14 changes: 7 additions & 7 deletions frontend/src/components/home/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function HeroSection() {
variants={fadeIn}
initial="initial"
animate="animate"
className="w-full max-w-xl rounded-xl border border-border bg-forge-900/90 backdrop-blur-sm overflow-hidden shadow-2xl shadow-black/50"
className="w-full max-w-xl mx-4 sm:mx-auto rounded-xl border border-border bg-forge-900/90 backdrop-blur-sm overflow-hidden shadow-2xl shadow-black/50"
>
{/* Title bar */}
<div className="flex items-center gap-2 px-4 py-2.5 bg-forge-800 border-b border-border">
Expand All @@ -111,14 +111,14 @@ export function HeroSection() {
</div>

{/* Terminal body */}
<div className="p-5 font-mono text-sm leading-relaxed">
<div className="p-4 sm:p-5 font-mono text-xs sm:text-sm leading-relaxed">
<div className="overflow-hidden">
<span className="text-emerald">$ </span>
<span className="text-text-secondary overflow-hidden whitespace-nowrap inline-block animate-typewriter">
forge bounty --reward 100 --lang typescript --tier 2
</span>
{typewriterDone && (
<span className="inline-block w-2 h-5 bg-emerald animate-blink ml-0.5 align-middle" />
<span className="inline-block w-2 h-4 sm:h-5 bg-emerald animate-blink ml-0.5 align-middle" />
)}
</div>

Expand Down Expand Up @@ -154,7 +154,7 @@ export function HeroSection() {
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.5 }}
className="font-display text-4xl md:text-5xl font-bold text-text-primary tracking-wider text-center mt-10"
className="font-display text-3xl sm:text-4xl md:text-5xl font-bold text-text-primary tracking-wider text-center mt-10 px-4"
>
THE AI-POWERED BOUNTY{' '}
<span className="text-emerald">FORGE</span>
Expand Down Expand Up @@ -211,22 +211,22 @@ export function HeroSection() {
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.8, duration: 0.5 }}
className="flex items-center justify-center gap-6 mt-8 font-mono text-sm text-text-muted"
className="flex flex-wrap items-center justify-center gap-4 sm:gap-6 mt-8 px-4 font-mono text-xs sm:text-sm text-text-muted"
>
<span>
<span className="text-text-primary font-semibold">
<CountUp target={stats?.open_bounties ?? 142} />
</span>
{' '}open bounties
</span>
<span className="text-text-muted">·</span>
<span className="hidden sm:inline text-text-muted">·</span>
<span>
<span className="text-text-primary font-semibold">
$<CountUp target={stats?.total_paid_usdc ?? 24500} />
</span>
{' '}paid
</span>
<span className="text-text-muted">·</span>
<span className="hidden sm:inline text-text-muted">·</span>
<span>
<span className="text-text-primary font-semibold">
<CountUp target={stats?.total_contributors ?? 89} />
Expand Down
48 changes: 25 additions & 23 deletions frontend/src/components/profile/ProfileDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ function MyBountiesTab({ bounties, loading }: { bounties: Bounty[]; loading: boo
<motion.div
key={b.id}
variants={staggerItem}
className="flex items-center gap-4 px-4 py-3 rounded-lg bg-forge-900 border border-border hover:bg-forge-850 transition-colors cursor-pointer"
className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4 px-3 sm:px-4 py-3 rounded-lg bg-forge-900 border border-border hover:bg-forge-850 transition-colors cursor-pointer"
onClick={() => window.location.href = `/bounties/${b.id}`}
>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-text-primary truncate">{b.title}</p>
<p className="text-xs text-text-muted mt-0.5">{timeAgo(b.created_at)}</p>
</div>
<span className="font-mono text-sm font-semibold text-emerald">{formatCurrency(b.reward_amount, b.reward_token)}</span>
<BountyStatusBadge status={b.status} />
<span className="text-xs text-text-muted inline-flex items-center gap-1">
<GitPullRequest className="w-3.5 h-3.5" /> {b.submission_count}
</span>
<div className="flex items-center gap-2 sm:gap-3">
<span className="font-mono text-sm font-semibold text-emerald">{formatCurrency(b.reward_amount, b.reward_token)}</span>
<BountyStatusBadge status={b.status} />
<span className="text-xs text-text-muted inline-flex items-center gap-1">
<GitPullRequest className="w-3.5 h-3.5" /> {b.submission_count}
</span>
</div>
</motion.div>
))}
</motion.div>
Expand All @@ -85,24 +87,24 @@ function SubmissionsTab() {
function EarningsTab() {
const totalEarned = MONTHLY_MOCK.reduce((s, m) => s + m.usdc, 0);
return (
<div className="space-y-6">
<div className="grid grid-cols-3 gap-4">
<div className="space-y-4 sm:space-y-6">
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 sm:gap-4">
{[
{ label: 'Total Earned', value: `$${totalEarned}`, color: 'text-emerald' },
{ label: 'This Month', value: '$800', color: 'text-emerald' },
{ label: 'Pending', value: '$0', color: 'text-text-muted' },
].map((s) => (
<div key={s.label} className="rounded-xl border border-border bg-forge-900 p-4">
<div key={s.label} className="rounded-xl border border-border bg-forge-900 p-3 sm:p-4">
<p className="text-xs text-text-muted mb-1">{s.label}</p>
<p className={`font-mono text-xl font-bold ${s.color}`}>{s.value}</p>
<p className={`font-mono text-lg sm:text-xl font-bold ${s.color}`}>{s.value}</p>
</div>
))}
</div>
<div className="rounded-xl border border-border bg-forge-900 p-4">
<p className="text-sm font-medium text-text-secondary mb-4">Monthly Earnings</p>
<ResponsiveContainer width="100%" height={180}>
<div className="rounded-xl border border-border bg-forge-900 p-3 sm:p-4">
<p className="text-sm font-medium text-text-secondary mb-3 sm:mb-4">Monthly Earnings</p>
<ResponsiveContainer width="100%" height={150} className="sm:!h-[180px]">
<BarChart data={MONTHLY_MOCK} margin={{ top: 4, right: 4, bottom: 0, left: 0 }}>
<XAxis dataKey="month" axisLine={false} tickLine={false} tick={{ fill: '#5C5C78', fontSize: 12, fontFamily: 'JetBrains Mono' }} />
<XAxis dataKey="month" axisLine={false} tickLine={false} tick={{ fill: '#5C5C78', fontSize: 11, fontFamily: 'JetBrains Mono' }} />
<YAxis hide />
<Tooltip
contentStyle={{ backgroundColor: '#16161F', border: '1px solid #1E1E2E', borderRadius: 8, fontFamily: 'JetBrains Mono', fontSize: 12 }}
Expand Down Expand Up @@ -162,32 +164,32 @@ export function ProfileDashboard() {
const myBounties = bountiesData?.items.filter((b) => b.creator_id === user.id) ?? [];

return (
<motion.div variants={fadeIn} initial="initial" animate="animate" className="max-w-4xl mx-auto px-4 py-8">
<motion.div variants={fadeIn} initial="initial" animate="animate" className="max-w-4xl mx-auto px-4 py-6 sm:py-8">
{/* Header */}
<div className="rounded-xl border border-border bg-forge-900 p-6 mb-6">
<div className="flex items-start gap-5">
<div className="rounded-xl border border-border bg-forge-900 p-4 sm:p-6 mb-4 sm:mb-6">
<div className="flex flex-col sm:flex-row sm:items-start gap-4 sm:gap-5">
{user.avatar_url ? (
<img src={user.avatar_url} className="w-16 h-16 rounded-full border-2 border-border" alt={user.username} />
<img src={user.avatar_url} className="w-14 h-14 sm:w-16 sm:h-16 rounded-full border-2 border-border" alt={user.username} />
) : (
<div className="w-16 h-16 rounded-full bg-forge-700 border-2 border-border flex items-center justify-center">
<span className="font-display text-2xl text-text-muted">{user.username[0]?.toUpperCase()}</span>
<div className="w-14 h-14 sm:w-16 sm:h-16 rounded-full bg-forge-700 border-2 border-border flex items-center justify-center">
<span className="font-display text-xl sm:text-2xl text-text-muted">{user.username[0]?.toUpperCase()}</span>
</div>
)}
<div className="flex-1">
<h1 className="font-sans text-2xl font-semibold text-text-primary">{user.username}</h1>
<h1 className="font-sans text-xl sm:text-2xl font-semibold text-text-primary">{user.username}</h1>
<p className="mt-1 font-mono text-sm text-text-muted">
Joined {joinDate} · {myBounties.length} bounties created
</p>
</div>
</div>

{/* Tab switcher */}
<div className="flex items-center gap-1 p-1 rounded-lg bg-forge-800 mt-6 w-fit">
<div className="flex items-center gap-1 p-1 rounded-lg bg-forge-800 mt-4 sm:mt-6 overflow-x-auto">
{TABS.map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`px-3 py-1.5 rounded-md text-sm font-medium transition-colors duration-150 ${
className={`px-2.5 sm:px-3 py-1.5 rounded-md text-xs sm:text-sm font-medium transition-colors duration-150 whitespace-nowrap ${
activeTab === tab
? 'bg-forge-700 text-text-primary'
: 'text-text-muted hover:text-text-secondary'
Expand Down