@devrongx/games 0.4.43 → 0.4.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -222,13 +222,15 @@ const deriveDemoData = (config: IChallengeConfig) => {
|
|
|
222
222
|
const markets = config.markets;
|
|
223
223
|
const len = markets.length;
|
|
224
224
|
|
|
225
|
-
let idxA: number, idxB: number;
|
|
226
|
-
if (len > 12) { idxA = 8; idxB = 12; }
|
|
227
|
-
else if (len >=
|
|
228
|
-
else { idxA = 0; idxB =
|
|
225
|
+
let idxA: number, idxB: number, idxC: number;
|
|
226
|
+
if (len > 12) { idxA = 8; idxB = 12; idxC = 4; }
|
|
227
|
+
else if (len >= 3) { idxA = len - 3; idxB = len - 2; idxC = len - 1; }
|
|
228
|
+
else if (len >= 2) { idxA = 0; idxB = 1; idxC = 0; }
|
|
229
|
+
else { idxA = 0; idxB = 0; idxC = 0; }
|
|
229
230
|
|
|
230
231
|
const marketA = markets[idxA];
|
|
231
232
|
const marketB = markets[idxB];
|
|
233
|
+
const marketC = markets[idxC]; // unselected third question
|
|
232
234
|
|
|
233
235
|
const optIdxA = Math.min(1, marketA.options.length - 1);
|
|
234
236
|
const optIdxB = Math.min(2, marketB.options.length - 1);
|
|
@@ -247,41 +249,127 @@ const deriveDemoData = (config: IChallengeConfig) => {
|
|
|
247
249
|
const combinedOdds = optionA.odds * optionB.odds;
|
|
248
250
|
const combinedReward = Math.round(combinedStake * combinedOdds);
|
|
249
251
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
return { marketA, marketB, optIdxA, optIdxB, optionA, optionB, betA, betB, chips, rewardA, rewardB, combinedStake, combinedOdds, combinedReward, maxMult };
|
|
252
|
+
return { marketA, marketB, marketC, optIdxA, optIdxB, optionA, optionB, betA, betB, chips, rewardA, rewardB, combinedStake, combinedOdds, combinedReward };
|
|
253
253
|
};
|
|
254
254
|
|
|
255
|
-
// ── Slide 3: Markets demo —
|
|
255
|
+
// ── Slide 3: Markets demo — 3 questions, 2 selected one by one ──
|
|
256
256
|
const MarketsSlide = ({ config }: SlideProps) => {
|
|
257
257
|
const demo = useMemo(() => deriveDemoData(config), [config]);
|
|
258
258
|
const [demoStep, setDemoStep] = useState(0);
|
|
259
259
|
|
|
260
260
|
useEffect(() => {
|
|
261
261
|
const timers = [
|
|
262
|
-
setTimeout(() => setDemoStep(1),
|
|
263
|
-
setTimeout(() => setDemoStep(2),
|
|
264
|
-
setTimeout(() => setDemoStep(3),
|
|
265
|
-
setTimeout(() => setDemoStep(4),
|
|
266
|
-
setTimeout(() => setDemoStep(5),
|
|
267
|
-
setTimeout(() => setDemoStep(6),
|
|
268
|
-
setTimeout(() => setDemoStep(7), 6800),
|
|
269
|
-
setTimeout(() => setDemoStep(8), 7800),
|
|
270
|
-
setTimeout(() => setDemoStep(9), 8500),
|
|
271
|
-
setTimeout(() => setDemoStep(10), 9100),
|
|
262
|
+
setTimeout(() => setDemoStep(1), 600), // All 3 cards appear
|
|
263
|
+
setTimeout(() => setDemoStep(2), 2000), // Card 1 option selected
|
|
264
|
+
setTimeout(() => setDemoStep(3), 3000), // Card 1 chips + auto-select
|
|
265
|
+
setTimeout(() => setDemoStep(4), 3800), // Card 1 outcome line
|
|
266
|
+
setTimeout(() => setDemoStep(5), 5000), // Card 1 compresses, Card 2 option selected
|
|
267
|
+
setTimeout(() => setDemoStep(6), 6000), // Card 2 chips + auto-select
|
|
268
|
+
setTimeout(() => setDemoStep(7), 6800), // Card 2 outcome line
|
|
272
269
|
];
|
|
273
270
|
return () => timers.forEach(clearTimeout);
|
|
274
271
|
}, []);
|
|
275
272
|
|
|
276
|
-
const { marketA, marketB, optIdxA, optIdxB, optionA, optionB, betA, betB, chips, rewardA, rewardB } = demo;
|
|
273
|
+
const { marketA, marketB, marketC, optIdxA, optIdxB, optionA, optionB, betA, betB, chips, rewardA, rewardB } = demo;
|
|
277
274
|
const IconA = MARKET_ICONS[marketA.icon];
|
|
278
275
|
const IconB = MARKET_ICONS[marketB.icon];
|
|
276
|
+
const IconC = MARKET_ICONS[marketC.icon];
|
|
277
|
+
|
|
278
|
+
const card1Compressed = demoStep >= 5;
|
|
279
|
+
|
|
280
|
+
// Shared option renderer for a full options grid
|
|
281
|
+
const renderOptionsGrid = (market: typeof marketA, selectedOptIdx: number | null) => (
|
|
282
|
+
<div className="grid grid-cols-2 gap-1.5">
|
|
283
|
+
{market.options.map((opt, j) => {
|
|
284
|
+
const isSelected = selectedOptIdx !== null && j === selectedOptIdx;
|
|
285
|
+
return (
|
|
286
|
+
<div
|
|
287
|
+
key={j}
|
|
288
|
+
className="flex items-center justify-between px-2 py-1.5 rounded-sm transition-all duration-500"
|
|
289
|
+
style={{
|
|
290
|
+
background: isSelected ? "linear-gradient(135deg, #22E3E8, #9945FF)" : "transparent",
|
|
291
|
+
borderLeft: isSelected ? "1px solid transparent" : "1px solid rgba(255,255,255,0.12)",
|
|
292
|
+
borderBottom: isSelected ? "1px solid transparent" : "1px solid rgba(255,255,255,0.06)",
|
|
293
|
+
borderTop: "1px solid transparent",
|
|
294
|
+
borderRight: "1px solid transparent",
|
|
295
|
+
}}
|
|
296
|
+
>
|
|
297
|
+
<div className="flex items-center gap-1.5 min-w-0 flex-shrink">
|
|
298
|
+
{isSelected && (
|
|
299
|
+
<motion.svg
|
|
300
|
+
initial={{ scale: 0 }}
|
|
301
|
+
animate={{ scale: 1 }}
|
|
302
|
+
transition={{ type: "spring", stiffness: 400, damping: 15 }}
|
|
303
|
+
width="10" height="10" viewBox="0 0 16 16" fill="none"
|
|
304
|
+
>
|
|
305
|
+
<circle cx="8" cy="8" r="8" fill="white" />
|
|
306
|
+
<path d="M5 8l2 2 4-4" stroke="#9945FF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
|
307
|
+
</motion.svg>
|
|
308
|
+
)}
|
|
309
|
+
<span className="text-[10px] text-white font-semibold truncate" style={OUTFIT}>{opt.label}</span>
|
|
310
|
+
</div>
|
|
311
|
+
<span className={`text-[10px] font-bold flex-shrink-0 ${isSelected ? "text-white" : "text-[#22E3E8]"}`} style={OUTFIT}>{opt.odds}x</span>
|
|
312
|
+
</div>
|
|
313
|
+
);
|
|
314
|
+
})}
|
|
315
|
+
</div>
|
|
316
|
+
);
|
|
279
317
|
|
|
280
|
-
|
|
318
|
+
// Shared chip carousel renderer
|
|
319
|
+
const renderChips = (selectedAmt: number) => (
|
|
320
|
+
<motion.div
|
|
321
|
+
initial={{ opacity: 0, height: 0 }}
|
|
322
|
+
animate={{ opacity: 1, height: "auto" }}
|
|
323
|
+
exit={{ opacity: 0, height: 0 }}
|
|
324
|
+
transition={{ duration: 0.3 }}
|
|
325
|
+
className="flex items-center gap-1.5 overflow-hidden mt-2"
|
|
326
|
+
>
|
|
327
|
+
<span className="text-[8px] text-white/60 font-semibold flex-shrink-0" style={OUTFIT}>Bet:</span>
|
|
328
|
+
{chips.map((amt, i) => {
|
|
329
|
+
const isChipSelected = amt === selectedAmt;
|
|
330
|
+
return (
|
|
331
|
+
<motion.div
|
|
332
|
+
key={amt}
|
|
333
|
+
initial={{ opacity: 0, scale: 0.8 }}
|
|
334
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
335
|
+
transition={{ delay: i * 0.08 }}
|
|
336
|
+
className="flex items-center gap-0.5 px-2 py-[3px] rounded relative overflow-hidden"
|
|
337
|
+
style={isChipSelected ? {
|
|
338
|
+
background: "linear-gradient(135deg, #22E3E8, #9945FF, #f83cc5)",
|
|
339
|
+
} : {
|
|
340
|
+
background: "rgba(34,227,232,0.08)",
|
|
341
|
+
border: "1px solid rgba(34,227,232,0.2)",
|
|
342
|
+
}}
|
|
343
|
+
>
|
|
344
|
+
<PointsIcon size={7} />
|
|
345
|
+
<span className={`text-[9px] font-bold relative z-[1] ${isChipSelected ? "text-black" : "text-[#22E3E8]"}`} style={OUTFIT}>{amt}</span>
|
|
346
|
+
</motion.div>
|
|
347
|
+
);
|
|
348
|
+
})}
|
|
349
|
+
</motion.div>
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
// Shared outcome line renderer
|
|
353
|
+
const renderOutcome = (bet: number, odds: number, reward: number) => (
|
|
354
|
+
<motion.div
|
|
355
|
+
initial={{ opacity: 0, y: 4 }}
|
|
356
|
+
animate={{ opacity: 1, y: 0 }}
|
|
357
|
+
transition={{ duration: 0.3 }}
|
|
358
|
+
className="flex items-center gap-[3px] mt-1.5"
|
|
359
|
+
>
|
|
360
|
+
<PointsIcon size={7} />
|
|
361
|
+
<span className="text-[9px] text-white font-semibold" style={OUTFIT}>{bet}</span>
|
|
362
|
+
<span className="text-[8px] text-white" style={OUTFIT}>×</span>
|
|
363
|
+
<span className="text-[9px] text-white/60 font-semibold" style={OUTFIT}>{odds}</span>
|
|
364
|
+
<span className="text-[8px] text-white/40" style={OUTFIT}>{"\u2192"}</span>
|
|
365
|
+
<PointsIcon size={7} />
|
|
366
|
+
<span className="text-[9px] text-[#22E3E8] font-bold" style={OUTFIT}>{reward}</span>
|
|
367
|
+
</motion.div>
|
|
368
|
+
);
|
|
281
369
|
|
|
282
370
|
return (
|
|
283
371
|
<motion.div
|
|
284
|
-
className="flex flex-col items-center gap-
|
|
372
|
+
className="flex flex-col items-center gap-2.5 w-full max-w-[300px]"
|
|
285
373
|
initial="initial"
|
|
286
374
|
animate="animate"
|
|
287
375
|
exit="exit"
|
|
@@ -297,65 +385,38 @@ const MarketsSlide = ({ config }: SlideProps) => {
|
|
|
297
385
|
{config.markets.length} questions to predict
|
|
298
386
|
</motion.p>
|
|
299
387
|
|
|
300
|
-
{/*
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
388
|
+
{/* All 3 cards appear together */}
|
|
389
|
+
{demoStep >= 1 && (
|
|
390
|
+
<motion.div
|
|
391
|
+
initial={{ opacity: 0, y: 16 }}
|
|
392
|
+
animate={{ opacity: 1, y: 0 }}
|
|
393
|
+
transition={{ duration: 0.5 }}
|
|
394
|
+
className="w-full flex flex-col gap-2"
|
|
395
|
+
>
|
|
396
|
+
{/* Card 1 */}
|
|
397
|
+
<div
|
|
398
|
+
className="w-full rounded-lg px-3 py-2.5"
|
|
308
399
|
style={{
|
|
309
400
|
background: "rgba(255,255,255,0.03)",
|
|
310
401
|
border: "1px solid rgba(255,255,255,0.08)",
|
|
311
402
|
}}
|
|
312
403
|
>
|
|
313
|
-
|
|
314
|
-
<div className="flex items-center gap-2 mb-2">
|
|
404
|
+
<div className="flex items-center gap-2 mb-1.5">
|
|
315
405
|
{IconA && <IconA size={14} style={{ color: marketA.accent }} className="flex-shrink-0" />}
|
|
316
406
|
<span className={`text-white font-semibold leading-tight ${card1Compressed ? "text-[11px]" : "text-[13px]"}`} style={OUTFIT}>
|
|
317
407
|
{marketA.question}
|
|
318
408
|
</span>
|
|
319
409
|
</div>
|
|
320
410
|
|
|
321
|
-
{/* Options grid or compressed selected tag */}
|
|
322
411
|
{!card1Compressed ? (
|
|
323
|
-
|
|
324
|
-
{marketA
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
className="flex items-center justify-between px-2 py-1.5 rounded-sm transition-all duration-500"
|
|
330
|
-
style={{
|
|
331
|
-
background: isSelected ? "linear-gradient(135deg, #22E3E8, #9945FF)" : "transparent",
|
|
332
|
-
borderLeft: isSelected ? "1px solid transparent" : "1px solid rgba(255,255,255,0.12)",
|
|
333
|
-
borderBottom: isSelected ? "1px solid transparent" : "1px solid rgba(255,255,255,0.06)",
|
|
334
|
-
borderTop: "1px solid transparent",
|
|
335
|
-
borderRight: "1px solid transparent",
|
|
336
|
-
}}
|
|
337
|
-
>
|
|
338
|
-
<div className="flex items-center gap-1.5">
|
|
339
|
-
{isSelected && (
|
|
340
|
-
<motion.svg
|
|
341
|
-
initial={{ scale: 0 }}
|
|
342
|
-
animate={{ scale: 1 }}
|
|
343
|
-
transition={{ type: "spring", stiffness: 400, damping: 15 }}
|
|
344
|
-
width="10" height="10" viewBox="0 0 16 16" fill="none"
|
|
345
|
-
>
|
|
346
|
-
<circle cx="8" cy="8" r="8" fill="white" />
|
|
347
|
-
<path d="M5 8l2 2 4-4" stroke="#9945FF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
|
348
|
-
</motion.svg>
|
|
349
|
-
)}
|
|
350
|
-
<span className="text-[10px] text-white font-semibold truncate" style={OUTFIT}>{opt.label}</span>
|
|
351
|
-
</div>
|
|
352
|
-
<span className={`text-[10px] font-bold ${isSelected ? "text-white" : "text-[#22E3E8]"}`} style={OUTFIT}>{opt.odds}x</span>
|
|
353
|
-
</div>
|
|
354
|
-
);
|
|
355
|
-
})}
|
|
356
|
-
</div>
|
|
412
|
+
<>
|
|
413
|
+
{renderOptionsGrid(marketA, demoStep >= 2 ? optIdxA : null)}
|
|
414
|
+
<AnimatePresence>
|
|
415
|
+
{demoStep >= 3 && demoStep < 5 && renderChips(betA)}
|
|
416
|
+
</AnimatePresence>
|
|
417
|
+
</>
|
|
357
418
|
) : (
|
|
358
|
-
<div className="flex items-center gap-1.5
|
|
419
|
+
<div className="flex items-center gap-1.5">
|
|
359
420
|
<svg width="10" height="10" viewBox="0 0 16 16" fill="none">
|
|
360
421
|
<circle cx="8" cy="8" r="8" fill="white" />
|
|
361
422
|
<path d="M5 8l2 2 4-4" stroke="#9945FF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
|
@@ -365,184 +426,53 @@ const MarketsSlide = ({ config }: SlideProps) => {
|
|
|
365
426
|
</div>
|
|
366
427
|
)}
|
|
367
428
|
|
|
368
|
-
{
|
|
369
|
-
|
|
370
|
-
{demoStep >= 3 && !card1Compressed && (
|
|
371
|
-
<motion.div
|
|
372
|
-
initial={{ opacity: 0, height: 0 }}
|
|
373
|
-
animate={{ opacity: 1, height: "auto" }}
|
|
374
|
-
exit={{ opacity: 0, height: 0 }}
|
|
375
|
-
transition={{ duration: 0.3 }}
|
|
376
|
-
className="flex items-center gap-1.5 overflow-hidden mt-2"
|
|
377
|
-
>
|
|
378
|
-
<span className="text-[8px] text-white/60 font-semibold flex-shrink-0" style={OUTFIT}>Bet:</span>
|
|
379
|
-
{chips.map((amt, i) => {
|
|
380
|
-
const isChipSelected = demoStep >= 4 && amt === betA;
|
|
381
|
-
return (
|
|
382
|
-
<motion.div
|
|
383
|
-
key={amt}
|
|
384
|
-
initial={{ opacity: 0, scale: 0.8 }}
|
|
385
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
386
|
-
transition={{ delay: i * 0.08 }}
|
|
387
|
-
className="flex items-center gap-0.5 px-2 py-[3px] rounded relative overflow-hidden"
|
|
388
|
-
style={isChipSelected ? {
|
|
389
|
-
background: "linear-gradient(135deg, #22E3E8, #9945FF, #f83cc5)",
|
|
390
|
-
} : {
|
|
391
|
-
background: "rgba(34,227,232,0.08)",
|
|
392
|
-
border: "1px solid rgba(34,227,232,0.2)",
|
|
393
|
-
}}
|
|
394
|
-
>
|
|
395
|
-
<PointsIcon size={7} />
|
|
396
|
-
<span
|
|
397
|
-
className={`text-[9px] font-bold relative z-[1] ${isChipSelected ? "text-black" : "text-[#22E3E8]"}`}
|
|
398
|
-
style={OUTFIT}
|
|
399
|
-
>
|
|
400
|
-
{amt}
|
|
401
|
-
</span>
|
|
402
|
-
</motion.div>
|
|
403
|
-
);
|
|
404
|
-
})}
|
|
405
|
-
</motion.div>
|
|
406
|
-
)}
|
|
407
|
-
</AnimatePresence>
|
|
408
|
-
|
|
409
|
-
{/* Outcome line — Card 1 */}
|
|
410
|
-
{demoStep >= 5 && (
|
|
411
|
-
<motion.div
|
|
412
|
-
initial={{ opacity: 0, y: 4 }}
|
|
413
|
-
animate={{ opacity: 1, y: 0 }}
|
|
414
|
-
transition={{ duration: 0.3 }}
|
|
415
|
-
className="flex items-center gap-[3px] mt-1.5"
|
|
416
|
-
>
|
|
417
|
-
<PointsIcon size={7} />
|
|
418
|
-
<span className="text-[9px] text-white font-semibold" style={OUTFIT}>{betA}</span>
|
|
419
|
-
<span className="text-[8px] text-white/40" style={OUTFIT}>×</span>
|
|
420
|
-
<span className="text-[9px] text-white/60 font-semibold" style={OUTFIT}>{optionA.odds}</span>
|
|
421
|
-
<span className="text-[8px] text-white/40" style={OUTFIT}>=</span>
|
|
422
|
-
<PointsIcon size={7} />
|
|
423
|
-
<span className="text-[9px] text-[#22E3E8] font-bold" style={OUTFIT}>{rewardA}</span>
|
|
424
|
-
</motion.div>
|
|
425
|
-
)}
|
|
426
|
-
</motion.div>
|
|
427
|
-
)}
|
|
428
|
-
</AnimatePresence>
|
|
429
|
+
{demoStep >= 4 && renderOutcome(betA, optionA.odds, rewardA)}
|
|
430
|
+
</div>
|
|
429
431
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
<motion.div
|
|
434
|
-
initial={{ opacity: 0, y: 20 }}
|
|
435
|
-
animate={{ opacity: 1, y: 0 }}
|
|
436
|
-
transition={{ duration: 0.5 }}
|
|
437
|
-
className="w-full rounded-lg px-3 py-3"
|
|
432
|
+
{/* Card 2 */}
|
|
433
|
+
<div
|
|
434
|
+
className="w-full rounded-lg px-3 py-2.5"
|
|
438
435
|
style={{
|
|
439
436
|
background: "rgba(255,255,255,0.03)",
|
|
440
437
|
border: "1px solid rgba(255,255,255,0.08)",
|
|
441
438
|
}}
|
|
442
439
|
>
|
|
443
|
-
<div className="flex items-center gap-2 mb-
|
|
440
|
+
<div className="flex items-center gap-2 mb-1.5">
|
|
444
441
|
{IconB && <IconB size={14} style={{ color: marketB.accent }} className="flex-shrink-0" />}
|
|
445
442
|
<span className="text-[13px] text-white font-semibold leading-tight" style={OUTFIT}>
|
|
446
443
|
{marketB.question}
|
|
447
444
|
</span>
|
|
448
445
|
</div>
|
|
449
446
|
|
|
450
|
-
|
|
451
|
-
{marketB.options.map((opt, j) => {
|
|
452
|
-
const isSelected = demoStep >= 7 && j === optIdxB;
|
|
453
|
-
return (
|
|
454
|
-
<div
|
|
455
|
-
key={j}
|
|
456
|
-
className="flex items-center justify-between px-2 py-1.5 rounded-sm transition-all duration-500"
|
|
457
|
-
style={{
|
|
458
|
-
background: isSelected ? "linear-gradient(135deg, #22E3E8, #9945FF)" : "transparent",
|
|
459
|
-
borderLeft: isSelected ? "1px solid transparent" : "1px solid rgba(255,255,255,0.12)",
|
|
460
|
-
borderBottom: isSelected ? "1px solid transparent" : "1px solid rgba(255,255,255,0.06)",
|
|
461
|
-
borderTop: "1px solid transparent",
|
|
462
|
-
borderRight: "1px solid transparent",
|
|
463
|
-
}}
|
|
464
|
-
>
|
|
465
|
-
<div className="flex items-center gap-1.5">
|
|
466
|
-
{isSelected && (
|
|
467
|
-
<motion.svg
|
|
468
|
-
initial={{ scale: 0 }}
|
|
469
|
-
animate={{ scale: 1 }}
|
|
470
|
-
transition={{ type: "spring", stiffness: 400, damping: 15 }}
|
|
471
|
-
width="10" height="10" viewBox="0 0 16 16" fill="none"
|
|
472
|
-
>
|
|
473
|
-
<circle cx="8" cy="8" r="8" fill="white" />
|
|
474
|
-
<path d="M5 8l2 2 4-4" stroke="#9945FF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
|
475
|
-
</motion.svg>
|
|
476
|
-
)}
|
|
477
|
-
<span className="text-[10px] text-white font-semibold truncate" style={OUTFIT}>{opt.label}</span>
|
|
478
|
-
</div>
|
|
479
|
-
<span className={`text-[10px] font-bold ${isSelected ? "text-white" : "text-[#22E3E8]"}`} style={OUTFIT}>{opt.odds}x</span>
|
|
480
|
-
</div>
|
|
481
|
-
);
|
|
482
|
-
})}
|
|
483
|
-
</div>
|
|
447
|
+
{renderOptionsGrid(marketB, demoStep >= 5 ? optIdxB : null)}
|
|
484
448
|
|
|
485
|
-
{/* Chip carousel — Card 2 */}
|
|
486
449
|
<AnimatePresence>
|
|
487
|
-
{demoStep >=
|
|
488
|
-
<motion.div
|
|
489
|
-
initial={{ opacity: 0, height: 0 }}
|
|
490
|
-
animate={{ opacity: 1, height: "auto" }}
|
|
491
|
-
exit={{ opacity: 0, height: 0 }}
|
|
492
|
-
transition={{ duration: 0.3 }}
|
|
493
|
-
className="flex items-center gap-1.5 overflow-hidden mt-2"
|
|
494
|
-
>
|
|
495
|
-
<span className="text-[8px] text-white/60 font-semibold flex-shrink-0" style={OUTFIT}>Bet:</span>
|
|
496
|
-
{chips.map((amt, i) => {
|
|
497
|
-
const isChipSelected = demoStep >= 9 && amt === betB;
|
|
498
|
-
return (
|
|
499
|
-
<motion.div
|
|
500
|
-
key={amt}
|
|
501
|
-
initial={{ opacity: 0, scale: 0.8 }}
|
|
502
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
503
|
-
transition={{ delay: i * 0.08 }}
|
|
504
|
-
className="flex items-center gap-0.5 px-2 py-[3px] rounded relative overflow-hidden"
|
|
505
|
-
style={isChipSelected ? {
|
|
506
|
-
background: "linear-gradient(135deg, #22E3E8, #9945FF, #f83cc5)",
|
|
507
|
-
} : {
|
|
508
|
-
background: "rgba(34,227,232,0.08)",
|
|
509
|
-
border: "1px solid rgba(34,227,232,0.2)",
|
|
510
|
-
}}
|
|
511
|
-
>
|
|
512
|
-
<PointsIcon size={7} />
|
|
513
|
-
<span
|
|
514
|
-
className={`text-[9px] font-bold relative z-[1] ${isChipSelected ? "text-black" : "text-[#22E3E8]"}`}
|
|
515
|
-
style={OUTFIT}
|
|
516
|
-
>
|
|
517
|
-
{amt}
|
|
518
|
-
</span>
|
|
519
|
-
</motion.div>
|
|
520
|
-
);
|
|
521
|
-
})}
|
|
522
|
-
</motion.div>
|
|
523
|
-
)}
|
|
450
|
+
{demoStep >= 6 && renderChips(betB)}
|
|
524
451
|
</AnimatePresence>
|
|
525
452
|
|
|
526
|
-
{
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
453
|
+
{demoStep >= 7 && renderOutcome(betB, optionB.odds, rewardB)}
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
{/* Card 3 — always unselected */}
|
|
457
|
+
<div
|
|
458
|
+
className="w-full rounded-lg px-3 py-2.5"
|
|
459
|
+
style={{
|
|
460
|
+
background: "rgba(255,255,255,0.03)",
|
|
461
|
+
border: "1px solid rgba(255,255,255,0.08)",
|
|
462
|
+
opacity: demoStep >= 2 ? 0.5 : 1,
|
|
463
|
+
transition: "opacity 0.5s",
|
|
464
|
+
}}
|
|
465
|
+
>
|
|
466
|
+
<div className="flex items-center gap-2 mb-1.5">
|
|
467
|
+
{IconC && <IconC size={14} style={{ color: marketC.accent }} className="flex-shrink-0" />}
|
|
468
|
+
<span className="text-[13px] text-white font-semibold leading-tight" style={OUTFIT}>
|
|
469
|
+
{marketC.question}
|
|
470
|
+
</span>
|
|
471
|
+
</div>
|
|
472
|
+
{renderOptionsGrid(marketC, null)}
|
|
473
|
+
</div>
|
|
474
|
+
</motion.div>
|
|
475
|
+
)}
|
|
546
476
|
</motion.div>
|
|
547
477
|
);
|
|
548
478
|
};
|
|
@@ -564,10 +494,33 @@ const MultiplierSlide = ({ config }: SlideProps) => {
|
|
|
564
494
|
return () => timers.forEach(clearTimeout);
|
|
565
495
|
}, []);
|
|
566
496
|
|
|
567
|
-
const { marketA, marketB, optionA, optionB, betA, betB, rewardA, rewardB, combinedStake, combinedOdds, combinedReward
|
|
497
|
+
const { marketA, marketB, optionA, optionB, betA, betB, rewardA, rewardB, combinedStake, combinedOdds, combinedReward } = demo;
|
|
568
498
|
const IconA = MARKET_ICONS[marketA.icon];
|
|
569
499
|
const IconB = MARKET_ICONS[marketB.icon];
|
|
570
|
-
|
|
500
|
+
|
|
501
|
+
// Shared outcome line — identical style for individual and combined
|
|
502
|
+
const renderOutcomeLine = (bet: number, odds: string, reward: number, pulse?: boolean) => (
|
|
503
|
+
<div className="flex items-center gap-[5px]">
|
|
504
|
+
<PointsIcon size={10} />
|
|
505
|
+
<span className="text-[12px] text-white font-semibold" style={OUTFIT}>{bet}</span>
|
|
506
|
+
<span className="text-[11px] text-white font-medium" style={OUTFIT}>×</span>
|
|
507
|
+
{pulse ? (
|
|
508
|
+
<motion.span
|
|
509
|
+
className="text-[12px] text-white font-bold"
|
|
510
|
+
style={OUTFIT}
|
|
511
|
+
animate={{ scale: [1, 1.25, 1] }}
|
|
512
|
+
transition={{ duration: 0.5, delay: 0.2 }}
|
|
513
|
+
>
|
|
514
|
+
{odds}
|
|
515
|
+
</motion.span>
|
|
516
|
+
) : (
|
|
517
|
+
<span className="text-[12px] text-white font-bold" style={OUTFIT}>{odds}</span>
|
|
518
|
+
)}
|
|
519
|
+
<span className="text-[11px] text-white/50" style={OUTFIT}>{"\u2192"}</span>
|
|
520
|
+
<PointsIcon size={10} />
|
|
521
|
+
<span className="text-[12px] text-[#22E3E8] font-bold" style={OUTFIT}>{reward}</span>
|
|
522
|
+
</div>
|
|
523
|
+
);
|
|
571
524
|
|
|
572
525
|
const renderCompactCard = (
|
|
573
526
|
market: typeof marketA,
|
|
@@ -594,7 +547,7 @@ const MultiplierSlide = ({ config }: SlideProps) => {
|
|
|
594
547
|
{Icon && <Icon size={12} style={{ color: market.accent }} className="flex-shrink-0" />}
|
|
595
548
|
<span className="text-[11px] text-white font-semibold leading-tight truncate" style={OUTFIT}>{market.question}</span>
|
|
596
549
|
</div>
|
|
597
|
-
<div className="flex items-center gap-1.5 mb-1">
|
|
550
|
+
<div className="flex items-center gap-1.5 mb-1.5">
|
|
598
551
|
<div
|
|
599
552
|
className="flex items-center gap-1 px-2 py-[2px] rounded-sm"
|
|
600
553
|
style={{ background: "linear-gradient(135deg, #22E3E8, #9945FF)" }}
|
|
@@ -604,17 +557,11 @@ const MultiplierSlide = ({ config }: SlideProps) => {
|
|
|
604
557
|
<span className="text-[9px] text-white/50 font-semibold" style={OUTFIT}>at {option.odds}x</span>
|
|
605
558
|
</div>
|
|
606
559
|
<motion.div
|
|
607
|
-
className="
|
|
560
|
+
className="overflow-hidden"
|
|
608
561
|
animate={{ opacity: hideOutcome ? 0 : 1, height: hideOutcome ? 0 : "auto" }}
|
|
609
562
|
transition={{ duration: 0.3 }}
|
|
610
563
|
>
|
|
611
|
-
|
|
612
|
-
<span className="text-[9px] text-white font-semibold" style={OUTFIT}>{betAmount}</span>
|
|
613
|
-
<span className="text-[8px] text-white/40" style={OUTFIT}>×</span>
|
|
614
|
-
<span className="text-[9px] text-white/60 font-semibold" style={OUTFIT}>{option.odds}</span>
|
|
615
|
-
<span className="text-[8px] text-white/40" style={OUTFIT}>=</span>
|
|
616
|
-
<PointsIcon size={7} />
|
|
617
|
-
<span className="text-[9px] text-[#22E3E8] font-bold" style={OUTFIT}>{reward}</span>
|
|
564
|
+
{renderOutcomeLine(betAmount, String(option.odds), reward)}
|
|
618
565
|
</motion.div>
|
|
619
566
|
</motion.div>
|
|
620
567
|
);
|
|
@@ -632,10 +579,10 @@ const MultiplierSlide = ({ config }: SlideProps) => {
|
|
|
632
579
|
initial={{ opacity: 0, y: 16 }}
|
|
633
580
|
animate={{ opacity: 1, y: 0 }}
|
|
634
581
|
transition={{ duration: 0.4 }}
|
|
635
|
-
className="text-[15px] text-white font-
|
|
582
|
+
className="text-[15px] text-white font-semibold"
|
|
636
583
|
style={OUTFIT}
|
|
637
584
|
>
|
|
638
|
-
|
|
585
|
+
Stack predictions. Multiply returns.
|
|
639
586
|
</motion.p>
|
|
640
587
|
)}
|
|
641
588
|
|
|
@@ -658,24 +605,26 @@ const MultiplierSlide = ({ config }: SlideProps) => {
|
|
|
658
605
|
initial={{ opacity: 0, y: 10 }}
|
|
659
606
|
animate={{ opacity: 1, y: 0 }}
|
|
660
607
|
transition={{ duration: 0.4 }}
|
|
661
|
-
className="w-full flex flex-col items-center gap-
|
|
608
|
+
className="w-full flex flex-col items-center gap-2 pt-2"
|
|
662
609
|
>
|
|
663
|
-
<span className="text-[
|
|
664
|
-
<div className="flex items-center gap-[
|
|
665
|
-
<PointsIcon size={
|
|
666
|
-
<span className="text-[
|
|
667
|
-
<span className="text-[
|
|
610
|
+
<span className="text-[10px] text-white/40 uppercase tracking-widest font-semibold" style={OUTFIT}>Combined multiplier</span>
|
|
611
|
+
<div className="flex items-center gap-[6px]">
|
|
612
|
+
<PointsIcon size={12} />
|
|
613
|
+
<span className="text-[15px] text-white font-semibold" style={OUTFIT}>{combinedStake}</span>
|
|
614
|
+
<span className="text-[13px] text-white font-medium" style={OUTFIT}>×</span>
|
|
668
615
|
<motion.span
|
|
669
|
-
className="text-[
|
|
616
|
+
className="text-[15px] text-white font-bold"
|
|
670
617
|
style={OUTFIT}
|
|
671
618
|
animate={{ scale: [1, 1.25, 1] }}
|
|
672
619
|
transition={{ duration: 0.5, delay: 0.2 }}
|
|
673
620
|
>
|
|
674
|
-
{
|
|
621
|
+
{optionA.odds}
|
|
675
622
|
</motion.span>
|
|
676
|
-
<span className="text-[
|
|
677
|
-
<
|
|
678
|
-
<span className="text-[
|
|
623
|
+
<span className="text-[13px] text-white font-medium" style={OUTFIT}>×</span>
|
|
624
|
+
<span className="text-[15px] text-white font-bold" style={OUTFIT}>{optionB.odds}</span>
|
|
625
|
+
<span className="text-[13px] text-white/50" style={OUTFIT}>{"\u2192"}</span>
|
|
626
|
+
<PointsIcon size={12} />
|
|
627
|
+
<span className="text-[15px] text-[#22E3E8] font-bold" style={OUTFIT}>{combinedReward}</span>
|
|
679
628
|
</div>
|
|
680
629
|
</motion.div>
|
|
681
630
|
)}
|
|
@@ -686,14 +635,11 @@ const MultiplierSlide = ({ config }: SlideProps) => {
|
|
|
686
635
|
initial={{ opacity: 0, y: 10 }}
|
|
687
636
|
animate={{ opacity: 1, y: 0 }}
|
|
688
637
|
transition={{ duration: 0.4 }}
|
|
689
|
-
className="
|
|
638
|
+
className="pt-1"
|
|
690
639
|
>
|
|
691
640
|
<p className="text-[14px] text-white/70 font-medium text-center" style={OUTFIT}>
|
|
692
641
|
Combine more predictions. Multiply further.
|
|
693
642
|
</p>
|
|
694
|
-
<p className="text-[12px] text-white/40 font-medium text-center" style={OUTFIT}>
|
|
695
|
-
Up to {maxMult}x with all {config.markets.length} questions
|
|
696
|
-
</p>
|
|
697
643
|
</motion.div>
|
|
698
644
|
)}
|
|
699
645
|
</motion.div>
|