@stargazeryan/poker-ui 0.5.0 → 0.6.0
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/README.md +182 -13
- package/dist/index.cjs +708 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +499 -23
- package/dist/index.d.ts +499 -23
- package/dist/index.js +661 -168
- package/dist/index.js.map +1 -1
- package/package.json +27 -7
- package/src/styles.css +128 -95
package/dist/index.cjs
CHANGED
|
@@ -22,22 +22,62 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
BB: () => BB,
|
|
25
|
+
COUNT_UP_MS: () => COUNT_UP_MS,
|
|
25
26
|
CardBack: () => CardBack,
|
|
26
27
|
CardTable: () => CardTable,
|
|
28
|
+
Chip: () => Chip,
|
|
29
|
+
ChipStack: () => ChipStack,
|
|
27
30
|
CommunityCards: () => CommunityCards,
|
|
31
|
+
DEAL_STAGGER_MS: () => DEAL_STAGGER_MS,
|
|
32
|
+
DEFAULT_BET_SCALE: () => DEFAULT_BET_SCALE,
|
|
33
|
+
DEFAULT_DENOMINATIONS: () => DEFAULT_DENOMINATIONS,
|
|
34
|
+
DEFAULT_FELT_GAP: () => DEFAULT_FELT_GAP,
|
|
35
|
+
DEFAULT_MARGIN_X: () => DEFAULT_MARGIN_X,
|
|
36
|
+
DEFAULT_MARGIN_Y: () => DEFAULT_MARGIN_Y,
|
|
37
|
+
DEFAULT_SEAT_GAP: () => DEFAULT_SEAT_GAP,
|
|
38
|
+
DEFAULT_SEAT_H: () => DEFAULT_SEAT_H,
|
|
39
|
+
DEFAULT_SEAT_W: () => DEFAULT_SEAT_W,
|
|
40
|
+
DESIGN_H: () => DESIGN_H,
|
|
41
|
+
DESIGN_W: () => DESIGN_W,
|
|
42
|
+
FLIP_STAGGER_MS: () => FLIP_STAGGER_MS,
|
|
43
|
+
GLOW_GAP: () => GLOW_GAP,
|
|
28
44
|
HoleCards: () => HoleCards,
|
|
29
45
|
PlayingCard: () => PlayingCard,
|
|
30
46
|
PokerTable: () => CardTable,
|
|
31
47
|
Pot: () => Pot,
|
|
48
|
+
RIM_GAP: () => RIM_GAP,
|
|
49
|
+
SEAT_SHRINK_FLOOR: () => SEAT_SHRINK_FLOOR,
|
|
50
|
+
SIZES: () => SIZES,
|
|
32
51
|
Seat: () => Seat,
|
|
52
|
+
chipBreakdown: () => chipBreakdown,
|
|
53
|
+
chipCount: () => chipCount,
|
|
54
|
+
chipSpotColor: () => chipSpotColor,
|
|
55
|
+
chipsTotal: () => chipsTotal,
|
|
33
56
|
cn: () => cn,
|
|
57
|
+
contrastRatio: () => contrastRatio,
|
|
58
|
+
describeCard: () => describeCard,
|
|
59
|
+
ellipseBox: () => ellipseBox,
|
|
34
60
|
ellipsePoint: () => ellipsePoint,
|
|
61
|
+
fitSeatScale: () => fitSeatScale,
|
|
62
|
+
flatten: () => flatten,
|
|
35
63
|
formatBB: () => formatBB,
|
|
64
|
+
getRankName: () => getRankName,
|
|
65
|
+
getSuitName: () => getSuitName,
|
|
36
66
|
getSuitSymbol: () => getSuitSymbol,
|
|
67
|
+
isKnownSuit: () => isKnownSuit,
|
|
68
|
+
isRedSuit: () => isRedSuit,
|
|
69
|
+
layoutSeats: () => layoutSeats,
|
|
70
|
+
minSeatSeparation: () => minSeatSeparation,
|
|
71
|
+
mostVisible: () => mostVisible,
|
|
37
72
|
nextSeatIndex: () => nextSeatIndex,
|
|
38
73
|
parseCard: () => parseCard,
|
|
74
|
+
parseColor: () => parseColor,
|
|
75
|
+
relativeLuminance: () => relativeLuminance,
|
|
39
76
|
ringPoints: () => ringPoints,
|
|
40
|
-
seatAngle: () => seatAngle
|
|
77
|
+
seatAngle: () => seatAngle,
|
|
78
|
+
seatPoint: () => seatPoint,
|
|
79
|
+
seatRingRadii: () => seatRingRadii,
|
|
80
|
+
tableRadii: () => tableRadii
|
|
41
81
|
});
|
|
42
82
|
module.exports = __toCommonJS(index_exports);
|
|
43
83
|
|
|
@@ -49,17 +89,147 @@ function cn(...parts) {
|
|
|
49
89
|
|
|
50
90
|
// src/format.ts
|
|
51
91
|
var BB = 20;
|
|
52
|
-
function formatBB(amount) {
|
|
53
|
-
const
|
|
54
|
-
return `${Number.isInteger(
|
|
92
|
+
function formatBB(amount, bb = BB) {
|
|
93
|
+
const value = amount / bb;
|
|
94
|
+
return `${Number.isInteger(value) ? value : value.toFixed(1)} BB`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/color.ts
|
|
98
|
+
function parseColor(color) {
|
|
99
|
+
const input = color.trim();
|
|
100
|
+
const hex = input.match(/^#([0-9a-f]{3,8})$/i);
|
|
101
|
+
if (hex) {
|
|
102
|
+
const raw = hex[1];
|
|
103
|
+
if (raw.length === 3 || raw.length === 4) {
|
|
104
|
+
const [r, g, b, a] = raw.split("").map((c) => parseInt(c + c, 16));
|
|
105
|
+
return { r, g, b, a: raw.length === 4 ? a / 255 : 1 };
|
|
106
|
+
}
|
|
107
|
+
if (raw.length === 6 || raw.length === 8) {
|
|
108
|
+
return {
|
|
109
|
+
r: parseInt(raw.slice(0, 2), 16),
|
|
110
|
+
g: parseInt(raw.slice(2, 4), 16),
|
|
111
|
+
b: parseInt(raw.slice(4, 6), 16),
|
|
112
|
+
a: raw.length === 8 ? parseInt(raw.slice(6, 8), 16) / 255 : 1
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const fn = input.match(/^rgba?\(([^)]+)\)$/i);
|
|
118
|
+
if (!fn) return null;
|
|
119
|
+
const parts = fn[1].split(/[,\s/]+/).filter(Boolean).map(Number);
|
|
120
|
+
if (parts.length < 3 || parts.slice(0, 3).some((n) => !Number.isFinite(n))) return null;
|
|
121
|
+
return { r: parts[0], g: parts[1], b: parts[2], a: Number.isFinite(parts[3]) ? parts[3] : 1 };
|
|
122
|
+
}
|
|
123
|
+
function relativeLuminance(color) {
|
|
124
|
+
const parsed = parseColor(color);
|
|
125
|
+
if (!parsed) return null;
|
|
126
|
+
const channel = (c) => {
|
|
127
|
+
const s = Math.min(255, Math.max(0, c)) / 255;
|
|
128
|
+
return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
129
|
+
};
|
|
130
|
+
return 0.2126 * channel(parsed.r) + 0.7152 * channel(parsed.g) + 0.0722 * channel(parsed.b);
|
|
131
|
+
}
|
|
132
|
+
function flatten(foreground, background) {
|
|
133
|
+
const fg = parseColor(foreground);
|
|
134
|
+
const bg = parseColor(background);
|
|
135
|
+
if (!fg || !bg) return null;
|
|
136
|
+
const mix = (f, b) => fg.a * f + (1 - fg.a) * b;
|
|
137
|
+
return { r: mix(fg.r, bg.r), g: mix(fg.g, bg.g), b: mix(fg.b, bg.b), a: 1 };
|
|
138
|
+
}
|
|
139
|
+
function contrastRatio(foreground, background) {
|
|
140
|
+
const composited = flatten(foreground, background);
|
|
141
|
+
if (!composited) return null;
|
|
142
|
+
const a = relativeLuminance(`rgb(${composited.r}, ${composited.g}, ${composited.b})`);
|
|
143
|
+
const b = relativeLuminance(background);
|
|
144
|
+
if (a === null || b === null) return null;
|
|
145
|
+
const [hi, lo] = a > b ? [a, b] : [b, a];
|
|
146
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
147
|
+
}
|
|
148
|
+
function mostVisible(candidates, background) {
|
|
149
|
+
let best = candidates[0];
|
|
150
|
+
let bestRatio = -1;
|
|
151
|
+
for (const candidate of candidates) {
|
|
152
|
+
const ratio = contrastRatio(candidate, background);
|
|
153
|
+
if (ratio !== null && ratio > bestRatio) {
|
|
154
|
+
best = candidate;
|
|
155
|
+
bestRatio = ratio;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return best;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/sizes.ts
|
|
162
|
+
var SIZES = ["xs", "sm", "md", "lg"];
|
|
163
|
+
|
|
164
|
+
// src/motion.ts
|
|
165
|
+
var COUNT_UP_MS = 500;
|
|
166
|
+
var DEAL_STAGGER_MS = 100;
|
|
167
|
+
var FLIP_STAGGER_MS = 70;
|
|
168
|
+
|
|
169
|
+
// src/cards.ts
|
|
170
|
+
var RANK_NAMES = {
|
|
171
|
+
A: "Ace",
|
|
172
|
+
K: "King",
|
|
173
|
+
Q: "Queen",
|
|
174
|
+
J: "Jack",
|
|
175
|
+
"10": "Ten",
|
|
176
|
+
"9": "Nine",
|
|
177
|
+
"8": "Eight",
|
|
178
|
+
"7": "Seven",
|
|
179
|
+
"6": "Six",
|
|
180
|
+
"5": "Five",
|
|
181
|
+
"4": "Four",
|
|
182
|
+
"3": "Three",
|
|
183
|
+
"2": "Two"
|
|
184
|
+
};
|
|
185
|
+
var SUIT_NAMES = {
|
|
186
|
+
s: "spades",
|
|
187
|
+
h: "hearts",
|
|
188
|
+
d: "diamonds",
|
|
189
|
+
c: "clubs"
|
|
190
|
+
};
|
|
191
|
+
var SUIT_SYMBOLS = {
|
|
192
|
+
s: "\u2660",
|
|
193
|
+
h: "\u2665",
|
|
194
|
+
d: "\u2666",
|
|
195
|
+
c: "\u2663"
|
|
196
|
+
};
|
|
197
|
+
function parseCard(card) {
|
|
198
|
+
if (!card || card.length < 2) return { rank: "", suit: "" };
|
|
199
|
+
return { rank: card.slice(0, -1), suit: card.slice(-1).toLowerCase() };
|
|
200
|
+
}
|
|
201
|
+
function getSuitSymbol(suit) {
|
|
202
|
+
return SUIT_SYMBOLS[suit.toLowerCase()] ?? suit;
|
|
203
|
+
}
|
|
204
|
+
function getRankName(rank) {
|
|
205
|
+
return RANK_NAMES[rank.toUpperCase()] ?? rank;
|
|
206
|
+
}
|
|
207
|
+
function getSuitName(suit) {
|
|
208
|
+
return SUIT_NAMES[suit.toLowerCase()] ?? suit;
|
|
209
|
+
}
|
|
210
|
+
function isRedSuit(suit) {
|
|
211
|
+
const s = suit.toLowerCase();
|
|
212
|
+
return s === "h" || s === "d";
|
|
213
|
+
}
|
|
214
|
+
function isKnownSuit(suit) {
|
|
215
|
+
return suit.toLowerCase() in SUIT_SYMBOLS;
|
|
216
|
+
}
|
|
217
|
+
function describeCard(card) {
|
|
218
|
+
if (card === null || card === "") return "face-down card";
|
|
219
|
+
const { rank, suit } = parseCard(card);
|
|
220
|
+
const rankName = RANK_NAMES[rank.toUpperCase()];
|
|
221
|
+
const suitName = SUIT_NAMES[suit];
|
|
222
|
+
if (!rankName || !suitName) return card;
|
|
223
|
+
return `${rankName} of ${suitName}`;
|
|
55
224
|
}
|
|
56
225
|
|
|
57
226
|
// src/seat.ts
|
|
58
227
|
function nextSeatIndex(current, seatCount, opts = {}) {
|
|
59
|
-
const
|
|
228
|
+
const floored = Math.floor(seatCount);
|
|
229
|
+
const n = Number.isFinite(floored) && floored > 0 ? floored : 1;
|
|
60
230
|
const dir = opts.dir ?? 1;
|
|
61
231
|
const skip = opts.skip;
|
|
62
|
-
const start = (Math.floor(current) % n + n) % n;
|
|
232
|
+
const start = ((Math.floor(current) || 0) % n + n) % n;
|
|
63
233
|
let i = start;
|
|
64
234
|
for (let step = 0; step < n - 1; step++) {
|
|
65
235
|
i = (i + dir + n) % n;
|
|
@@ -86,6 +256,112 @@ function ringPoints(count, cx, cy, rx, ry, startAngle = 90) {
|
|
|
86
256
|
return Array.from({ length: n }, (_, i) => ellipsePoint(cx, cy, rx, ry, seatAngle(i, n, startAngle)));
|
|
87
257
|
}
|
|
88
258
|
|
|
259
|
+
// src/layout.ts
|
|
260
|
+
var DESIGN_W = 1200;
|
|
261
|
+
var DESIGN_H = 900;
|
|
262
|
+
var DEFAULT_MARGIN_X = 164 / DESIGN_W;
|
|
263
|
+
var DEFAULT_MARGIN_Y = 196 / DESIGN_H;
|
|
264
|
+
var DEFAULT_FELT_GAP = 11;
|
|
265
|
+
var DEFAULT_BET_SCALE = 0.72;
|
|
266
|
+
var DEFAULT_SEAT_GAP = 24;
|
|
267
|
+
var DEFAULT_SEAT_W = 160;
|
|
268
|
+
var DEFAULT_SEAT_H = 176;
|
|
269
|
+
var RIM_GAP = 6;
|
|
270
|
+
var GLOW_GAP = 2;
|
|
271
|
+
var SEAT_SHRINK_FLOOR = 0.5;
|
|
272
|
+
function tableRadii(designWidth, designHeight, marginX, marginY) {
|
|
273
|
+
return {
|
|
274
|
+
rx: Math.max(0, designWidth / 2 - marginX * designWidth),
|
|
275
|
+
ry: Math.max(0, designHeight / 2 - marginY * designHeight)
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function seatRingRadii(designWidth, designHeight, tableRx, tableRy, seatW, seatH, feltGap) {
|
|
279
|
+
const rx = Math.min(tableRx - feltGap + seatW / 2 + 6, designWidth / 2 - seatW / 2);
|
|
280
|
+
const ry = Math.min(tableRy - feltGap + seatH / 2 + 6, designHeight / 2 - seatH / 2);
|
|
281
|
+
return { rx: Math.max(0, rx), ry: Math.max(0, ry) };
|
|
282
|
+
}
|
|
283
|
+
function seatPoint(index, count, cx, cy, ringRx, ringRy, startAngle = 90) {
|
|
284
|
+
return ellipsePoint(cx, cy, ringRx, ringRy, seatAngle(index, count, startAngle));
|
|
285
|
+
}
|
|
286
|
+
function ellipseBox(designWidth, designHeight, rx, ry) {
|
|
287
|
+
const top = designHeight / 2 - ry;
|
|
288
|
+
const left = designWidth / 2 - rx;
|
|
289
|
+
return { top, right: left, bottom: top, left };
|
|
290
|
+
}
|
|
291
|
+
function boxSeparation(a, b) {
|
|
292
|
+
const dx = Math.max(b.x - a.x - (a.width + b.width) / 2, a.x - b.x - (a.width + b.width) / 2);
|
|
293
|
+
const dy = Math.max(b.y - a.y - (a.height + b.height) / 2, a.y - b.y - (a.height + b.height) / 2);
|
|
294
|
+
if (dx > 0 && dy > 0) return Math.hypot(dx, dy);
|
|
295
|
+
if (dx > 0) return dx;
|
|
296
|
+
if (dy > 0) return dy;
|
|
297
|
+
return Math.max(dx, dy);
|
|
298
|
+
}
|
|
299
|
+
function minSeatSeparation(seats) {
|
|
300
|
+
let worst = Infinity;
|
|
301
|
+
for (let i = 0; i < seats.length; i++) {
|
|
302
|
+
for (let j = i + 1; j < seats.length; j++) {
|
|
303
|
+
const s = boxSeparation(seats[i], seats[j]);
|
|
304
|
+
if (s < worst) worst = s;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return worst;
|
|
308
|
+
}
|
|
309
|
+
function positionsFor(count, cx, cy, ringRx, ringRy, seatW, seatH, startAngle) {
|
|
310
|
+
return Array.from({ length: count }, (_, index) => {
|
|
311
|
+
const p = seatPoint(index, count, cx, cy, ringRx, ringRy, startAngle);
|
|
312
|
+
return { index, x: p.x, y: p.y, width: seatW, height: seatH };
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
function fitSeatScale(opts) {
|
|
316
|
+
if (opts.seatGap <= 0) return 1;
|
|
317
|
+
const { rx, ry } = tableRadii(opts.designWidth, opts.designHeight, opts.marginX, opts.marginY);
|
|
318
|
+
const cx = opts.designWidth / 2;
|
|
319
|
+
const cy = opts.designHeight / 2;
|
|
320
|
+
for (let step = 0; step <= 50; step++) {
|
|
321
|
+
const scale = 1 - step * 0.01;
|
|
322
|
+
const w = Math.max(1, Math.round(opts.seatWidth * scale));
|
|
323
|
+
const h = Math.max(1, Math.round(opts.seatHeight * scale));
|
|
324
|
+
const ring = seatRingRadii(opts.designWidth, opts.designHeight, rx, ry, w, h, opts.feltGap);
|
|
325
|
+
const seats = positionsFor(opts.count, cx, cy, ring.rx, ring.ry, w, h, opts.startAngle);
|
|
326
|
+
if (minSeatSeparation(seats) >= opts.seatGap) return scale;
|
|
327
|
+
if (scale <= SEAT_SHRINK_FLOOR) break;
|
|
328
|
+
}
|
|
329
|
+
return SEAT_SHRINK_FLOOR;
|
|
330
|
+
}
|
|
331
|
+
function layoutSeats(opts) {
|
|
332
|
+
const { rx, ry } = tableRadii(opts.designWidth, opts.designHeight, opts.marginX, opts.marginY);
|
|
333
|
+
const cx = opts.designWidth / 2;
|
|
334
|
+
const cy = opts.designHeight / 2;
|
|
335
|
+
const scale = fitSeatScale(opts);
|
|
336
|
+
const seatW = Math.max(1, Math.round(opts.seatWidth * scale));
|
|
337
|
+
const seatH = Math.max(1, Math.round(opts.seatHeight * scale));
|
|
338
|
+
const ring = seatRingRadii(opts.designWidth, opts.designHeight, rx, ry, seatW, seatH, opts.feltGap);
|
|
339
|
+
const betScale = Math.min(1, Math.max(0.2, opts.betRadiusScale ?? DEFAULT_BET_SCALE));
|
|
340
|
+
const betRx = rx * betScale;
|
|
341
|
+
const betRy = ry * betScale;
|
|
342
|
+
const box = (bx, by) => ellipseBox(opts.designWidth, opts.designHeight, bx, by);
|
|
343
|
+
return {
|
|
344
|
+
cx,
|
|
345
|
+
cy,
|
|
346
|
+
tableRx: rx,
|
|
347
|
+
tableRy: ry,
|
|
348
|
+
ringRx: ring.rx,
|
|
349
|
+
ringRy: ring.ry,
|
|
350
|
+
betRx,
|
|
351
|
+
betRy,
|
|
352
|
+
seatW,
|
|
353
|
+
seatH,
|
|
354
|
+
seats: positionsFor(opts.count, cx, cy, ring.rx, ring.ry, seatW, seatH, opts.startAngle),
|
|
355
|
+
boxes: {
|
|
356
|
+
table: box(rx, ry),
|
|
357
|
+
felt: box(rx - opts.feltGap, ry - opts.feltGap),
|
|
358
|
+
rim: box(rx - RIM_GAP, ry - RIM_GAP),
|
|
359
|
+
glow: box(rx - GLOW_GAP, ry - GLOW_GAP),
|
|
360
|
+
bettingLine: box(betRx, betRy)
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
89
365
|
// src/components/PlayingCard.tsx
|
|
90
366
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
91
367
|
var SIZE_CLASSES = {
|
|
@@ -126,82 +402,77 @@ var BACK_EMBLEM_SIZE = {
|
|
|
126
402
|
md: 28,
|
|
127
403
|
lg: 42
|
|
128
404
|
};
|
|
129
|
-
function parseCard(card) {
|
|
130
|
-
if (!card || card.length < 2) return { rank: "", suit: "" };
|
|
131
|
-
return { rank: card.slice(0, -1), suit: card.slice(-1) };
|
|
132
|
-
}
|
|
133
|
-
function getSuitSymbol(suit) {
|
|
134
|
-
switch (suit) {
|
|
135
|
-
case "s":
|
|
136
|
-
return "\u2660";
|
|
137
|
-
case "h":
|
|
138
|
-
return "\u2665";
|
|
139
|
-
case "d":
|
|
140
|
-
return "\u2666";
|
|
141
|
-
case "c":
|
|
142
|
-
return "\u2663";
|
|
143
|
-
default:
|
|
144
|
-
return suit;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
405
|
function getSuitClass(suit) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
case "c":
|
|
151
|
-
return "text-neutral-900";
|
|
152
|
-
case "h":
|
|
153
|
-
case "d":
|
|
154
|
-
return "text-red-600";
|
|
155
|
-
default:
|
|
156
|
-
return "";
|
|
157
|
-
}
|
|
406
|
+
if (isRedSuit(suit)) return "text-red-600";
|
|
407
|
+
return isKnownSuit(suit) ? "text-neutral-900" : "";
|
|
158
408
|
}
|
|
159
409
|
var CARD_FACE = "relative bg-gradient-to-br from-white via-white to-neutral-100 rounded-md border border-neutral-300/90 overflow-hidden shadow-[0_2px_6px_rgba(0,0,0,0.45),inset_0_1px_0_rgba(255,255,255,0.9)]";
|
|
160
|
-
function PlayingCard({ card, size = "md", className }) {
|
|
161
|
-
if (!card) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardBack, { size, className });
|
|
410
|
+
function PlayingCard({ card, size = "md", label, className }) {
|
|
411
|
+
if (!card) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardBack, { size, className, label });
|
|
412
|
+
const name = label ?? describeCard(card);
|
|
162
413
|
const { rank, suit } = parseCard(card);
|
|
163
414
|
const suitSymbol = getSuitSymbol(suit);
|
|
164
415
|
const suitClass = getSuitClass(suit);
|
|
165
416
|
const large = size === "md" || size === "lg";
|
|
166
417
|
if (!large) {
|
|
167
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
419
|
+
"div",
|
|
420
|
+
{
|
|
421
|
+
role: "img",
|
|
422
|
+
"aria-label": name,
|
|
423
|
+
className: cn(SIZE_CLASSES[size], CARD_FACE, className),
|
|
424
|
+
style: { aspectRatio: "10/14" },
|
|
425
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("absolute inset-0 flex flex-col leading-none", suitClass), children: [
|
|
426
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn(SMALL_RANK[size], "font-bold tracking-tight"), children: rank }) }),
|
|
427
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: SMALL_SUIT[size], children: suitSymbol }) })
|
|
428
|
+
] })
|
|
429
|
+
}
|
|
430
|
+
);
|
|
171
431
|
}
|
|
172
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
433
|
+
"div",
|
|
434
|
+
{
|
|
435
|
+
role: "img",
|
|
436
|
+
"aria-label": name,
|
|
437
|
+
className: cn(SIZE_CLASSES[size], CARD_FACE, className),
|
|
438
|
+
style: { aspectRatio: "10/14" },
|
|
439
|
+
children: [
|
|
440
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("absolute top-[3px] left-[5px] flex flex-col items-center leading-none", suitClass), children: [
|
|
441
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn(CORNER_RANK[size], "font-bold tracking-tight"), children: rank }),
|
|
442
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn(CORNER_SUIT[size], "-mt-[1px]"), children: suitSymbol })
|
|
443
|
+
] }),
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("absolute bottom-[3px] right-[5px] flex flex-col items-center leading-none rotate-180", suitClass), children: [
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn(CORNER_RANK[size], "font-bold tracking-tight"), children: rank }),
|
|
446
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn(CORNER_SUIT[size], "-mt-[1px]"), children: suitSymbol })
|
|
447
|
+
] }),
|
|
448
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("absolute inset-0 flex items-center justify-center opacity-90", suitClass), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: CENTER_SUIT[size], children: suitSymbol }) })
|
|
449
|
+
]
|
|
450
|
+
}
|
|
451
|
+
);
|
|
183
452
|
}
|
|
184
453
|
function CardBackEmblem({ size }) {
|
|
185
454
|
const s = BACK_EMBLEM_SIZE[size];
|
|
186
455
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: s, height: s, viewBox: "0 0 40 40", className: "drop-shadow-[0_1px_2px_rgba(0,0,0,0.6)]", "aria-hidden": "true", children: [
|
|
187
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "#f0c04a", opacity: "0.92", children: [
|
|
456
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "var(--color-card-back-emblem, #f0c04a)", opacity: "0.92", children: [
|
|
188
457
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "20", cy: "11", rx: "4", ry: "7" }),
|
|
189
458
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "20", cy: "29", rx: "4", ry: "7" }),
|
|
190
459
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "11", cy: "20", rx: "7", ry: "4" }),
|
|
191
460
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "29", cy: "20", rx: "7", ry: "4" })
|
|
192
461
|
] }),
|
|
193
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "20", cy: "20", r: "3.2", fill: "#5a0c18" })
|
|
462
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "20", cy: "20", r: "3.2", fill: "var(--color-card-back, #5a0c18)" })
|
|
194
463
|
] });
|
|
195
464
|
}
|
|
196
|
-
function CardBack({ size = "md", className }) {
|
|
465
|
+
function CardBack({ size = "md", label = "face-down card", className }) {
|
|
197
466
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
198
467
|
"div",
|
|
199
468
|
{
|
|
469
|
+
role: "img",
|
|
470
|
+
"aria-label": label,
|
|
200
471
|
className: cn(
|
|
201
472
|
SIZE_CLASSES[size],
|
|
202
473
|
"relative rounded-md p-[3px] overflow-hidden",
|
|
203
|
-
"bg-gradient-to-br from-
|
|
204
|
-
"border-2 border-
|
|
474
|
+
"bg-gradient-to-br from-card-back-light via-card-back to-card-back-dark",
|
|
475
|
+
"border-2 border-card-back-ink/70 shadow-[0_2px_6px_rgba(0,0,0,0.45)]",
|
|
205
476
|
className
|
|
206
477
|
),
|
|
207
478
|
style: { aspectRatio: "10/14" },
|
|
@@ -209,8 +480,23 @@ function CardBack({ size = "md", className }) {
|
|
|
209
480
|
}
|
|
210
481
|
);
|
|
211
482
|
}
|
|
212
|
-
function HoleCards({ cards, size = "lg", className, deal = true }) {
|
|
213
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("flex gap-2", className), children: cards.map((card, i) =>
|
|
483
|
+
function HoleCards({ cards, size = "lg", className, deal = true, dealKey }) {
|
|
484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("flex gap-2", className), children: cards.map((card, i) => (
|
|
485
|
+
/*
|
|
486
|
+
* Keying on the card rather than the index is what makes the deal
|
|
487
|
+
* animation replay: React reuses an element whose key is unchanged, and
|
|
488
|
+
* a reused element never restarts its CSS animation.
|
|
489
|
+
*/
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
491
|
+
"div",
|
|
492
|
+
{
|
|
493
|
+
className: cn(deal && "animate-deal-in"),
|
|
494
|
+
style: deal ? { animationDelay: `${i * DEAL_STAGGER_MS}ms` } : void 0,
|
|
495
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlayingCard, { card, size })
|
|
496
|
+
},
|
|
497
|
+
dealKey !== void 0 ? `${dealKey}:${i}` : `${i}:${card ?? "back"}`
|
|
498
|
+
)
|
|
499
|
+
)) });
|
|
214
500
|
}
|
|
215
501
|
function CommunityCards({ cards, size = "md", className, animated = true, slots }) {
|
|
216
502
|
const count = slots ?? cards.length;
|
|
@@ -219,14 +505,171 @@ function CommunityCards({ cards, size = "md", className, animated = true, slots
|
|
|
219
505
|
"div",
|
|
220
506
|
{
|
|
221
507
|
className: cn("h-full w-full", animated && "animate-card-flip"),
|
|
222
|
-
style: animated ? { animationDelay: `${i *
|
|
508
|
+
style: animated ? { animationDelay: `${i * FLIP_STAGGER_MS}ms` } : void 0,
|
|
223
509
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlayingCard, { card, size })
|
|
224
510
|
}
|
|
225
511
|
) : null }, i)) });
|
|
226
512
|
}
|
|
227
513
|
|
|
228
|
-
// src/
|
|
514
|
+
// src/chips.ts
|
|
515
|
+
var DEFAULT_DENOMINATIONS = [
|
|
516
|
+
{ value: 100, color: "#1a1a2e", className: "fill-chip-black" },
|
|
517
|
+
{ value: 25, color: "#27ae60", className: "fill-chip-green" },
|
|
518
|
+
{ value: 10, color: "#2980b9", className: "fill-chip-blue" },
|
|
519
|
+
{ value: 5, color: "#c0392b", className: "fill-chip-red" },
|
|
520
|
+
{ value: 1, color: "#ecf0f1", className: "fill-chip-white" }
|
|
521
|
+
];
|
|
522
|
+
var SPOT_CANDIDATES = ["rgba(255,255,255,0.9)", "rgba(0,0,0,0.45)"];
|
|
523
|
+
function chipSpotColor(bodyColor) {
|
|
524
|
+
return mostVisible(SPOT_CANDIDATES, bodyColor);
|
|
525
|
+
}
|
|
526
|
+
function chipBreakdown(amount, denominations = DEFAULT_DENOMINATIONS) {
|
|
527
|
+
const usable = denominations.filter((d) => Number.isFinite(d.value) && d.value >= 1);
|
|
528
|
+
const sorted = [...usable].sort((a, b) => b.value - a.value);
|
|
529
|
+
let remaining = Math.max(0, Math.floor(Number.isFinite(amount) ? amount : 0));
|
|
530
|
+
const entries = [];
|
|
531
|
+
for (const denomination of sorted) {
|
|
532
|
+
const count = Math.floor(remaining / denomination.value);
|
|
533
|
+
if (count > 0) {
|
|
534
|
+
entries.push({ ...denomination, count });
|
|
535
|
+
remaining -= count * denomination.value;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return entries;
|
|
539
|
+
}
|
|
540
|
+
function chipsTotal(entries) {
|
|
541
|
+
return entries.reduce((sum, e) => sum + e.value * e.count, 0);
|
|
542
|
+
}
|
|
543
|
+
function chipCount(entries) {
|
|
544
|
+
return entries.reduce((sum, e) => sum + e.count, 0);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/components/Chip.tsx
|
|
548
|
+
var import_react = require("react");
|
|
229
549
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
550
|
+
var CHIP_WIDTH = { sm: 22, md: 30, lg: 42 };
|
|
551
|
+
var SPOT_ANGLES = [0, 45, 90, 135, 180, 225, 270, 315];
|
|
552
|
+
function Chip({
|
|
553
|
+
value,
|
|
554
|
+
color = "#2980b9",
|
|
555
|
+
colorClassName,
|
|
556
|
+
spotColor,
|
|
557
|
+
size = "md",
|
|
558
|
+
label,
|
|
559
|
+
className
|
|
560
|
+
}) {
|
|
561
|
+
const clipId = `chip-clip-${(0, import_react.useId)().replace(/:/g, "")}`;
|
|
562
|
+
const width = CHIP_WIDTH[size];
|
|
563
|
+
const spots = spotColor ?? chipSpotColor(color);
|
|
564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
565
|
+
"svg",
|
|
566
|
+
{
|
|
567
|
+
width,
|
|
568
|
+
height: width * 0.625,
|
|
569
|
+
viewBox: "0 0 48 30",
|
|
570
|
+
role: "img",
|
|
571
|
+
"aria-label": label ?? (value !== void 0 ? `${value} chip` : "chip"),
|
|
572
|
+
className,
|
|
573
|
+
children: [
|
|
574
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("clipPath", { id: clipId, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ellipse", { cx: "24", cy: "15", rx: "22", ry: "13" }) }) }),
|
|
575
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ellipse", { cx: "24", cy: "18", rx: "22", ry: "13", className: colorClassName, fill: color }),
|
|
576
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ellipse", { cx: "24", cy: "18", rx: "22", ry: "13", fill: "rgba(0,0,0,0.32)" }),
|
|
577
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ellipse", { cx: "24", cy: "15", rx: "22", ry: "13", className: colorClassName, fill: color }),
|
|
578
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { clipPath: `url(#${clipId})`, children: SPOT_ANGLES.map((angle) => {
|
|
579
|
+
const rad = angle * Math.PI / 180;
|
|
580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
581
|
+
"rect",
|
|
582
|
+
{
|
|
583
|
+
x: -1.7,
|
|
584
|
+
y: -3,
|
|
585
|
+
width: 3.4,
|
|
586
|
+
height: 6,
|
|
587
|
+
rx: 1.3,
|
|
588
|
+
fill: spots,
|
|
589
|
+
transform: `translate(${24 + 19.3 * Math.cos(rad)} ${15 + 10.7 * Math.sin(rad)}) rotate(${angle})`
|
|
590
|
+
},
|
|
591
|
+
angle
|
|
592
|
+
);
|
|
593
|
+
}) }),
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ellipse", { cx: "24", cy: "15", rx: "21", ry: "12.1", fill: "none", stroke: "rgba(255,255,255,0.3)", strokeWidth: "1.2" }),
|
|
595
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ellipse", { cx: "24", cy: "15", rx: "13.4", ry: "7.9", fill: "rgba(255,255,255,0.94)" }),
|
|
596
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ellipse", { cx: "24", cy: "15", rx: "13.4", ry: "7.9", fill: "none", stroke: "rgba(0,0,0,0.18)", strokeWidth: "0.8" }),
|
|
597
|
+
value !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
598
|
+
"text",
|
|
599
|
+
{
|
|
600
|
+
x: "24",
|
|
601
|
+
y: "18.3",
|
|
602
|
+
textAnchor: "middle",
|
|
603
|
+
fontSize: "9.5",
|
|
604
|
+
fontWeight: "700",
|
|
605
|
+
fill: "#171717",
|
|
606
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
607
|
+
children: value
|
|
608
|
+
}
|
|
609
|
+
)
|
|
610
|
+
]
|
|
611
|
+
}
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
function ChipStack({
|
|
615
|
+
amount,
|
|
616
|
+
size = "md",
|
|
617
|
+
denominations = DEFAULT_DENOMINATIONS,
|
|
618
|
+
maxChips = 12,
|
|
619
|
+
label,
|
|
620
|
+
className
|
|
621
|
+
}) {
|
|
622
|
+
const entries = chipBreakdown(amount, denominations);
|
|
623
|
+
const total = chipCount(entries);
|
|
624
|
+
const drawn = [];
|
|
625
|
+
for (const entry of entries) {
|
|
626
|
+
for (let i = 0; i < entry.count && drawn.length < maxChips; i++) drawn.push(entry);
|
|
627
|
+
if (drawn.length >= maxChips) break;
|
|
628
|
+
}
|
|
629
|
+
const hidden = total - drawn.length;
|
|
630
|
+
const offset = Math.max(3, Math.round(CHIP_WIDTH[size] * 0.17));
|
|
631
|
+
const breakdown = entries.map((e) => `${e.count}x${e.label ?? e.value}`).join(", ");
|
|
632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
633
|
+
"div",
|
|
634
|
+
{
|
|
635
|
+
className: cn("inline-flex flex-col items-center gap-1", className),
|
|
636
|
+
role: "img",
|
|
637
|
+
"aria-label": `${amount} in ${total} ${total === 1 ? "chip" : "chips"}${breakdown ? `: ${breakdown}` : ""}`,
|
|
638
|
+
children: [
|
|
639
|
+
drawn.length > 0 && // Presentation only — the stack already carries the accessible name.
|
|
640
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { "aria-hidden": "true", className: "flex flex-col items-center drop-shadow-[0_3px_4px_rgba(0,0,0,0.5)]", children: drawn.map((entry, i) => (
|
|
641
|
+
// Later chips are tucked under the ones above them, so z-index has
|
|
642
|
+
// to descend as the stack grows.
|
|
643
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "relative", style: { marginTop: i === 0 ? 0 : -offset, zIndex: drawn.length - i }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
644
|
+
Chip,
|
|
645
|
+
{
|
|
646
|
+
value: entry.label ?? entry.value,
|
|
647
|
+
color: entry.color,
|
|
648
|
+
colorClassName: entry.className,
|
|
649
|
+
spotColor: entry.spotColor,
|
|
650
|
+
size
|
|
651
|
+
}
|
|
652
|
+
) }, i)
|
|
653
|
+
)) }),
|
|
654
|
+
hidden > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-mono text-[10px] leading-none text-neutral-400", children: [
|
|
655
|
+
"+",
|
|
656
|
+
hidden
|
|
657
|
+
] }),
|
|
658
|
+
label !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "leading-none", children: label })
|
|
659
|
+
]
|
|
660
|
+
}
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// src/components/seatSize.ts
|
|
665
|
+
var import_react2 = require("react");
|
|
666
|
+
var SeatSizeContext = (0, import_react2.createContext)(null);
|
|
667
|
+
function useSeatSize() {
|
|
668
|
+
return (0, import_react2.useContext)(SeatSizeContext);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// src/components/Seat.tsx
|
|
672
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
230
673
|
function Seat({
|
|
231
674
|
isActive = false,
|
|
232
675
|
isWinner = false,
|
|
@@ -244,21 +687,24 @@ function Seat({
|
|
|
244
687
|
topLeft,
|
|
245
688
|
topRight,
|
|
246
689
|
topCenter,
|
|
247
|
-
width
|
|
248
|
-
height
|
|
690
|
+
width,
|
|
691
|
+
height,
|
|
249
692
|
className,
|
|
250
693
|
frameClassName,
|
|
251
694
|
frameStyle
|
|
252
695
|
}) {
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
/* @__PURE__ */ (0,
|
|
696
|
+
const laidOut = useSeatSize();
|
|
697
|
+
const frameWidth = width ?? laidOut?.width ?? DEFAULT_SEAT_W;
|
|
698
|
+
const frameHeight = height ?? laidOut?.height ?? DEFAULT_SEAT_H;
|
|
699
|
+
const activeClass = animated ? "border-gold animate-turn-glow" : "border-gold shadow-[0_0_18px_color-mix(in_oklab,var(--color-gold)_50%,transparent)]";
|
|
700
|
+
const winnerClass = animated ? "border-gold animate-winner-glow" : "border-gold shadow-[0_0_0_3px_color-mix(in_oklab,var(--color-gold)_90%,transparent)]";
|
|
701
|
+
const effTopLeft = topLeft !== void 0 ? topLeft : isWinner && winnerCrown ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-3xl drop-shadow-[0_2px_4px_rgba(0,0,0,0.6)] animate-bounce", children: "\u{1F451}" }) : void 0;
|
|
702
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: cn("relative flex flex-col items-center", className), style: { width: frameWidth }, children: [
|
|
703
|
+
topCenter !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute -top-2 left-1/2 z-20 flex -translate-x-1/2 gap-1", children: topCenter }),
|
|
704
|
+
effTopLeft !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute -top-3 -left-2 z-40", children: effTopLeft }),
|
|
705
|
+
topRight !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute -top-2 -right-2 z-40", children: topRight }),
|
|
706
|
+
above !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "pointer-events-none absolute -top-12 left-1/2 z-30 -translate-x-1/2", children: above }),
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
262
708
|
"div",
|
|
263
709
|
{
|
|
264
710
|
role: onClick ? "button" : void 0,
|
|
@@ -267,98 +713,86 @@ function Seat({
|
|
|
267
713
|
onKeyDown: onClick ? (e) => {
|
|
268
714
|
if (e.key === "Enter" || e.key === " ") onClick();
|
|
269
715
|
} : void 0,
|
|
270
|
-
style: { width, height, ...frameStyle },
|
|
716
|
+
style: { width: frameWidth, height: frameHeight, ...frameStyle },
|
|
271
717
|
className: cn(
|
|
272
718
|
"relative flex flex-col items-center justify-between gap-1 rounded-2xl border bg-neutral-900/80 p-2 text-neutral-100 transition",
|
|
273
719
|
"border-neutral-700",
|
|
274
720
|
isActive && activeClass,
|
|
275
721
|
isWinner && winnerClass,
|
|
276
722
|
isDimmed && "opacity-50",
|
|
277
|
-
onClick && "cursor-pointer hover:border-neutral-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-
|
|
723
|
+
onClick && "cursor-pointer hover:border-neutral-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-gold",
|
|
278
724
|
frameClassName
|
|
279
725
|
),
|
|
280
726
|
children: [
|
|
281
|
-
header !== void 0 && /* @__PURE__ */ (0,
|
|
282
|
-
/* @__PURE__ */ (0,
|
|
283
|
-
footer !== void 0 && /* @__PURE__ */ (0,
|
|
284
|
-
overlay !== void 0 && /* @__PURE__ */ (0,
|
|
727
|
+
header !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex w-full shrink-0 items-center justify-between gap-1 text-[11px]", children: header }),
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex min-h-0 flex-1 items-center justify-center", children }),
|
|
729
|
+
footer !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex w-full shrink-0 items-center justify-between text-[11px] text-neutral-300", children: footer }),
|
|
730
|
+
overlay !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 text-center", children: overlay })
|
|
285
731
|
]
|
|
286
732
|
}
|
|
287
733
|
),
|
|
288
|
-
badge !== void 0 && /* @__PURE__ */ (0,
|
|
289
|
-
below !== void 0 && /* @__PURE__ */ (0,
|
|
734
|
+
badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute top-0 right-0 z-40", children: badge }),
|
|
735
|
+
below !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mt-1 flex flex-col items-center gap-1", children: below })
|
|
290
736
|
] });
|
|
291
737
|
}
|
|
292
738
|
|
|
293
739
|
// src/components/Pot.tsx
|
|
294
|
-
var
|
|
295
|
-
var
|
|
740
|
+
var import_react3 = require("react");
|
|
741
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
742
|
+
var defaultFormat = (amount) => amount.toLocaleString();
|
|
743
|
+
function prefersReducedMotion() {
|
|
744
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
745
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
746
|
+
}
|
|
296
747
|
function CountUp({ value, format }) {
|
|
297
|
-
const [shown, setShown] = (0,
|
|
298
|
-
const
|
|
299
|
-
(0,
|
|
300
|
-
const from =
|
|
748
|
+
const [shown, setShown] = (0, import_react3.useState)(value);
|
|
749
|
+
const shownRef = (0, import_react3.useRef)(value);
|
|
750
|
+
(0, import_react3.useEffect)(() => {
|
|
751
|
+
const from = shownRef.current;
|
|
301
752
|
const to = value;
|
|
302
753
|
if (from === to) return;
|
|
754
|
+
if (prefersReducedMotion()) {
|
|
755
|
+
shownRef.current = to;
|
|
756
|
+
setShown(to);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
303
759
|
let raf = 0;
|
|
304
|
-
const
|
|
305
|
-
|
|
760
|
+
const dur = COUNT_UP_MS;
|
|
761
|
+
let origin = null;
|
|
306
762
|
const tick = (now) => {
|
|
307
|
-
|
|
763
|
+
if (origin === null) origin = now;
|
|
764
|
+
const t = Math.min(1, Math.max(0, (now - origin) / dur));
|
|
308
765
|
const eased = 1 - Math.pow(1 - t, 3);
|
|
309
|
-
|
|
766
|
+
const next = Math.round(from + (to - from) * eased);
|
|
767
|
+
shownRef.current = next;
|
|
768
|
+
setShown(next);
|
|
310
769
|
if (t < 1) raf = requestAnimationFrame(tick);
|
|
311
|
-
else fromRef.current = to;
|
|
312
770
|
};
|
|
313
771
|
raf = requestAnimationFrame(tick);
|
|
314
772
|
return () => cancelAnimationFrame(raf);
|
|
315
773
|
}, [value]);
|
|
316
|
-
return /* @__PURE__ */ (0,
|
|
774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: format(shown) });
|
|
317
775
|
}
|
|
318
|
-
function Pot({ amount, label, format =
|
|
319
|
-
return /* @__PURE__ */ (0,
|
|
320
|
-
label && /* @__PURE__ */ (0,
|
|
321
|
-
/* @__PURE__ */ (0,
|
|
776
|
+
function Pot({ amount, label, format = defaultFormat, animate = true, className }) {
|
|
777
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: cn("flex items-center gap-2 font-mono text-sm text-gold", className), children: [
|
|
778
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-neutral-400", children: label }),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "whitespace-nowrap rounded-full border border-gold/50 bg-neutral-900/80 px-3 py-1 shadow-inner", children: animate ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CountUp, { value: amount, format }) : format(amount) })
|
|
322
780
|
] });
|
|
323
781
|
}
|
|
324
782
|
|
|
325
783
|
// src/components/CardTable.tsx
|
|
326
|
-
var
|
|
327
|
-
var
|
|
328
|
-
var
|
|
329
|
-
var
|
|
330
|
-
var
|
|
331
|
-
var MARGIN_Y = 196;
|
|
332
|
-
var TABLE_RX = DESIGN_W / 2 - MARGIN_X;
|
|
333
|
-
var TABLE_RY = DESIGN_H / 2 - MARGIN_Y;
|
|
334
|
-
var FELT_GAP = 11;
|
|
335
|
-
var BET_SCALE = 0.72;
|
|
336
|
-
var BET_RX = TABLE_RX * BET_SCALE;
|
|
337
|
-
var BET_RY = TABLE_RY * BET_SCALE;
|
|
338
|
-
var CONFETTI_COLORS = ["#f39c12", "#e74c3c", "#2ecc71", "#3498db", "#f1c40f", "#9b59b6"];
|
|
339
|
-
function calculateSeatLayouts(seatCount, seatWidth, seatHeight, startAngle) {
|
|
340
|
-
const cx = DESIGN_W / 2;
|
|
341
|
-
const cy = DESIGN_H / 2;
|
|
342
|
-
const ringX = TABLE_RX - FELT_GAP + seatWidth / 2 + 6;
|
|
343
|
-
const ringY = TABLE_RY - FELT_GAP + seatHeight / 2 + 6;
|
|
344
|
-
const layouts = [];
|
|
345
|
-
for (let i = 0; i < seatCount; i++) {
|
|
346
|
-
const pt = ellipsePoint(cx, cy, ringX, ringY, seatAngle(i, seatCount, startAngle));
|
|
347
|
-
layouts.push({
|
|
348
|
-
x: pt.x - seatWidth / 2,
|
|
349
|
-
y: pt.y - seatHeight / 2,
|
|
350
|
-
index: i
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
return layouts;
|
|
354
|
-
}
|
|
784
|
+
var import_react4 = require("react");
|
|
785
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
786
|
+
var MIN_FIT_ASPECT = 0.5;
|
|
787
|
+
var MAX_FIT_ASPECT = 2.5;
|
|
788
|
+
var DEFAULT_CONFETTI_COLORS = ["#f39c12", "#e74c3c", "#2ecc71", "#3498db", "#f1c40f", "#9b59b6"];
|
|
355
789
|
function CardTable({
|
|
356
790
|
seatCount = 6,
|
|
357
791
|
seats,
|
|
358
792
|
renderSeat,
|
|
359
793
|
bets,
|
|
360
794
|
renderBet,
|
|
361
|
-
betRadiusScale =
|
|
795
|
+
betRadiusScale = DEFAULT_BET_SCALE,
|
|
362
796
|
startAngle = 90,
|
|
363
797
|
yourSeatIndex = null,
|
|
364
798
|
center,
|
|
@@ -366,96 +800,142 @@ function CardTable({
|
|
|
366
800
|
yourTurn = false,
|
|
367
801
|
winnerSeats = [],
|
|
368
802
|
confetti = true,
|
|
369
|
-
|
|
370
|
-
|
|
803
|
+
confettiColors = DEFAULT_CONFETTI_COLORS,
|
|
804
|
+
seatWidth = DEFAULT_SEAT_W,
|
|
805
|
+
seatHeight = DEFAULT_SEAT_H,
|
|
806
|
+
seatGap = DEFAULT_SEAT_GAP,
|
|
807
|
+
designWidth = DESIGN_W,
|
|
808
|
+
designHeight = DESIGN_H,
|
|
809
|
+
marginX = DEFAULT_MARGIN_X,
|
|
810
|
+
marginY = DEFAULT_MARGIN_Y,
|
|
811
|
+
feltGap = DEFAULT_FELT_GAP,
|
|
812
|
+
fit = "design",
|
|
371
813
|
className
|
|
372
814
|
}) {
|
|
373
|
-
const
|
|
374
|
-
const
|
|
375
|
-
const
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
[count, seatWidth, seatHeight, startAngle]
|
|
379
|
-
);
|
|
380
|
-
const betRx = TABLE_RX * betRadiusScale;
|
|
381
|
-
const betRy = TABLE_RY * betRadiusScale;
|
|
382
|
-
const hasBets = bets !== void 0 || renderBet !== void 0;
|
|
383
|
-
(0, import_react2.useLayoutEffect)(() => {
|
|
815
|
+
const requested = Math.floor(seatCount);
|
|
816
|
+
const count = Number.isFinite(requested) ? Math.max(1, requested) : 1;
|
|
817
|
+
const outerRef = (0, import_react4.useRef)(null);
|
|
818
|
+
const [box, setBox] = (0, import_react4.useState)({ w: 0, h: 0 });
|
|
819
|
+
(0, import_react4.useLayoutEffect)(() => {
|
|
384
820
|
const el = outerRef.current;
|
|
385
821
|
if (!el) return;
|
|
386
822
|
const compute = () => {
|
|
387
823
|
const w = el.clientWidth;
|
|
388
824
|
const h = el.clientHeight;
|
|
389
825
|
if (!w || !h) return;
|
|
390
|
-
|
|
826
|
+
setBox({ w, h });
|
|
391
827
|
};
|
|
392
828
|
compute();
|
|
393
829
|
const ro = new ResizeObserver(compute);
|
|
394
830
|
ro.observe(el);
|
|
395
831
|
return () => ro.disconnect();
|
|
396
832
|
}, []);
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
833
|
+
const geo = (0, import_react4.useMemo)(() => {
|
|
834
|
+
const dh = designHeight;
|
|
835
|
+
const dw = fit === "container" && box.w > 0 && box.h > 0 ? dh * Math.min(MAX_FIT_ASPECT, Math.max(MIN_FIT_ASPECT, box.w / box.h)) : designWidth;
|
|
836
|
+
const layout2 = layoutSeats({
|
|
837
|
+
count,
|
|
838
|
+
designWidth: dw,
|
|
839
|
+
designHeight: dh,
|
|
840
|
+
marginX,
|
|
841
|
+
marginY,
|
|
842
|
+
feltGap,
|
|
843
|
+
seatWidth,
|
|
844
|
+
seatHeight,
|
|
845
|
+
// Always applied. Every Seat inside the table is told its frame size
|
|
846
|
+
// through context, so the shrink is no longer limited to `renderSeat`.
|
|
847
|
+
seatGap,
|
|
848
|
+
startAngle,
|
|
849
|
+
betRadiusScale
|
|
850
|
+
});
|
|
851
|
+
const scale2 = box.w > 0 && box.h > 0 ? Math.min(box.w / dw, box.h / dh) : 1;
|
|
852
|
+
return { designW: dw, designH: dh, scale: scale2, layout: layout2 };
|
|
853
|
+
}, [
|
|
854
|
+
count,
|
|
855
|
+
designWidth,
|
|
856
|
+
designHeight,
|
|
857
|
+
marginX,
|
|
858
|
+
marginY,
|
|
859
|
+
feltGap,
|
|
860
|
+
seatWidth,
|
|
861
|
+
seatHeight,
|
|
862
|
+
seatGap,
|
|
863
|
+
startAngle,
|
|
864
|
+
fit,
|
|
865
|
+
betRadiusScale,
|
|
866
|
+
box.w,
|
|
867
|
+
box.h
|
|
868
|
+
]);
|
|
869
|
+
const { designW, designH, scale, layout } = geo;
|
|
870
|
+
const { cx, cy, seatW, seatH, betRx, betRy, boxes } = layout;
|
|
871
|
+
const hasBets = bets !== void 0 || renderBet !== void 0;
|
|
872
|
+
const px = (b) => ({
|
|
873
|
+
top: `${b.top}px`,
|
|
874
|
+
right: `${b.right}px`,
|
|
875
|
+
bottom: `${b.bottom}px`,
|
|
876
|
+
left: `${b.left}px`
|
|
877
|
+
});
|
|
878
|
+
const tableFrameInset = px(boxes.table);
|
|
879
|
+
const feltInset = px(boxes.felt);
|
|
880
|
+
const rimInset = px(boxes.rim);
|
|
881
|
+
const ringInset = px(boxes.glow);
|
|
882
|
+
const betLineInset = px(boxes.bettingLine);
|
|
883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
405
884
|
"div",
|
|
406
885
|
{
|
|
407
886
|
ref: outerRef,
|
|
408
887
|
className: cn("relative flex h-full w-full min-h-0 items-center justify-center overflow-hidden", className),
|
|
409
|
-
children: /* @__PURE__ */ (0,
|
|
888
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { width: designW * scale, height: designH * scale }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
410
889
|
"div",
|
|
411
890
|
{
|
|
412
891
|
className: "relative",
|
|
413
|
-
style: { width:
|
|
892
|
+
style: { width: designW, height: designH, transform: `scale(${scale})`, transformOrigin: "top left" },
|
|
414
893
|
children: [
|
|
415
|
-
/* @__PURE__ */ (0,
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
416
895
|
"div",
|
|
417
896
|
{
|
|
418
|
-
className: "absolute -inset-6 rounded-[50%] bg-[radial-gradient(closest-side,
|
|
897
|
+
className: "absolute -inset-6 rounded-[50%] bg-[radial-gradient(closest-side,color-mix(in_oklab,var(--color-gold-light)_16%,transparent),transparent_72%)] blur-3xl",
|
|
419
898
|
"aria-hidden": "true"
|
|
420
899
|
}
|
|
421
900
|
),
|
|
422
|
-
/* @__PURE__ */ (0,
|
|
901
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
423
902
|
"div",
|
|
424
903
|
{
|
|
425
|
-
className: "absolute rounded-[50%] bg-gradient-to-b from-
|
|
904
|
+
className: "absolute rounded-[50%] bg-gradient-to-b from-rail via-rail-dark to-rail-deep shadow-[0_26px_70px_-12px_rgba(0,0,0,0.85),inset_0_3px_0_rgba(255,255,255,0.20),inset_0_-6px_16px_rgba(0,0,0,0.5)]",
|
|
426
905
|
style: tableFrameInset,
|
|
427
906
|
"aria-hidden": "true"
|
|
428
907
|
}
|
|
429
908
|
),
|
|
430
|
-
/* @__PURE__ */ (0,
|
|
909
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
431
910
|
"div",
|
|
432
911
|
{
|
|
433
|
-
className: "absolute rounded-[50%] bg-[radial-gradient(ellipse_at_50%_32
|
|
912
|
+
className: "absolute rounded-[50%] bg-[radial-gradient(ellipse_at_50%_32%,var(--color-felt-light),var(--color-felt)_55%,var(--color-felt-dark))] shadow-[inset_0_0_90px_rgba(0,0,0,0.55),inset_0_3px_10px_rgba(255,255,255,0.06)]",
|
|
434
913
|
style: feltInset,
|
|
435
914
|
"aria-hidden": "true"
|
|
436
915
|
}
|
|
437
916
|
),
|
|
438
|
-
ambient && /* @__PURE__ */ (0,
|
|
439
|
-
/* @__PURE__ */ (0,
|
|
917
|
+
ambient && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
918
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
440
919
|
"div",
|
|
441
920
|
{
|
|
442
|
-
className: "absolute animate-spotlight rounded-[50%] bg-[radial-gradient(closest-side,
|
|
921
|
+
className: "absolute animate-spotlight rounded-[50%] bg-[radial-gradient(closest-side,color-mix(in_oklab,var(--color-gold-glow)_14%,transparent),transparent_70%)] blur-2xl",
|
|
443
922
|
style: feltInset,
|
|
444
923
|
"aria-hidden": "true"
|
|
445
924
|
}
|
|
446
925
|
),
|
|
447
|
-
/* @__PURE__ */ (0,
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute overflow-hidden rounded-[50%]", style: feltInset, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute inset-0 animate-felt-shimmer bg-[linear-gradient(115deg,transparent_42%,rgba(255,255,255,0.06)_50%,transparent_58%)] bg-[length:220%_100%]" }) })
|
|
448
927
|
] }),
|
|
449
|
-
/* @__PURE__ */ (0,
|
|
928
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
450
929
|
"div",
|
|
451
930
|
{
|
|
931
|
+
"data-part": "betting-line",
|
|
452
932
|
className: "absolute rounded-[50%] border-2 border-white/10 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.25)]",
|
|
453
933
|
style: betLineInset,
|
|
454
934
|
"aria-hidden": "true"
|
|
455
935
|
}
|
|
456
936
|
),
|
|
457
|
-
/* @__PURE__ */ (0,
|
|
458
|
-
yourTurn && /* @__PURE__ */ (0,
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute flex items-center justify-center pointer-events-none", style: feltInset, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-white/[0.05] text-[110px] font-black tracking-[0.2em] select-none leading-none", children: "\u2660\u2665\u2666\u2663" }) }),
|
|
938
|
+
yourTurn && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
459
939
|
"div",
|
|
460
940
|
{
|
|
461
941
|
className: "pointer-events-none absolute z-10 animate-turn-glow rounded-[50%]",
|
|
@@ -463,20 +943,33 @@ function CardTable({
|
|
|
463
943
|
"aria-hidden": "true"
|
|
464
944
|
}
|
|
465
945
|
),
|
|
466
|
-
center !== void 0 && /* @__PURE__ */ (0,
|
|
467
|
-
/* @__PURE__ */ (0,
|
|
946
|
+
center !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center", children: center }),
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute inset-0 z-20", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SeatSizeContext.Provider, { value: { width: seatW, height: seatH }, children: layout.seats.map((seat) => {
|
|
948
|
+
const { index, x, y } = seat;
|
|
468
949
|
const isYou = index === yourSeatIndex;
|
|
469
|
-
const
|
|
950
|
+
const box2 = { index, isYou, x, y, width: seatW, height: seatH };
|
|
951
|
+
const content = seats ? seats[index] ?? null : renderSeat ? renderSeat(index, isYou, box2) : null;
|
|
470
952
|
if (content === null) return null;
|
|
471
|
-
return /* @__PURE__ */ (0,
|
|
472
|
-
|
|
473
|
-
|
|
953
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
954
|
+
"div",
|
|
955
|
+
{
|
|
956
|
+
"data-part": "seat",
|
|
957
|
+
"data-seat": index,
|
|
958
|
+
className: "absolute",
|
|
959
|
+
style: { left: `${x - seatW / 2}px`, top: `${y - seatH / 2}px` },
|
|
960
|
+
children: content
|
|
961
|
+
},
|
|
962
|
+
index
|
|
963
|
+
);
|
|
964
|
+
}) }) }),
|
|
965
|
+
hasBets && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pointer-events-none absolute inset-0 z-20", children: layout.seats.map(({ index }) => {
|
|
474
966
|
const content = bets ? bets[index] ?? null : renderBet ? renderBet(index) : null;
|
|
475
967
|
if (content === null || content === void 0) return null;
|
|
476
|
-
const pt = ellipsePoint(
|
|
477
|
-
return /* @__PURE__ */ (0,
|
|
968
|
+
const pt = ellipsePoint(cx, cy, betRx, betRy, seatAngle(index, count, startAngle));
|
|
969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
478
970
|
"div",
|
|
479
971
|
{
|
|
972
|
+
"data-seat-bet": index,
|
|
480
973
|
className: "absolute",
|
|
481
974
|
style: { left: `${pt.x}px`, top: `${pt.y}px`, transform: "translate(-50%, -50%)" },
|
|
482
975
|
children: content
|
|
@@ -484,12 +977,12 @@ function CardTable({
|
|
|
484
977
|
index
|
|
485
978
|
);
|
|
486
979
|
}) }),
|
|
487
|
-
confetti && winnerSeats.length > 0 && /* @__PURE__ */ (0,
|
|
980
|
+
confetti && winnerSeats.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pointer-events-none absolute inset-0 z-30 overflow-hidden", "aria-hidden": "true", children: Array.from({ length: 44 }).map((_, i) => {
|
|
488
981
|
const w = 5 + i % 4 * 2;
|
|
489
982
|
const h = 9 + i % 3 * 4;
|
|
490
983
|
const dur = 1.7 + i % 5 * 0.28;
|
|
491
984
|
const delay = i % 12 * 0.14;
|
|
492
|
-
return /* @__PURE__ */ (0,
|
|
985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
493
986
|
"span",
|
|
494
987
|
{
|
|
495
988
|
className: "absolute top-[26%] animate-confetti rounded-[2px]",
|
|
@@ -497,7 +990,7 @@ function CardTable({
|
|
|
497
990
|
left: `${i * 37 % 96}%`,
|
|
498
991
|
width: w,
|
|
499
992
|
height: h,
|
|
500
|
-
backgroundColor:
|
|
993
|
+
backgroundColor: confettiColors[i % confettiColors.length],
|
|
501
994
|
animationDuration: `${dur}s`,
|
|
502
995
|
animationDelay: `${delay}s`,
|
|
503
996
|
animationIterationCount: "infinite"
|
|
@@ -506,7 +999,7 @@ function CardTable({
|
|
|
506
999
|
i
|
|
507
1000
|
);
|
|
508
1001
|
}) }),
|
|
509
|
-
/* @__PURE__ */ (0,
|
|
1002
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute rounded-[50%] border border-white/10 pointer-events-none", style: rimInset, "aria-hidden": "true" })
|
|
510
1003
|
]
|
|
511
1004
|
}
|
|
512
1005
|
) })
|
|
@@ -516,21 +1009,61 @@ function CardTable({
|
|
|
516
1009
|
// Annotate the CommonJS export names for ESM import in node:
|
|
517
1010
|
0 && (module.exports = {
|
|
518
1011
|
BB,
|
|
1012
|
+
COUNT_UP_MS,
|
|
519
1013
|
CardBack,
|
|
520
1014
|
CardTable,
|
|
1015
|
+
Chip,
|
|
1016
|
+
ChipStack,
|
|
521
1017
|
CommunityCards,
|
|
1018
|
+
DEAL_STAGGER_MS,
|
|
1019
|
+
DEFAULT_BET_SCALE,
|
|
1020
|
+
DEFAULT_DENOMINATIONS,
|
|
1021
|
+
DEFAULT_FELT_GAP,
|
|
1022
|
+
DEFAULT_MARGIN_X,
|
|
1023
|
+
DEFAULT_MARGIN_Y,
|
|
1024
|
+
DEFAULT_SEAT_GAP,
|
|
1025
|
+
DEFAULT_SEAT_H,
|
|
1026
|
+
DEFAULT_SEAT_W,
|
|
1027
|
+
DESIGN_H,
|
|
1028
|
+
DESIGN_W,
|
|
1029
|
+
FLIP_STAGGER_MS,
|
|
1030
|
+
GLOW_GAP,
|
|
522
1031
|
HoleCards,
|
|
523
1032
|
PlayingCard,
|
|
524
1033
|
PokerTable,
|
|
525
1034
|
Pot,
|
|
1035
|
+
RIM_GAP,
|
|
1036
|
+
SEAT_SHRINK_FLOOR,
|
|
1037
|
+
SIZES,
|
|
526
1038
|
Seat,
|
|
1039
|
+
chipBreakdown,
|
|
1040
|
+
chipCount,
|
|
1041
|
+
chipSpotColor,
|
|
1042
|
+
chipsTotal,
|
|
527
1043
|
cn,
|
|
1044
|
+
contrastRatio,
|
|
1045
|
+
describeCard,
|
|
1046
|
+
ellipseBox,
|
|
528
1047
|
ellipsePoint,
|
|
1048
|
+
fitSeatScale,
|
|
1049
|
+
flatten,
|
|
529
1050
|
formatBB,
|
|
1051
|
+
getRankName,
|
|
1052
|
+
getSuitName,
|
|
530
1053
|
getSuitSymbol,
|
|
1054
|
+
isKnownSuit,
|
|
1055
|
+
isRedSuit,
|
|
1056
|
+
layoutSeats,
|
|
1057
|
+
minSeatSeparation,
|
|
1058
|
+
mostVisible,
|
|
531
1059
|
nextSeatIndex,
|
|
532
1060
|
parseCard,
|
|
1061
|
+
parseColor,
|
|
1062
|
+
relativeLuminance,
|
|
533
1063
|
ringPoints,
|
|
534
|
-
seatAngle
|
|
1064
|
+
seatAngle,
|
|
1065
|
+
seatPoint,
|
|
1066
|
+
seatRingRadii,
|
|
1067
|
+
tableRadii
|
|
535
1068
|
});
|
|
536
1069
|
//# sourceMappingURL=index.cjs.map
|