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
12 changes: 7 additions & 5 deletions frontend/src/components/bounty/BountyCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ 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">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 mt-3">
<span className="font-mono text-lg font-semibold text-emerald">
{formatCurrency(bounty.reward_amount, bounty.reward_token)}
</span>
Expand All @@ -120,10 +120,12 @@ export function BountyCard({ bounty }: BountyCardProps) {
</div>

{/* Status badge */}
<span className={`absolute bottom-4 right-5 text-xs font-medium inline-flex items-center gap-1 ${statusColor}`}>
<span className={`w-1.5 h-1.5 rounded-full ${dotColor}`} />
{statusLabel}
</span>
<div className="mt-2 flex justify-end">
<span className={`text-xs font-medium inline-flex items-center gap-1 ${statusColor}`}>
<span className={`w-1.5 h-1.5 rounded-full ${dotColor}`} />
{statusLabel}
</span>
</div>
</motion.div>
);
}
10 changes: 5 additions & 5 deletions frontend/src/components/bounty/BountyDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ 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-4 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
Expand All @@ -36,16 +36,16 @@ export function BountyDetail({ bounty }: BountyDetailProps) {
<div className="lg:col-span-2 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="flex items-center gap-2 mb-3 text-xs font-mono text-text-muted">
<div className="flex items-start gap-3 sm:gap-4 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 flex-wrap">
{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>
{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-lg sm:text-2xl font-semibold text-text-primary">{bounty.title}</h1>
</div>
<button
onClick={copyLink}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/bounty/BountyGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function BountyGrid() {
<div className="max-w-7xl mx-auto px-4">
{/* Header row */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8">
<h2 className="font-sans text-2xl font-semibold text-text-primary">Open Bounties</h2>
<h2 className="font-sans text-xl sm:text-2xl font-semibold text-text-primary">Open Bounties</h2>
<div className="flex items-center gap-2">
<Link
to="/bounties/create"
Expand Down
28 changes: 14 additions & 14 deletions frontend/src/components/home/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function HeroSection() {
};

return (
<section className="relative min-h-[90vh] flex flex-col items-center justify-center px-4 pt-24 pb-16 overflow-hidden">
<section className="relative min-h-[80vh] sm:min-h-[90vh] flex flex-col items-center justify-center px-4 pt-20 sm:pt-24 pb-12 sm:pb-16 overflow-hidden">
{/* Background layers */}
<div className="absolute inset-0 bg-grid-forge bg-grid-forge pointer-events-none" style={{ backgroundSize: '40px 40px' }} />
<div className="absolute inset-0 bg-gradient-hero pointer-events-none" />
Expand All @@ -98,23 +98,23 @@ 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-md sm:max-w-xl 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">
<div className="flex items-center gap-2 px-3 sm:px-4 py-2 sm:py-2.5 bg-forge-800 border-b border-border">
<div className="flex gap-1.5">
<span className="w-3 h-3 rounded-full bg-status-error/80" />
<span className="w-3 h-3 rounded-full bg-status-warning/80" />
<span className="w-3 h-3 rounded-full bg-status-success/80" />
</div>
<span className="font-mono text-xs text-text-muted ml-2">solfoundry — terminal</span>
<span className="font-mono text-[10px] sm:text-xs text-text-muted ml-2">solfoundry — terminal</span>
</div>

{/* Terminal body */}
<div className="p-5 font-mono text-sm leading-relaxed">
<div className="p-3 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">
<span className="text-text-secondary overflow-hidden whitespace-nowrap inline-block animate-typewriter-sm sm:animate-typewriter text-[11px] sm:text-sm">
forge bounty --reward 100 --lang typescript --tier 2
</span>
{typewriterDone && (
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-8 sm:mt-10"
>
THE AI-POWERED BOUNTY{' '}
<span className="text-emerald">FORGE</span>
Expand All @@ -164,7 +164,7 @@ export function HeroSection() {
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.45, duration: 0.5 }}
className="font-sans text-lg text-text-secondary text-center mt-4 max-w-lg"
className="font-sans text-base sm:text-lg text-text-secondary text-center mt-3 sm:mt-4 max-w-lg"
>
Fund bounties. Ship code. Earn rewards.
</motion.p>
Expand All @@ -174,12 +174,12 @@ export function HeroSection() {
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.6, duration: 0.5 }}
className="flex flex-wrap items-center justify-center gap-4 mt-8"
className="flex flex-wrap items-center justify-center gap-3 sm:gap-4 mt-6 sm:mt-8"
>
<motion.div variants={buttonHover} initial="rest" whileHover="hover" whileTap="tap">
<Link
to="/bounties"
className="px-6 py-3 rounded-lg bg-emerald text-text-inverse font-semibold text-sm hover:bg-emerald-light transition-colors duration-200 shadow-lg shadow-emerald/20 inline-block"
className="px-5 sm:px-6 py-2.5 sm:py-3 rounded-lg bg-emerald text-text-inverse font-semibold text-sm hover:bg-emerald-light transition-colors duration-200 shadow-lg shadow-emerald/20 inline-block"
>
Browse Bounties
</Link>
Expand All @@ -188,7 +188,7 @@ export function HeroSection() {
<motion.div variants={buttonHover} initial="rest" whileHover="hover" whileTap="tap">
<Link
to="/bounties/create"
className="px-6 py-3 rounded-lg border border-emerald text-emerald font-semibold text-sm hover:bg-emerald-bg transition-colors duration-200 inline-block"
className="px-5 sm:px-6 py-2.5 sm:py-3 rounded-lg border border-emerald text-emerald font-semibold text-sm hover:bg-emerald-bg transition-colors duration-200 inline-block"
>
Post a Bounty
</Link>
Expand All @@ -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-col sm:flex-row items-center justify-center gap-3 sm:gap-6 mt-6 sm:mt-8 font-mono 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
6 changes: 3 additions & 3 deletions frontend/src/components/how-it-works/FlowTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ export function FlowTabs() {
return (
<div>
{/* Tab switcher */}
<div className="flex items-center gap-1 p-1 rounded-xl bg-forge-800 mx-auto w-fit mb-12">
<div className="flex items-center gap-1 p-1 rounded-xl bg-forge-800 mx-auto w-fit mb-12 max-w-full px-2">
<button
onClick={() => setActiveTab('usdc')}
className={`px-5 py-2.5 rounded-lg text-sm font-semibold transition-all duration-200 ${
className={`px-3 sm:px-5 py-2 sm:py-2.5 rounded-lg text-xs sm:text-sm font-semibold transition-all duration-200 ${
activeTab === 'usdc'
? 'bg-emerald text-text-inverse'
: 'text-text-muted hover:text-text-secondary'
Expand All @@ -218,7 +218,7 @@ export function FlowTabs() {
</button>
<button
onClick={() => setActiveTab('fndry')}
className={`px-5 py-2.5 rounded-lg text-sm font-semibold transition-all duration-200 ${
className={`px-3 sm:px-5 py-2 sm:py-2.5 rounded-lg text-xs sm:text-sm font-semibold transition-all duration-200 ${
activeTab === 'fndry'
? 'bg-magenta text-text-inverse'
: 'text-text-muted hover:text-text-secondary'
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/layout/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function Footer() {
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-footer opacity-50" />

<div className="max-w-7xl mx-auto px-4 py-12">
<div className="grid grid-cols-1 md:grid-cols-4 gap-10">
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-8 sm:gap-10">
{/* Col 1: Brand */}
<div>
<div className="flex items-center gap-2 mb-3">
Expand Down Expand Up @@ -92,7 +92,7 @@ export function Footer() {
<div>
<h4 className="font-sans text-sm font-semibold text-text-primary mb-4">$FNDRY Token</h4>
<p className="text-sm text-text-muted mb-3">Contract Address:</p>
<div className="font-mono text-xs text-text-muted bg-forge-800 rounded px-3 py-2 inline-flex items-center gap-2 w-full">
<div className="font-mono text-xs text-text-muted bg-forge-800 rounded px-3 py-2 flex items-center gap-2 min-w-0 w-full">
<span className="truncate">{FNDRY_CA.slice(0, 8)}...{FNDRY_CA.slice(-4)}</span>
<button
onClick={copyCA}
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/layout/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ export function Navbar() {

<div className="max-w-7xl mx-auto h-full px-4 flex items-center justify-between">
{/* Left: Logo + Nav */}
<div className="flex items-center gap-8">
<Link to="/" className="flex items-center gap-2.5 group">
<div className="flex items-center gap-6 lg:gap-8">
<Link to="/" className="flex items-center gap-2 group">
<img
src="/logo-icon.png"
alt="SolFoundry"
className="w-7 h-7 group-hover:drop-shadow-[0_0_8px_rgba(0,230,118,0.4)] transition-all duration-200"
className="w-6 h-6 sm:w-7 sm:h-7 group-hover:drop-shadow-[0_0_8px_rgba(0,230,118,0.4)] transition-all duration-200"
/>
<span className="font-display text-lg font-semibold text-text-primary tracking-wide">
<span className="font-display text-base sm:text-lg font-semibold text-text-primary tracking-wide">
SolFoundry
</span>
</Link>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/leaderboard/LeaderboardTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function LeaderboardTable({ entries }: LeaderboardTableProps) {
variants={fadeIn}
initial="initial"
animate="animate"
className="max-w-4xl mx-auto mt-6 rounded-xl border border-border bg-forge-900 overflow-hidden"
className="max-w-4xl mx-auto mt-6 rounded-xl border border-border bg-forge-900 overflow-x-auto"
>
{/* Header */}
<div className="flex items-center px-4 py-3 border-b border-border/50 text-xs font-semibold text-text-muted uppercase tracking-wider">
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/leaderboard/PodiumCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ function PodiumCard({ entry, rank }: { entry: LeaderboardEntry; rank: number })
: 'text-orange-500';

const avatarBorderClass = isGold ? 'border-yellow-500/50' : 'border-zinc-600';
const avatarSize = isGold ? 'w-14 h-14' : 'w-12 h-12';
const padding = isGold ? 'py-8 px-6' : 'py-6 px-6';
const avatarSize = isGold ? 'w-12 h-12 sm:w-14 sm:h-14' : 'w-10 h-10 sm:w-12 sm:h-12';
const padding = isGold ? 'py-6 px-4 sm:py-8 sm:px-6' : 'py-5 px-4 sm:py-6 sm:px-6';

return (
<motion.div
variants={staggerItem}
className={`relative flex flex-col items-center rounded-xl border bg-forge-900 ${borderClass} ${padding} min-w-[140px]`}
className={`relative flex flex-col items-center rounded-xl border bg-forge-900 ${borderClass} ${padding} min-w-[110px] sm:min-w-[140px]`}
>
{/* Crown for #1 */}
{isGold && (
Expand Down Expand Up @@ -84,7 +84,7 @@ export function PodiumCards({ entries }: PodiumCardsProps) {
variants={staggerContainer}
initial="initial"
animate="animate"
className="flex items-end justify-center gap-4 md:gap-6 mb-12"
className="flex items-end justify-center gap-2 sm:gap-4 md:gap-6 mb-12 overflow-x-auto px-2 py-2"
>
{ordered.map((entry, i) => (
<PodiumCard key={entry.username} entry={entry} rank={ranks[i]} />
Expand Down
69 changes: 69 additions & 0 deletions frontend/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,72 @@ input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}

/* ============================================================================
Mobile Responsive — 375px / 768px breakpoints
============================================================================ */

/* Prevent horizontal overflow globally */
html, body {
overflow-x: hidden;
max-width: 100vw;
}

/* Ensure all containers respect viewport */
*, *::before, *::after {
box-sizing: border-box;
}

/* Mobile-safe padding for main content */
@media (max-width: 375px) {
.max-w-7xl {
padding-left: 16px;
padding-right: 16px;
}
}

/* Hero terminal — smaller typewriter on mobile */
@media (max-width: 639px) {
.animate-typewriter-sm {
animation: typewriter-sm 2.5s steps(38) 0.5s forwards;
width: 0;
}
@keyframes typewriter-sm {
from { width: 0; }
to { width: 100%; }
}
}

/* Footer token address — prevent overflow on small screens */
@media (max-width: 375px) {
.font-mono.text-xs {
font-size: 10px;
}
}

/* Nav mobile menu — close on body scroll lock */
body.menu-open {
overflow: hidden;
}

/* Ensure grid layouts don't break on narrow screens */
@media (max-width: 375px) {
.grid-cols-1 {
grid-template-columns: 1fr;
}
}

/* Leaderboard podium — prevent overflow on very small screens */
@media (max-width: 420px) {
.flex.items-end.justify-center {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
}

/* General text truncation safety for narrow viewports */
@media (max-width: 375px) {
h1 {
font-size: 1.375rem;
}
}
2 changes: 1 addition & 1 deletion frontend/src/pages/HowItWorksPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function HowItWorksPage() {
<PageLayout>
<motion.div variants={fadeIn} initial="initial" animate="animate" className="max-w-5xl mx-auto px-4 py-12">
<div className="text-center mb-12">
<h1 className="font-display text-4xl font-bold text-text-primary mb-3">How It Works</h1>
<h1 className="font-display text-3xl sm:text-4xl font-bold text-text-primary mb-3">How It Works</h1>
<p className="text-text-secondary text-lg">Two paths to earning on SolFoundry</p>
</div>
<FlowTabs />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/LeaderboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function LeaderboardPage() {
<PageLayout>
<motion.div variants={fadeIn} initial="initial" animate="animate" className="max-w-5xl mx-auto px-4 py-12">
<div className="text-center mb-10">
<h1 className="font-display text-4xl font-bold text-text-primary mb-3">Leaderboard</h1>
<h1 className="font-display text-3xl sm:text-4xl font-bold text-text-primary mb-3">Leaderboard</h1>
<p className="text-text-secondary">Top contributors ranked by bounties completed</p>
</div>

Expand Down
Loading