@devrongx/games 0.3.4 → 0.3.5

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrongx/games",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Game UI components for sports prediction markets",
5
5
  "license": "MIT",
6
6
  "main": "./src/index.ts",
@@ -6,7 +6,7 @@ import Image from "next/image";
6
6
  import { motion, AnimatePresence, useSpring, useTransform, useMotionValue } from "framer-motion";
7
7
  import { ChevronDown, Info, X, Play } from "lucide-react";
8
8
  import { IBetSummary, ILeaderboardEntry, IChallengeConfig, IUserBets, deriveParlayGroups, deriveMarketToParlay, calcDisplayReward, optionReward, calcParlayMultiplier } from "./config";
9
- import { OUTFIT, MARKET_ICONS, PointsIcon, SelectedCheck } from "./constants";
9
+ import { OUTFIT, MARKET_ICONS, PointsIcon, SelectedCheck, AiInsightButton } from "./constants";
10
10
  import { useGamePopupStore } from "../../core/gamePopupStore";
11
11
  import { LeaderboardRow } from "./LeaderboardRow";
12
12
 
@@ -355,6 +355,14 @@ export const PreMatchGame = ({ config, bets, onBetsChange, expandedPicker, onOpt
355
355
  );
356
356
  })}
357
357
 
358
+ {/* AI Insights button — right-aligned, below options */}
359
+ <div className="col-span-2 flex justify-end pr-4 mt-3">
360
+ <AiInsightButton
361
+ question={market.question}
362
+ options={market.options.map(o => o.label)}
363
+ />
364
+ </div>
365
+
358
366
  {/* Amount picker — inline chip carousel (always reserves height when picker is open) */}
