@@ -64,6 +64,63 @@ function relativeTime(ts: number): string {
6464 return `${ Math . floor ( diffDays / 30 ) } mo ago` ;
6565}
6666
67+ // ─── Sample data (shown only when no real wins exist yet) ──────
68+ // Helps launch with a populated feel; replaced by real data as soon
69+ // as one user runs `loopkit celebrate --share`.
70+ const SAMPLE_WINS : PublicWin [ ] = [
71+ {
72+ _id : "sample-1" ,
73+ productName : "ProposalAI" ,
74+ weekNum : 12 ,
75+ shippingScore : 88 ,
76+ streak : 12 ,
77+ tasksCompleted : 5 ,
78+ tasksTotal : 5 ,
79+ feedbackCount : 8 ,
80+ loopkitScore : 91 ,
81+ mrr : 240 ,
82+ oneThing :
83+ "Stop perfectionism. Ship the v0.1 with a known gap. The gap is the conversation that gets you the next customer." ,
84+ createdAt : Date . now ( ) - 2 * 24 * 60 * 60 * 1000 ,
85+ handle : "demo-founder" ,
86+ projectSlug : "proposalai" ,
87+ } ,
88+ {
89+ _id : "sample-2" ,
90+ productName : "ShipLane" ,
91+ weekNum : 8 ,
92+ shippingScore : 75 ,
93+ streak : 6 ,
94+ tasksCompleted : 4 ,
95+ tasksTotal : 5 ,
96+ feedbackCount : 3 ,
97+ loopkitScore : 78 ,
98+ mrr : null ,
99+ oneThing :
100+ "Distribution tasks keep getting pushed to next week. Block 90 min Tuesday and 90 min Friday. Non-negotiable." ,
101+ createdAt : Date . now ( ) - 4 * 24 * 60 * 60 * 1000 ,
102+ handle : "founder-jane" ,
103+ projectSlug : "shiplane" ,
104+ } ,
105+ {
106+ _id : "sample-3" ,
107+ productName : "PulseDeck" ,
108+ weekNum : 5 ,
109+ shippingScore : 100 ,
110+ streak : 5 ,
111+ tasksCompleted : 3 ,
112+ tasksTotal : 3 ,
113+ feedbackCount : 12 ,
114+ loopkitScore : 85 ,
115+ mrr : 60 ,
116+ oneThing :
117+ "Three paying customers this week. All from one tweet thread. Build-in-public works when the loop is honest." ,
118+ createdAt : Date . now ( ) - 6 * 24 * 60 * 60 * 1000 ,
119+ handle : "mike-builds" ,
120+ projectSlug : "pulsedeck" ,
121+ } ,
122+ ] ;
123+
67124function WinCard ( { win } : { win : PublicWin } ) {
68125 return (
69126 < article className = "p-5 rounded-2xl border border-zinc-800 bg-zinc-900/30 hover:bg-zinc-900/50 transition-colors" >
@@ -138,6 +195,17 @@ export default async function WinsPage() {
138195 )
139196 : 0 ;
140197
198+ const showSamples = wins . length === 0 ;
199+ const displayedWins = showSamples ? SAMPLE_WINS : wins ;
200+ const stats = showSamples
201+ ? { count : SAMPLE_WINS . length , founders : 3 , avg : 88 , streak : 12 }
202+ : {
203+ count : totalWins ,
204+ founders : shippingFounders ,
205+ avg : avgScore ,
206+ streak : longestStreak ,
207+ } ;
208+
141209 return (
142210 < main id = "main-content" className = "relative overflow-hidden" >
143211 { /* ─── Hero ──────────────────────────────────────────── */ }
@@ -146,8 +214,10 @@ export default async function WinsPage() {
146214
147215 < div className = "relative z-10 max-w-4xl mx-auto px-6 text-center" >
148216 < div className = "fade-up inline-flex items-center gap-2 px-4 py-1.5 mb-8 rounded-full border border-zinc-800 bg-zinc-900/50 text-sm text-zinc-400" >
149- < span className = "w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
150- { totalWins > 0 ? `${ totalWins } public win${ totalWins === 1 ? "" : "s" } ` : "Wins start here" }
217+ < span className = { `w-2 h-2 rounded-full ${ showSamples ? "bg-amber-500" : "bg-emerald-500" } animate-pulse` } />
218+ { showSamples
219+ ? "Sample wins — your data appears here when you ship"
220+ : `${ stats . count } public win${ stats . count === 1 ? "" : "s" } ` }
151221 </ div >
152222
153223 < h1 className = "fade-up delay-1 text-5xl sm:text-7xl font-bold tracking-tight leading-[1.08]" >
@@ -166,21 +236,21 @@ export default async function WinsPage() {
166236 < dl className = "fade-up delay-3 mt-10 grid grid-cols-2 sm:grid-cols-4 gap-3 max-w-2xl mx-auto" >
167237 < div className = "p-4 rounded-xl border border-zinc-800 bg-zinc-900/30" >
168238 < dt className = "text-xs text-zinc-500 uppercase tracking-wider" > Wins</ dt >
169- < dd className = "mt-1 text-2xl font-bold text-white" > { totalWins } </ dd >
239+ < dd className = "mt-1 text-2xl font-bold text-white" > { stats . count } </ dd >
170240 </ div >
171241 < div className = "p-4 rounded-xl border border-zinc-800 bg-zinc-900/30" >
172242 < dt className = "text-xs text-zinc-500 uppercase tracking-wider" > Founders</ dt >
173- < dd className = "mt-1 text-2xl font-bold text-white" > { shippingFounders } </ dd >
243+ < dd className = "mt-1 text-2xl font-bold text-white" > { stats . founders } </ dd >
174244 </ div >
175245 < div className = "p-4 rounded-xl border border-zinc-800 bg-zinc-900/30" >
176246 < dt className = "text-xs text-zinc-500 uppercase tracking-wider" > Avg Score</ dt >
177- < dd className = "mt-1 text-2xl font-bold text-white" > { avgScore } %</ dd >
247+ < dd className = "mt-1 text-2xl font-bold text-white" > { stats . avg } %</ dd >
178248 </ div >
179249 < div className = "p-4 rounded-xl border border-orange-500/20 bg-zinc-900/30" >
180250 < dt className = "text-xs text-orange-400 uppercase tracking-wider flex items-center gap-1" >
181251 < Flame className = "h-3 w-3" /> Longest
182252 </ dt >
183- < dd className = "mt-1 text-2xl font-bold text-white" > { longestStreak } </ dd >
253+ < dd className = "mt-1 text-2xl font-bold text-white" > { stats . streak } </ dd >
184254 </ div >
185255 </ dl >
186256 ) }
@@ -207,36 +277,43 @@ export default async function WinsPage() {
207277 < div className = "max-w-4xl mx-auto" >
208278 < header className = "mb-12" >
209279 < h2 className = "text-3xl sm:text-4xl font-bold tracking-tight mb-3" >
210- This week' s wins
280+ { showSamples ? "Sample wins (what you'll see)" : " This week' s wins" }
211281 </ h2 >
212282 < p className = "text-zinc-400" >
213- { wins . length > 0
214- ? `Showing the ${ wins . length } most recent public wins.`
215- : "No public wins yet. Be the first — run `loopkit celebrate --share`." }
283+ { showSamples
284+ ? "These are sample wins. Run `loopkit celebrate --share` after your next `loop` and yours will appear here."
285+ : `Showing the ${ wins . length } most recent public wins.` }
216286 </ p >
217287 </ header >
218288
219289 { wins . length === 0 ? (
220- < div className = "p-12 text-center rounded-2xl border border-dashed border-zinc-800 bg-zinc-900/20" >
221- < Trophy className = "h-10 w-10 text-zinc-700 mx-auto mb-4" aria-hidden = "true" />
222- < h3 className = "text-lg font-semibold text-white mb-2" >
223- The leaderboard is open.
224- </ h3 >
225- < p className = "text-zinc-400 text-sm mb-6 max-w-md mx-auto" >
226- When a LoopKit user runs < code className = "font-mono text-violet-400" > loopkit celebrate --share</ code > ,
227- their weekly win lands here.
228- </ p >
229- < Link
230- href = "/"
231- className = "inline-flex items-center gap-2 px-5 py-2.5 rounded-lg bg-white text-black text-sm font-medium hover:bg-zinc-200 transition-colors"
232- >
233- Start shipping
234- < ChevronRight className = "h-4 w-4" aria-hidden = "true" />
235- </ Link >
236- </ div >
290+ < >
291+ < div className = "grid grid-cols-1 md:grid-cols-2 gap-4" >
292+ { displayedWins . map ( ( win ) => (
293+ < WinCard key = { win . _id } win = { win } />
294+ ) ) }
295+ </ div >
296+ < div className = "mt-8 p-8 text-center rounded-2xl border border-dashed border-zinc-800 bg-zinc-900/20" >
297+ < Trophy className = "h-10 w-10 text-zinc-700 mx-auto mb-4" aria-hidden = "true" />
298+ < h3 className = "text-lg font-semibold text-white mb-2" >
299+ Ready to land your win here?
300+ </ h3 >
301+ < p className = "text-zinc-400 text-sm mb-6 max-w-md mx-auto" >
302+ Run < code className = "font-mono text-violet-400" > loopkit celebrate --share</ code > { " " }
303+ after your next < code className = "font-mono text-violet-400" > loop</ code > and replace one of these samples with your own.
304+ </ p >
305+ < Link
306+ href = "/"
307+ className = "inline-flex items-center gap-2 px-5 py-2.5 rounded-lg bg-white text-black text-sm font-medium hover:bg-zinc-200 transition-colors"
308+ >
309+ Start shipping
310+ < ChevronRight className = "h-4 w-4" aria-hidden = "true" />
311+ </ Link >
312+ </ div >
313+ </ >
237314 ) : (
238315 < div className = "grid grid-cols-1 md:grid-cols-2 gap-4" >
239- { wins . map ( ( win ) => (
316+ { displayedWins . map ( ( win ) => (
240317 < WinCard key = { win . _id } win = { win } />
241318 ) ) }
242319 </ div >
0 commit comments