|
| 1 | +"use client"; |
| 2 | + |
| 3 | +// Floating Morpheus button on the stake page (prospecting side of the loop — |
| 4 | +// MorLootbox handles collecting; this invites a NEW backer to stake). |
| 5 | +// button → "Gnars subnet" panel (pitch + Stake) → staking milestones → stake. |
| 6 | +// Sits above the MiniTV (bottom-left); MorLootbox owns bottom-right. |
| 7 | +// |
| 8 | +// NOTE: milestone copy + targets are placeholders — swap for the real program. |
| 9 | +// Strings are hardcoded EN for now (not yet wired to next-intl stake namespace). |
| 10 | + |
| 11 | +import Image from "next/image"; |
| 12 | +import { useState } from "react"; |
| 13 | +import { AnimatePresence, motion } from "framer-motion"; |
| 14 | +import { ArrowRight, Check, ChevronLeft, Lock, X } from "lucide-react"; |
| 15 | +import { Button } from "@/components/ui/button"; |
| 16 | + |
| 17 | +type View = "closed" | "intro" | "milestones"; |
| 18 | + |
| 19 | +const MILESTONES: { label: string; done: boolean }[] = [ |
| 20 | + { label: "Subnet live — Gnars is a Morpheus Builder", done: true }, |
| 21 | + { label: "First 10 backers on board", done: false }, |
| 22 | + { label: "$10k staked — featured stakers wall", done: false }, |
| 23 | + { label: "$50k staked — community drop", done: false }, |
| 24 | + { label: "$100k staked — IRL Gnars event", done: false }, |
| 25 | +]; |
| 26 | + |
| 27 | +export function MorpheusStakeWidget() { |
| 28 | + const [view, setView] = useState<View>("closed"); |
| 29 | + |
| 30 | + const goStake = () => { |
| 31 | + document.getElementById("stake-start")?.scrollIntoView({ behavior: "smooth", block: "start" }); |
| 32 | + setView("closed"); |
| 33 | + }; |
| 34 | + |
| 35 | + return ( |
| 36 | + <div className="fixed left-4 bottom-[150px] z-40 flex flex-col items-start gap-3"> |
| 37 | + <AnimatePresence> |
| 38 | + {view !== "closed" && ( |
| 39 | + <motion.div |
| 40 | + initial={{ opacity: 0, y: 12, scale: 0.96 }} |
| 41 | + animate={{ opacity: 1, y: 0, scale: 1 }} |
| 42 | + exit={{ opacity: 0, y: 12, scale: 0.96 }} |
| 43 | + transition={{ duration: 0.18 }} |
| 44 | + className="w-[min(360px,calc(100vw-2rem))] max-h-[65vh] overflow-y-auto rounded-2xl border border-violet-500/30 bg-background/95 p-5 shadow-2xl backdrop-blur" |
| 45 | + > |
| 46 | + <div className="mb-3 flex items-center justify-between"> |
| 47 | + <div className="flex items-center gap-2"> |
| 48 | + {view === "milestones" ? ( |
| 49 | + <button |
| 50 | + type="button" |
| 51 | + onClick={() => setView("intro")} |
| 52 | + className="text-muted-foreground transition-colors hover:text-foreground" |
| 53 | + aria-label="Back" |
| 54 | + > |
| 55 | + <ChevronLeft className="h-4 w-4" /> |
| 56 | + </button> |
| 57 | + ) : ( |
| 58 | + <Image src="/logos/morpheus.webp" alt="Morpheus" width={22} height={22} className="rounded" /> |
| 59 | + )} |
| 60 | + <span className="text-xs font-bold uppercase tracking-wider text-violet-400">Gnars subnet</span> |
| 61 | + </div> |
| 62 | + <button |
| 63 | + type="button" |
| 64 | + onClick={() => setView("closed")} |
| 65 | + className="text-muted-foreground transition-colors hover:text-foreground" |
| 66 | + aria-label="Close" |
| 67 | + > |
| 68 | + <X className="h-4 w-4" /> |
| 69 | + </button> |
| 70 | + </div> |
| 71 | + |
| 72 | + {view === "intro" ? ( |
| 73 | + <div className="space-y-4"> |
| 74 | + <div> |
| 75 | + <h3 className="text-lg font-black tracking-tight">Stake on the Gnars subnet</h3> |
| 76 | + <p className="mt-1 text-sm text-muted-foreground"> |
| 77 | + Back Gnars on Morpheus and put decentralized AI behind a real action-sports culture. |
| 78 | + Self-custody on Ethereum mainnet — your keys the whole way. |
| 79 | + </p> |
| 80 | + </div> |
| 81 | + <Button |
| 82 | + onClick={() => setView("milestones")} |
| 83 | + className="w-full bg-violet-500 text-white hover:bg-violet-600" |
| 84 | + > |
| 85 | + Stake <ArrowRight className="ml-1 h-4 w-4" /> |
| 86 | + </Button> |
| 87 | + </div> |
| 88 | + ) : ( |
| 89 | + <div className="space-y-4"> |
| 90 | + <div> |
| 91 | + <h3 className="text-base font-black tracking-tight">Staking milestones</h3> |
| 92 | + <p className="mt-1 text-xs text-muted-foreground">What the subnet unlocks as backing grows.</p> |
| 93 | + </div> |
| 94 | + <ol className="space-y-2.5"> |
| 95 | + {MILESTONES.map((m, i) => ( |
| 96 | + <li key={i} className="flex items-start gap-2.5"> |
| 97 | + <span |
| 98 | + className={`mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full ${ |
| 99 | + m.done ? "bg-violet-500 text-white" : "border border-border text-muted-foreground" |
| 100 | + }`} |
| 101 | + > |
| 102 | + {m.done ? <Check className="h-3 w-3" /> : <Lock className="h-3 w-3" />} |
| 103 | + </span> |
| 104 | + <span className={`text-sm ${m.done ? "font-semibold text-foreground" : "text-muted-foreground"}`}> |
| 105 | + {m.label} |
| 106 | + </span> |
| 107 | + </li> |
| 108 | + ))} |
| 109 | + </ol> |
| 110 | + <Button onClick={goStake} className="w-full bg-violet-500 text-white hover:bg-violet-600"> |
| 111 | + Stake now <ArrowRight className="ml-1 h-4 w-4" /> |
| 112 | + </Button> |
| 113 | + </div> |
| 114 | + )} |
| 115 | + </motion.div> |
| 116 | + )} |
| 117 | + </AnimatePresence> |
| 118 | + |
| 119 | + <button |
| 120 | + type="button" |
| 121 | + onClick={() => setView(view === "closed" ? "intro" : "closed")} |
| 122 | + aria-label="Stake on the Gnars subnet" |
| 123 | + className="group relative flex h-14 w-14 items-center justify-center rounded-full border border-violet-400/40 bg-background/90 shadow-lg backdrop-blur transition hover:scale-105" |
| 124 | + > |
| 125 | + {view === "closed" && ( |
| 126 | + <span className="absolute inset-0 animate-ping rounded-full bg-violet-500/20" aria-hidden /> |
| 127 | + )} |
| 128 | + <Image src="/logos/morpheus.webp" alt="Morpheus" width={34} height={34} className="relative rounded-full" /> |
| 129 | + </button> |
| 130 | + </div> |
| 131 | + ); |
| 132 | +} |
0 commit comments