Redesign demo page with Reddit-style voting UX and improve ELI5 section

Demo page changes:
- Reddit-style vote arrows on left (orange upvote, blue downvote)
- More realistic governance proposals (treasury, moderation, research, security, town halls)
- Prominent color-coded vote states and confirmation flow
- Cleaner card layout with progress bars

Homepage ELI5 section:
- Three distinct colored cards (orange/blue/purple) for each mechanism
- Icon badges for visual hierarchy
- Clearer explanations with emphasized takeaways

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-05 19:11:11 +00:00
parent 9fdf122145
commit eebd6a4349
2 changed files with 342 additions and 263 deletions

View File

@ -34,9 +34,9 @@ interface DemoProposal {
const initialProposals: DemoProposal[] = [ const initialProposals: DemoProposal[] = [
{ {
id: 1, id: 1,
title: "Add dark mode to the dashboard", title: "Allocate 15% of treasury to ecosystem grants program",
description: "Implement a dark theme option for better nighttime usage", description: "Fund community developers building tools and integrations for the ecosystem over the next 6 months",
score: 45, score: 72,
userVote: 0, userVote: 0,
pendingVote: 0, pendingVote: 0,
stage: "ranking", stage: "ranking",
@ -45,9 +45,9 @@ const initialProposals: DemoProposal[] = [
}, },
{ {
id: 2, id: 2,
title: "Weekly community calls", title: "Establish a community moderation council",
description: "Host weekly video calls to discuss proposals and progress", description: "Elect 7 members to handle disputes, enforce guidelines, and maintain community standards",
score: 43, score: 58,
userVote: 0, userVote: 0,
pendingVote: 0, pendingVote: 0,
stage: "ranking", stage: "ranking",
@ -56,9 +56,31 @@ const initialProposals: DemoProposal[] = [
}, },
{ {
id: 3, id: 3,
title: "Create a mobile app", title: "Partner with University research lab for governance study",
description: "Build native iOS and Android apps for on-the-go voting", description: "Collaborate with academic researchers to analyze and improve our decision-making processes",
score: 44, score: 41,
userVote: 0,
pendingVote: 0,
stage: "ranking",
yesVotes: 0,
noVotes: 0,
},
{
id: 4,
title: "Create bounty program for security audits",
description: "Reward external security researchers who identify vulnerabilities in our smart contracts",
score: 35,
userVote: 0,
pendingVote: 0,
stage: "ranking",
yesVotes: 0,
noVotes: 0,
},
{
id: 5,
title: "Host quarterly virtual town halls",
description: "Regular video conferences for community updates, Q&A sessions, and open discussion",
score: 23,
userVote: 0, userVote: 0,
pendingVote: 0, pendingVote: 0,
stage: "ranking", stage: "ranking",
@ -173,7 +195,7 @@ export default function DemoPage() {
const rankingProposals = proposals const rankingProposals = proposals
.filter((p) => p.stage === "ranking") .filter((p) => p.stage === "ranking")
.sort((a, b) => b.score - a.score); // Sort by score descending .sort((a, b) => b.score - a.score);
const votingProposals = proposals.filter((p) => p.stage === "voting"); const votingProposals = proposals.filter((p) => p.stage === "voting");
return ( return (
@ -184,25 +206,26 @@ export default function DemoPage() {
</Badge> </Badge>
<h1 className="text-4xl font-bold">Try Quadratic Proposal Ranking</h1> <h1 className="text-4xl font-bold">Try Quadratic Proposal Ranking</h1>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto"> <p className="text-xl text-muted-foreground max-w-2xl mx-auto">
Experience how rVote works without creating an account. Click the arrows Experience how rVote works without creating an account. Click the vote
to add votes and see the quadratic cost increase in real-time. arrows to rank proposalswatch how quadratic costs scale in real-time.
</p> </p>
</div> </div>
{/* Credits display */} {/* Credits display */}
<Card className="border-primary/50 bg-primary/5"> <Card className="border-2 border-orange-500/30 bg-gradient-to-r from-orange-500/10 to-amber-500/10">
<CardContent className="py-4"> <CardContent className="py-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Coins className="h-5 w-5 text-primary" /> <Coins className="h-6 w-6 text-orange-500" />
<span className="font-semibold text-lg">{credits} credits</span> <span className="font-bold text-2xl text-orange-600">{credits}</span>
<span className="text-muted-foreground">credits</span>
</div> </div>
<span className="text-sm text-muted-foreground"> <Badge variant="outline" className="border-orange-500/30 text-orange-600">
Max vote weight: {maxWeight} Max vote: ±{maxWeight}
</span> </Badge>
</div> </div>
<Button variant="outline" size="sm" onClick={resetDemo}> <Button variant="outline" size="sm" onClick={resetDemo} className="border-orange-500/30 hover:bg-orange-500/10">
<RotateCcw className="h-4 w-4 mr-2" /> <RotateCcw className="h-4 w-4 mr-2" />
Reset Demo Reset Demo
</Button> </Button>
@ -211,14 +234,14 @@ export default function DemoPage() {
</Card> </Card>
{/* Quadratic cost explainer */} {/* Quadratic cost explainer */}
<Card> <Card className="border-muted">
<CardHeader> <CardHeader className="pb-2">
<CardTitle className="text-lg flex items-center gap-2"> <CardTitle className="text-lg flex items-center gap-2">
<TrendingUp className="h-5 w-5" /> <TrendingUp className="h-5 w-5 text-orange-500" />
Quadratic Ranking Cost Quadratic Voting Cost
</CardTitle> </CardTitle>
<CardDescription> <CardDescription>
Click the arrows to add votes. Each additional vote costs more! Each additional vote costs exponentially more credits
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@ -226,174 +249,203 @@ export default function DemoPage() {
{[1, 2, 3, 4, 5].map((w) => ( {[1, 2, 3, 4, 5].map((w) => (
<div <div
key={w} key={w}
className={`p-3 rounded-lg border ${ className={`p-3 rounded-lg border-2 transition-all ${
w <= maxWeight w <= maxWeight
? "bg-primary/10 border-primary/30" ? "bg-orange-500/10 border-orange-500/40 text-orange-700"
: "bg-muted border-muted" : "bg-muted/50 border-muted text-muted-foreground"
}`} }`}
> >
<div className="font-bold text-lg">{w}</div> <div className="font-bold text-xl">{w > 0 ? "+" : ""}{w}</div>
<div className="text-muted-foreground">vote{w > 1 ? "s" : ""}</div> <div className="text-xs opacity-70">vote{w > 1 ? "s" : ""}</div>
<div className="font-mono text-xs mt-1">{w * w} credits</div> <div className="font-mono text-sm mt-1 font-semibold">{w * w}¢</div>
</div> </div>
))} ))}
</div> </div>
<p className="text-sm text-muted-foreground mt-4 text-center">
This prevents wealthy voters from dominating. Spreading votes across
proposals is more efficient than concentrating them.
</p>
</CardContent> </CardContent>
</Card> </Card>
{/* Ranking stage */} {/* Ranking stage */}
<section className="space-y-4"> <section className="space-y-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-3">
<Badge>Stage 1</Badge> <Badge className="bg-orange-500 hover:bg-orange-600">Stage 1</Badge>
<h2 className="text-xl font-semibold">Ranking</h2> <h2 className="text-xl font-semibold">Quadratic Ranking</h2>
<span className="text-muted-foreground text-sm"> <span className="text-muted-foreground text-sm">
Proposals need +100 to advance Score +100 to advance
</span> </span>
</div> </div>
{rankingProposals.map((proposal, index) => { <div className="space-y-2">
const hasPending = proposal.pendingVote !== 0; {rankingProposals.map((proposal) => {
const hasVoted = proposal.userVote !== 0; const hasPending = proposal.pendingVote !== 0;
const pendingCost = proposal.pendingVote * proposal.pendingVote; const hasVoted = proposal.userVote !== 0;
const previewScore = proposal.score + proposal.pendingVote; const pendingCost = proposal.pendingVote * proposal.pendingVote;
const rank = index + 1; const previewScore = proposal.score + proposal.pendingVote;
const progressPercent = Math.min((proposal.score / 100) * 100, 100);
const previewPercent = Math.min((previewScore / 100) * 100, 100);
return ( return (
<Card key={proposal.id} className="transition-all duration-300"> <Card
<div className="flex"> key={proposal.id}
{/* Rank indicator */} className={`transition-all duration-200 overflow-hidden ${
<div className="flex items-center justify-center px-3 bg-muted/50 border-r font-bold text-2xl text-muted-foreground min-w-[50px]"> hasPending
#{rank} ? proposal.pendingVote > 0
</div> ? "ring-2 ring-orange-500/50 bg-orange-500/5"
<div className="flex flex-col items-center justify-center px-4 border-r bg-muted/30 min-w-[100px]"> : "ring-2 ring-blue-500/50 bg-blue-500/5"
{/* Up arrow */} : hasVoted
<Button ? proposal.userVote > 0
variant={proposal.userVote > 0 ? "default" : proposal.pendingVote > 0 ? "outline" : "ghost"} ? "bg-orange-500/5"
size="sm" : "bg-blue-500/5"
className={`h-8 w-8 p-0 ${proposal.pendingVote > 0 ? "border-primary bg-primary/10" : ""}`} : ""
onClick={() => { }`}
if (proposal.userVote > 0) { >
removeVote(proposal.id); <div className="flex">
} else if (!hasPending || proposal.pendingVote > 0) { {/* Reddit-style vote column */}
incrementVote(proposal.id); <div className="flex flex-col items-center justify-center py-4 px-3 bg-muted/40 min-w-[70px] gap-1">
} {/* Upvote button */}
}} <button
disabled={hasVoted && proposal.userVote < 0} onClick={() => {
> if (hasVoted && proposal.userVote > 0) {
<ChevronUp className="h-5 w-5" /> removeVote(proposal.id);
</Button> } else if (!hasVoted || proposal.pendingVote >= 0) {
incrementVote(proposal.id);
}
}}
disabled={hasVoted && proposal.userVote < 0}
className={`p-1 rounded transition-all hover:scale-110 ${
(hasVoted && proposal.userVote > 0) || proposal.pendingVote > 0
? "text-orange-500"
: "text-muted-foreground hover:text-orange-500"
} ${hasVoted && proposal.userVote < 0 ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}`}
>
<ChevronUp className="h-8 w-8" strokeWidth={3} />
</button>
{/* Score display */} {/* Score display */}
<Badge <div className={`font-bold text-xl tabular-nums min-w-[3ch] text-center ${
variant={hasPending ? "default" : "outline"}
className={`font-mono text-lg my-1 min-w-[4rem] justify-center transition-all ${
hasPending hasPending
? proposal.pendingVote > 0 ? proposal.pendingVote > 0
? "bg-primary text-primary-foreground" ? "text-orange-500"
: "bg-destructive text-destructive-foreground" : "text-blue-500"
: "" : hasVoted
}`} ? proposal.userVote > 0
> ? "text-orange-500"
{hasPending ? ( : "text-blue-500"
<span className="flex items-center gap-1 text-sm"> : "text-foreground"
<span className="opacity-70">{proposal.score}</span> }`}>
<span></span> {hasPending ? previewScore : proposal.score}
<span>{previewScore}</span> </div>
</span>
) : (
proposal.score
)}
</Badge>
{/* Down arrow */} {/* Downvote button */}
<Button <button
variant={proposal.userVote < 0 ? "destructive" : proposal.pendingVote < 0 ? "outline" : "ghost"} onClick={() => {
size="sm" if (hasVoted && proposal.userVote < 0) {
className={`h-8 w-8 p-0 ${proposal.pendingVote < 0 ? "border-destructive bg-destructive/10" : ""}`} removeVote(proposal.id);
onClick={() => { } else if (!hasVoted || proposal.pendingVote <= 0) {
if (proposal.userVote < 0) { decrementVote(proposal.id);
removeVote(proposal.id); }
} else if (!hasPending || proposal.pendingVote < 0) { }}
decrementVote(proposal.id); disabled={hasVoted && proposal.userVote > 0}
} className={`p-1 rounded transition-all hover:scale-110 ${
}} (hasVoted && proposal.userVote < 0) || proposal.pendingVote < 0
disabled={hasVoted && proposal.userVote > 0} ? "text-blue-500"
> : "text-muted-foreground hover:text-blue-500"
<ChevronDown className="h-5 w-5" /> } ${hasVoted && proposal.userVote > 0 ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}`}
</Button> >
<ChevronDown className="h-8 w-8" strokeWidth={3} />
</button>
</div>
{/* Pending vote info */} {/* Proposal content */}
{hasPending && ( <div className="flex-1 p-4 min-w-0">
<div className="flex flex-col items-center gap-0.5 mt-2"> <h3 className="font-semibold text-base leading-tight">{proposal.title}</h3>
<span className="text-xs font-medium"> <p className="text-sm text-muted-foreground mt-1 line-clamp-2">
{proposal.pendingVote > 0 ? "+" : ""}{proposal.pendingVote} vote{Math.abs(proposal.pendingVote) !== 1 ? "s" : ""} {proposal.description}
</span> </p>
<span className="text-xs text-muted-foreground">
{pendingCost} credit{pendingCost !== 1 ? "s" : ""} {/* Progress bar */}
</span> <div className="mt-3">
<div className="flex gap-1 mt-1"> <div className="flex items-center justify-between text-xs text-muted-foreground mb-1">
<Button <span>Progress to voting stage</span>
variant="ghost" <span className={hasPending ? (proposal.pendingVote > 0 ? "text-orange-500" : "text-blue-500") : ""}>
size="sm" {hasPending ? previewScore : proposal.score}/100
className="h-6 w-6 p-0" </span>
onClick={() => cancelPending(proposal.id)} </div>
title="Cancel" <div className="h-2 rounded-full bg-muted overflow-hidden">
> <div
<X className="h-3 w-3" /> className={`h-full rounded-full transition-all duration-300 ${
</Button> hasPending
<Button ? proposal.pendingVote > 0
variant={proposal.pendingVote > 0 ? "default" : "destructive"} ? "bg-orange-500"
size="sm" : "bg-blue-500"
className="h-6 px-2 text-xs" : "bg-primary"
onClick={() => castVote(proposal.id)} }`}
title="Confirm vote" style={{ width: `${hasPending ? previewPercent : progressPercent}%` }}
> />
<Check className="h-3 w-3 mr-1" />
Cast
</Button>
</div> </div>
</div> </div>
)}
{/* Existing vote display */} {/* Vote status / pending confirmation */}
{hasVoted && !hasPending && ( {(hasPending || hasVoted) && (
<span className="text-xs text-muted-foreground mt-2"> <div className="mt-3 flex items-center gap-3">
Your vote: {proposal.userVote > 0 ? "+" : ""}{proposal.userVote} {hasPending ? (
</span> <>
)} <Badge
</div> variant="outline"
className={proposal.pendingVote > 0
<div className="flex-1 p-4"> ? "border-orange-500/50 text-orange-600 bg-orange-500/10"
<h3 className="font-semibold">{proposal.title}</h3> : "border-blue-500/50 text-blue-600 bg-blue-500/10"
<p className="text-sm text-muted-foreground"> }
{proposal.description} >
</p> {proposal.pendingVote > 0 ? "+" : ""}{proposal.pendingVote} vote = {pendingCost} credits
<div className="mt-3"> </Badge>
<div className="flex items-center justify-between text-xs mb-1"> <Button
<span>Progress to voting</span> size="sm"
<span>{hasPending ? previewScore : proposal.score}/100</span> variant="ghost"
</div> className="h-7 px-2 text-muted-foreground hover:text-foreground"
<Progress onClick={() => cancelPending(proposal.id)}
value={Math.min(((hasPending ? previewScore : proposal.score) / 100) * 100, 100)} >
className="h-2" <X className="h-4 w-4 mr-1" />
/> Cancel
</Button>
<Button
size="sm"
className={`h-7 ${
proposal.pendingVote > 0
? "bg-orange-500 hover:bg-orange-600"
: "bg-blue-500 hover:bg-blue-600"
}`}
onClick={() => castVote(proposal.id)}
>
<Check className="h-4 w-4 mr-1" />
Confirm
</Button>
</>
) : hasVoted && (
<Badge
variant="secondary"
className={proposal.userVote > 0
? "bg-orange-500/20 text-orange-600 border-orange-500/30"
: "bg-blue-500/20 text-blue-600 border-blue-500/30"
}
>
You voted: {proposal.userVote > 0 ? "+" : ""}{proposal.userVote}
</Badge>
)}
</div>
)}
</div> </div>
</div> </div>
</div> </Card>
</Card> );
); })}
})} </div>
</section> </section>
{/* Voting stage - only show if proposals have been promoted */} {/* Voting stage */}
{votingProposals.length > 0 && ( {votingProposals.length > 0 && (
<section className="space-y-4"> <section className="space-y-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-3">
<Badge variant="outline">Stage 2</Badge> <Badge variant="outline" className="border-green-500/50 text-green-600">Stage 2</Badge>
<h2 className="text-xl font-semibold">Pass/Fail Voting</h2> <h2 className="text-xl font-semibold">Pass/Fail Voting</h2>
<span className="text-muted-foreground text-sm"> <span className="text-muted-foreground text-sm">
One member = one vote One member = one vote
@ -401,79 +453,79 @@ export default function DemoPage() {
</div> </div>
{votingProposals.map((proposal) => { {votingProposals.map((proposal) => {
const total = proposal.yesVotes + proposal.noVotes; const total = proposal.yesVotes + proposal.noVotes;
const yesPercent = total > 0 ? (proposal.yesVotes / total) * 100 : 50; const yesPercent = total > 0 ? (proposal.yesVotes / total) * 100 : 50;
return ( return (
<Card key={proposal.id}> <Card key={proposal.id} className="border-green-500/30 bg-green-500/5">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<CardTitle className="text-lg">{proposal.title}</CardTitle> <CardTitle className="text-lg">{proposal.title}</CardTitle>
<div className="flex items-center gap-1 text-sm text-yellow-600"> <div className="flex items-center gap-1 text-sm text-amber-600">
<Clock className="h-4 w-4" /> <Clock className="h-4 w-4" />
<span>6 days left</span> <span>6 days left</span>
</div>
</div> </div>
</div> <CardDescription>{proposal.description}</CardDescription>
<CardDescription>{proposal.description}</CardDescription> </CardHeader>
</CardHeader> <CardContent className="space-y-4">
<CardContent className="space-y-4"> {/* Vote bar */}
{/* Vote bar */} <div className="space-y-2">
<div className="space-y-2"> <div className="h-4 rounded-full overflow-hidden bg-muted flex">
<div className="h-4 rounded-full overflow-hidden bg-red-500/20 flex"> <div
<div className="h-full bg-green-500 transition-all"
className="h-full bg-green-500 transition-all" style={{ width: `${yesPercent}%` }}
style={{ width: `${yesPercent}%` }} />
/> <div
<div className="h-full bg-red-500 transition-all"
className="h-full bg-red-500 transition-all" style={{ width: `${100 - yesPercent}%` }}
style={{ width: `${100 - yesPercent}%` }} />
/> </div>
<div className="flex justify-between text-sm font-medium">
<span className="text-green-600">
{proposal.yesVotes} Yes ({Math.round(yesPercent)}%)
</span>
<span className="text-red-600">
{proposal.noVotes} No ({Math.round(100 - yesPercent)}%)
</span>
</div>
</div> </div>
<div className="flex justify-between text-sm">
<span className="text-green-600">
{proposal.yesVotes} Yes ({Math.round(yesPercent)}%)
</span>
<span className="text-red-600">
{proposal.noVotes} No ({Math.round(100 - yesPercent)}%)
</span>
</div>
</div>
{/* Vote buttons */} {/* Vote buttons */}
<div className="grid grid-cols-3 gap-2"> <div className="grid grid-cols-3 gap-2">
<Button <Button
variant="outline" variant="outline"
className="flex-col h-auto py-3 hover:bg-green-500/10 hover:border-green-500" className="flex-col h-auto py-3 border-green-500/30 hover:bg-green-500/10 hover:border-green-500"
onClick={() => castFinalVote(proposal.id, "yes")} onClick={() => castFinalVote(proposal.id, "yes")}
> >
<Check className="h-5 w-5 text-green-500" /> <Check className="h-5 w-5 text-green-500" />
<span className="text-xs mt-1">Yes</span> <span className="text-xs mt-1">Yes</span>
</Button> </Button>
<Button <Button
variant="outline" variant="outline"
className="flex-col h-auto py-3 hover:bg-red-500/10 hover:border-red-500" className="flex-col h-auto py-3 border-red-500/30 hover:bg-red-500/10 hover:border-red-500"
onClick={() => castFinalVote(proposal.id, "no")} onClick={() => castFinalVote(proposal.id, "no")}
> >
<X className="h-5 w-5 text-red-500" /> <X className="h-5 w-5 text-red-500" />
<span className="text-xs mt-1">No</span> <span className="text-xs mt-1">No</span>
</Button> </Button>
<Button <Button
variant="outline" variant="outline"
className="flex-col h-auto py-3" className="flex-col h-auto py-3"
onClick={() => castFinalVote(proposal.id, "abstain")} onClick={() => castFinalVote(proposal.id, "abstain")}
> >
<Minus className="h-5 w-5" /> <Minus className="h-5 w-5" />
<span className="text-xs mt-1">Abstain</span> <span className="text-xs mt-1">Abstain</span>
</Button> </Button>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
); );
})} })}
</section> </section>
)} )}
{/* CTA */} {/* CTA */}
<Card className="border-primary bg-primary/5"> <Card className="border-2 border-primary/30 bg-gradient-to-r from-primary/10 to-accent/10">
<CardContent className="py-8 text-center space-y-4"> <CardContent className="py-8 text-center space-y-4">
<h2 className="text-2xl font-bold">Ready to try it for real?</h2> <h2 className="text-2xl font-bold">Ready to try it for real?</h2>
<p className="text-muted-foreground"> <p className="text-muted-foreground">
@ -481,7 +533,7 @@ export default function DemoPage() {
You&apos;ll get 50 credits to start and earn 10 more each day. You&apos;ll get 50 credits to start and earn 10 more each day.
</p> </p>
<div className="flex justify-center gap-4"> <div className="flex justify-center gap-4">
<Button asChild size="lg"> <Button asChild size="lg" className="bg-orange-500 hover:bg-orange-600">
<Link href="/auth/signup"> <Link href="/auth/signup">
Create Account <ArrowRight className="ml-2 h-4 w-4" /> Create Account <ArrowRight className="ml-2 h-4 w-4" />
</Link> </Link>

View File

@ -22,6 +22,7 @@ import {
ListOrdered, ListOrdered,
Target, Target,
Layers, Layers,
ChevronUp,
} from "lucide-react"; } from "lucide-react";
export default async function HomePage() { export default async function HomePage() {
@ -117,42 +118,68 @@ export default async function HomePage() {
{/* ELI5 Section */} {/* ELI5 Section */}
<section className="py-8"> <section className="py-8">
<Card className="border-2 border-accent/30 bg-gradient-to-r from-accent/5 via-primary/5 to-accent/5"> <div className="text-center mb-6">
<CardHeader className="text-center pb-2"> <Badge variant="secondary" className="mb-3 bg-muted text-muted-foreground">
<Badge variant="secondary" className="w-fit mx-auto mb-2 bg-accent/10 text-accent-foreground border-accent/20"> ELI5
ELI5 </Badge>
</Badge> <h2 className="text-2xl font-bold">rVote in 30 Seconds</h2>
<CardTitle className="text-2xl">rVote in 30 Seconds</CardTitle> <p className="text-lg text-muted-foreground mt-2 max-w-2xl mx-auto">
</CardHeader> A <strong className="text-orange-500">quadratic</strong>{" "}
<CardContent className="text-center max-w-3xl mx-auto"> <strong className="text-blue-500">Reddit-style ranking system</strong>{" "}
<p className="text-lg text-muted-foreground leading-relaxed"> with <strong className="text-purple-500">time-delayed vote decay</strong>{" "}
<strong className="text-foreground">rVote</strong> is a{" "} for proposal prioritization.
<strong className="text-primary">quadratic Reddit-style ranking system</strong>{" "} </p>
with <strong className="text-accent">time-delayed vote decay</strong>{" "} </div>
for proposal prioritization.
</p> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6 text-sm"> {/* Quadratic */}
<div className="p-3 rounded-lg bg-primary/10"> <Card className="border-2 border-orange-500/40 bg-gradient-to-br from-orange-500/10 to-orange-500/5 overflow-hidden">
<strong className="text-primary">Quadratic</strong> <CardContent className="pt-5 pb-4">
<p className="text-muted-foreground mt-1"> <div className="flex items-center gap-2 mb-3">
Voting more costs exponentially more credits (11, 24, 39), preventing any single voice from dominating. <div className="h-8 w-8 rounded-full bg-orange-500 flex items-center justify-center">
</p> <span className="text-white font-bold text-sm">x²</span>
</div>
<h3 className="font-bold text-orange-600 text-lg">Quadratic</h3>
</div> </div>
<div className="p-3 rounded-lg bg-secondary/10"> <p className="text-sm text-muted-foreground leading-relaxed">
<strong className="text-secondary">Reddit-style</strong> Voting more costs exponentially more credits. 1 vote = 1 credit, 2 votes = 4, 3 votes = 9.
<p className="text-muted-foreground mt-1"> <strong className="text-foreground block mt-2">No single voice can dominate.</strong>
Upvote or downvote proposals. The best ideas rise to the top through collective ranking. </p>
</p> </CardContent>
</Card>
{/* Reddit-style */}
<Card className="border-2 border-blue-500/40 bg-gradient-to-br from-blue-500/10 to-blue-500/5 overflow-hidden">
<CardContent className="pt-5 pb-4">
<div className="flex items-center gap-2 mb-3">
<div className="h-8 w-8 rounded-full bg-blue-500 flex items-center justify-center">
<ChevronUp className="h-5 w-5 text-white" />
</div>
<h3 className="font-bold text-blue-600 text-lg">Reddit-style</h3>
</div> </div>
<div className="p-3 rounded-lg bg-accent/10"> <p className="text-sm text-muted-foreground leading-relaxed">
<strong className="text-accent-foreground">Vote Decay</strong> Upvote or downvote proposals. Scores aggregate from all community votes.
<p className="text-muted-foreground mt-1"> <strong className="text-foreground block mt-2">Best ideas rise to the top.</strong>
Votes fade after 30-60 days, ensuring rankings reflect current community priorities, not ancient history. </p>
</p> </CardContent>
</Card>
{/* Vote Decay */}
<Card className="border-2 border-purple-500/40 bg-gradient-to-br from-purple-500/10 to-purple-500/5 overflow-hidden">
<CardContent className="pt-5 pb-4">
<div className="flex items-center gap-2 mb-3">
<div className="h-8 w-8 rounded-full bg-purple-500 flex items-center justify-center">
<Clock className="h-4 w-4 text-white" />
</div>
<h3 className="font-bold text-purple-600 text-lg">Vote Decay</h3>
</div> </div>
</div> <p className="text-sm text-muted-foreground leading-relaxed">
</CardContent> Votes fade after 30-60 days. Old support expires, requiring renewed interest.
</Card> <strong className="text-foreground block mt-2">Rankings stay fresh and relevant.</strong>
</p>
</CardContent>
</Card>
</div>
</section> </section>
{/* What is Quadratic Proposal Ranking */} {/* What is Quadratic Proposal Ranking */}