359
367
  {isPickerOpenForMarket && (
360
368
  <div className="col-span-2 mt-0.5 relative">
@@ -5,7 +5,7 @@ import { useState, useCallback, useEffect } from "react";
5
5
  import { motion, AnimatePresence } from "framer-motion";
6
6
  import { Check, Rewind, FastForward, ArrowRight } from "lucide-react";
7
7
  import { IChallengeConfig, IChallengeMarket, IUserBets } from "./config";
8
- import { OUTFIT, MARKET_ICONS, PointsIcon } from "./constants";
8
+ import { OUTFIT, MARKET_ICONS, PointsIcon, AiInsightButton } from "./constants";
9
9
  import { useGamePopupStore } from "../../core/gamePopupStore";
10
10
 
11
11
  interface PreMatchQuestionsProps {
@@ -80,6 +80,62 @@ const StartSlide = ({ onStart }: { onStart: () => void }) => {
80
80
  );
81
81
  };
82
82
 
83
+ // ── Points hint + locked carousel (hidden for now — uncomment when points flow is live) ──
84
+ // const QuestionPointsHint = ({
85
+ // market,
86
+ // startingBalance,
87
+ // stakeIncrements,
88
+ // }: {
89
+ // market: IChallengeMarket;
90
+ // startingBalance: number;
91
+ // stakeIncrements: number;
92
+ // }) => {
93
+ // const chipCount = Math.floor(startingBalance / stakeIncrements);
94
+ // return (
95
+ // <motion.div
96
+ // initial={{ opacity: 0, y: 14 }}
97
+ // animate={{ opacity: 1, y: 0 }}
98
+ // transition={{ duration: 0.5, delay: 0.6 }}
99
+ // className="w-full mt-8 flex flex-col gap-2.5 -mx-5"
100
+ // style={{ width: "calc(100% + 40px)", paddingLeft: 20 }}
101
+ // >
102
+ // <p className="text-[11px] text-white font-medium leading-relaxed" style={OUTFIT}>
103
+ // Pick using your cricket knowledge — the{" "}
104
+ // <span className="text-[#22E3E8] font-bold">{market.options[0].odds}x</span>
105
+ // {" "}
106
+ // <PointsIcon size={11} className="inline-block align-text-bottom" />
107
+ // {" "}multiplier next to each option is how much your points grow if you{"'"}re right.
108
+ // </p>
109
+ // <p className="text-[11px] text-white/70 font-medium" style={OUTFIT}>
110
+ // How many points to bet? You{"'"}ll decide that next.
111
+ // </p>
112
+ // {/* Locked chips carousel — extends past right edge */}
113
+ // <div className="relative mt-0.5 overflow-hidden" style={{ marginRight: -20 }}>
114
+ // <div className="flex items-center gap-1.5 py-1 opacity-40">
115
+ // {Array.from({ length: chipCount }, (_, i) => (i + 1) * stakeIncrements).map(amt => (
116
+ // <div
117
+ // key={amt}
118
+ // className="flex-shrink-0 flex items-center gap-0.5 px-2.5 py-[4px] rounded"
119
+ // style={{
120
+ // background: "rgba(34,227,232,0.08)",
121
+ // border: "1px solid rgba(34,227,232,0.15)",
122
+ // }}
123
+ // >
124
+ // <PointsIcon size={8} />
125
+ // <span className="text-[9px] font-bold text-[#22E3E8]" style={OUTFIT}>{amt}</span>
126
+ // </div>
127
+ // ))}
128
+ // </div>
129
+ // {/* Right fade */}
130
+ // <div
131
+ // className="absolute inset-y-0 right-0 w-20 pointer-events-none"
132
+ // style={{ background: "linear-gradient(90deg, transparent 0%, rgba(0,0,0,0.85) 70%, black 100%)" }}
133
+ // />
134
+ // </div>
135
+ // </motion.div>
136
+ // );
137
+ // };
138
+
83
139
  // ── Single question slide ──
84
140
  const QuestionSlide = ({
85
141
  market,
@@ -95,6 +151,7 @@ const QuestionSlide = ({
95
151
  stakeIncrements: number;
96
152
  }) => {
97
153
  const chipCount = Math.floor(startingBalance / stakeIncrements);
154
+ void chipCount; // unused while QuestionPointsHint is hidden
98
155
  const IconComponent = MARKET_ICONS[market.icon];
99
156
 
100
157
  return (
@@ -190,50 +247,17 @@ const QuestionSlide = ({
190
247
  })}
191
248
  </motion.div>
192
249
 
193
- {/* Hint text + locked points carousel */}
250
+ {/* AI Insights button right-aligned, below options */}
194
251
  <motion.div
195
- initial={{ opacity: 0, y: 14 }}
196
- animate={{ opacity: 1, y: 0 }}
197
- transition={{ duration: 0.5, delay: 0.6 }}
198
- className="w-full mt-8 flex flex-col gap-2.5 -mx-5"
199
- style={{ width: "calc(100% + 40px)", paddingLeft: 20 }}
252
+ initial={{ opacity: 0 }}
253
+ animate={{ opacity: 1 }}
254
+ transition={{ duration: 0.4, delay: 0.55 }}
255
+ className="w-full max-w-[320px] flex justify-end pr-4 mt-8"
200
256
  >
201
- <p className="text-[11px] text-white font-medium leading-relaxed" style={OUTFIT}>
202
- Pick using your cricket knowledge — the{" "}
203
- <span className="text-[#22E3E8] font-bold">{market.options[0].odds}x</span>
204
- {" "}
205
- <PointsIcon size={11} className="inline-block align-text-bottom" />
206
- {" "}multiplier next to each option is how much your points grow if you{"'"}re right.
207
- </p>
208
- <p className="text-[11px] text-white/70 font-medium" style={OUTFIT}>
209
- How many points to bet? You{"'"}ll decide that next.
210
- </p>
211
-
212
- {/* Locked chips carousel — extends past right edge.
213
- Chips have reduced opacity directly so there's no flash before blur loads. */}
214
- <div className="relative mt-0.5 overflow-hidden" style={{ marginRight: -20 }}>
215
- <div className="flex items-center gap-1.5 py-1 opacity-40">
216
- {Array.from({ length: chipCount }, (_, i) => (i + 1) * stakeIncrements).map(amt => (
217
- <div
218
- key={amt}
219
- className="flex-shrink-0 flex items-center gap-0.5 px-2.5 py-[4px] rounded"
220
- style={{
221
- background: "rgba(34,227,232,0.08)",
222
- border: "1px solid rgba(34,227,232,0.15)",
223
- }}
224
- >
225
- <PointsIcon size={8} />
226
- <span className="text-[9px] font-bold text-[#22E3E8]" style={OUTFIT}>{amt}</span>
227
- </div>
228
- ))}
229
- </div>
230
- {/* Right fade — vanishes into the edge */}
231
- <div
232
- className="absolute inset-y-0 right-0 w-20 pointer-events-none"
233
- style={{ background: "linear-gradient(90deg, transparent 0%, rgba(0,0,0,0.85) 70%, black 100%)" }}
234
- />
235
- </div>
257
+ <AiInsightButton question={market.question} options={market.options.map(o => o.label)} />
236
258
  </motion.div>
259
+
260
+ {/* <QuestionPointsHint market={market} startingBalance={startingBalance} stakeIncrements={stakeIncrements} /> */}
237
261
  </div>
238
262
  );
239
263
  };
@@ -2,7 +2,7 @@
2
2
  // Shared constants and micro-components for IPL betting UI.
3
3
 
4
4
  import Image from "next/image";
5
- import { Coins, Trophy, Swords, Square, Zap, Target, BarChart3, Star } from "lucide-react";
5
+ import { Coins, Trophy, Swords, Square, Zap, Target, BarChart3, Star, ArrowUpRight } from "lucide-react";
6
6
 
7
7
  /** Font style applied to all betting UI text */
8
8
  export const OUTFIT = { fontFamily: "Outfit, sans-serif" } as const;
@@ -31,3 +31,41 @@ export const SelectedCheck = ({ size = 10 }: { size?: number }) => (
31
31
  <path d="M5 8l2 2 4-4" stroke="#9945FF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
32
32
  </svg>
33
33
  );
34
+
35
+ /** Build iplgpt.com URL with question + options pre-filled */
36
+ export const buildIplGptUrl = (question: string, options: string[]) => {
37
+ const params = new URLSearchParams({ q: question, opts: options.join(",") });
38
+ return `https://www.iplgpt.com/?${params.toString()}`;
39
+ };
40
+
41
+ /**
42
+ * AI Insights button — solid cyan, floating rounded pill, Sparkles icon only.
43
+ * Redirects to iplgpt.com with question + options pre-filled in the query string.
44
+ */
45
+ export const AiInsightButton = ({
46
+ question,
47
+ options,
48
+ onClick,
49
+ }: {
50
+ question: string;
51
+ options: string[];
52
+ onClick?: (e: React.MouseEvent) => void;
53
+ }) => (
54
+ <a
55
+ href={buildIplGptUrl(question, options)}
56
+ target="_blank"
57
+ rel="noopener noreferrer"
58
+ onClick={(e) => { e.stopPropagation(); onClick?.(e); }}
59
+ className="inline-flex items-center gap-[3px] select-none"
60
+ style={{
61
+ borderBottom: "1px dotted rgba(34,227,232,0.9)",
62
+ paddingBottom: 2,
63
+ textDecoration: "none",
64
+ }}
65
+ >
66
+ <span className="text-[11px] font-semibold" style={{ ...OUTFIT, color: "#22E3E8", letterSpacing: "0.02em" }}>
67
+ Expert Insight
68
+ </span>
69
+ <ArrowUpRight size={12} style={{ color: "#22E3E8", flexShrink: 0 }} />
70
+ </a>
71
+ );