@scriptonita/chess-football-ui 0.5.0 → 0.7.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/dist/index.cjs +433 -253
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -4
- package/dist/index.d.ts +104 -4
- package/dist/index.js +424 -254
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -53,26 +53,66 @@ var BLACK_PIECE_STYLE = {
|
|
|
53
53
|
border: "1px solid rgba(0,0,0,0.55)",
|
|
54
54
|
color: "#fafafa"
|
|
55
55
|
};
|
|
56
|
+
var ON_BOARD_CHIP_STYLE = {
|
|
57
|
+
white: {
|
|
58
|
+
...WHITE_PIECE_STYLE,
|
|
59
|
+
boxShadow: [
|
|
60
|
+
"inset 0 1.5px 1px rgba(255,255,255,0.95)",
|
|
61
|
+
"inset 0 -2px 3px rgba(0,0,0,0.18)",
|
|
62
|
+
"0 1px 1px rgba(0,0,0,0.35)"
|
|
63
|
+
].join(", ")
|
|
64
|
+
},
|
|
65
|
+
black: {
|
|
66
|
+
...BLACK_PIECE_STYLE,
|
|
67
|
+
boxShadow: [
|
|
68
|
+
"inset 0 1.5px 1px rgba(255,255,255,0.22)",
|
|
69
|
+
"inset 0 -2px 3px rgba(0,0,0,0.6)",
|
|
70
|
+
"0 1px 1px rgba(0,0,0,0.5)"
|
|
71
|
+
].join(", ")
|
|
72
|
+
}
|
|
73
|
+
};
|
|
56
74
|
var MOVED_STYLE = {
|
|
57
75
|
filter: "saturate(0.15) brightness(0.75)"
|
|
58
76
|
};
|
|
59
|
-
function GamePiece({ piece, isSelected, hasBall, onClick }) {
|
|
60
|
-
const
|
|
61
|
-
const style = piece.hasMovedThisTurn ? { ...baseStyle, ...MOVED_STYLE } : baseStyle;
|
|
77
|
+
function GamePiece({ piece, isSelected, hasBall, onClick, isMoving = false }) {
|
|
78
|
+
const chipStyle = ON_BOARD_CHIP_STYLE[piece.side];
|
|
62
79
|
return /* @__PURE__ */ jsxs(
|
|
63
80
|
"div",
|
|
64
81
|
{
|
|
65
82
|
onClick,
|
|
66
|
-
style,
|
|
83
|
+
style: piece.hasMovedThisTurn ? MOVED_STYLE : void 0,
|
|
67
84
|
className: cn(
|
|
68
|
-
"relative w-[88%] h-[88%]
|
|
85
|
+
"relative w-[88%] h-[88%] rounded-full cursor-pointer z-10 transition-transform duration-200 ease-out motion-reduce:transition-none",
|
|
69
86
|
isSelected && "ring-4 ring-primary scale-110 z-30",
|
|
87
|
+
isMoving && "scale-[1.08] z-40",
|
|
70
88
|
piece.hasMovedThisTurn && "opacity-70"
|
|
71
89
|
),
|
|
72
90
|
children: [
|
|
73
|
-
/* @__PURE__ */ jsx(
|
|
74
|
-
|
|
75
|
-
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
"div",
|
|
93
|
+
{
|
|
94
|
+
"aria-hidden": "true",
|
|
95
|
+
"data-testid": "piece-shadow",
|
|
96
|
+
"data-lifted": isMoving ? "true" : "false",
|
|
97
|
+
className: cn(
|
|
98
|
+
"absolute inset-0 rounded-full bg-black pointer-events-none transition-all duration-200 ease-out motion-reduce:transition-none",
|
|
99
|
+
isMoving ? "translate-x-[9%] translate-y-[24%] scale-[1.04] opacity-35 blur-[5px]" : "translate-x-[4%] translate-y-[9%] scale-95 opacity-50 blur-[3px]"
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
),
|
|
103
|
+
/* @__PURE__ */ jsxs(
|
|
104
|
+
"div",
|
|
105
|
+
{
|
|
106
|
+
"data-testid": "piece-chip",
|
|
107
|
+
style: chipStyle,
|
|
108
|
+
className: "absolute inset-0 rounded-full flex items-center justify-center",
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ jsx(PieceIcon, { type: piece.type, side: piece.side }),
|
|
111
|
+
hasBall && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full ring-2 ring-orange-400 pointer-events-none" }),
|
|
112
|
+
isSelected && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full animate-pulse motion-reduce:animate-none ring-2 ring-yellow-400 ring-offset-2 ring-offset-transparent" })
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
)
|
|
76
116
|
]
|
|
77
117
|
}
|
|
78
118
|
);
|
|
@@ -128,6 +168,7 @@ var Football = ({ className }) => {
|
|
|
128
168
|
var STATIC_I18N_KEYS = [
|
|
129
169
|
"actionPointsAriaLabel",
|
|
130
170
|
"actionPointsShort",
|
|
171
|
+
"ballHolder",
|
|
131
172
|
"endTurn",
|
|
132
173
|
"endTurnConfirm",
|
|
133
174
|
"endTurnConfirmDescription",
|
|
@@ -183,10 +224,204 @@ function GameI18nProvider({ t, children }) {
|
|
|
183
224
|
function useGameT() {
|
|
184
225
|
return useContext(GameI18nContext);
|
|
185
226
|
}
|
|
227
|
+
function BallHolderChip({ className }) {
|
|
228
|
+
const t = useGameT();
|
|
229
|
+
const boardState = useGameStore((s) => s.boardState);
|
|
230
|
+
const holder = boardState?.pieces.find((p) => p.id === boardState.ball.holderId) ?? null;
|
|
231
|
+
if (!holder) return null;
|
|
232
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-1.5 min-h-[1.75rem]", className), "aria-live": "polite", children: [
|
|
233
|
+
/* @__PURE__ */ jsxs(
|
|
234
|
+
"div",
|
|
235
|
+
{
|
|
236
|
+
style: holder.side === "white" ? WHITE_PIECE_STYLE : BLACK_PIECE_STYLE,
|
|
237
|
+
className: "relative w-7 h-7 flex items-center justify-center rounded-full shrink-0",
|
|
238
|
+
children: [
|
|
239
|
+
/* @__PURE__ */ jsx(PieceIcon, { type: holder.type, side: holder.side }),
|
|
240
|
+
/* @__PURE__ */ jsx("div", { className: "absolute -bottom-1 -right-1 w-3.5 h-3.5 flex items-center justify-center rounded-full bg-bg-secondary border border-border-subtle", children: /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5", children: /* @__PURE__ */ jsx(Football, {}) }) })
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
),
|
|
244
|
+
/* @__PURE__ */ jsxs("span", { className: "font-inter text-[11px] text-fg-secondary", children: [
|
|
245
|
+
t("ballHolder"),
|
|
246
|
+
": ",
|
|
247
|
+
t(`pieces.${holder.type}`)
|
|
248
|
+
] })
|
|
249
|
+
] });
|
|
250
|
+
}
|
|
251
|
+
function KeyboardShortcutsList({ className }) {
|
|
252
|
+
const t = useGameT();
|
|
253
|
+
return /* @__PURE__ */ jsxs("ul", { className: cn("font-mono text-[10px] text-fg-secondary leading-relaxed", className), children: [
|
|
254
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
255
|
+
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "\u2191\u2193\u2190\u2192" }),
|
|
256
|
+
" ",
|
|
257
|
+
t("shortcuts.arrows")
|
|
258
|
+
] }),
|
|
259
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
260
|
+
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "Enter" }),
|
|
261
|
+
" ",
|
|
262
|
+
t("shortcuts.select")
|
|
263
|
+
] }),
|
|
264
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
265
|
+
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "M" }),
|
|
266
|
+
" ",
|
|
267
|
+
t("shortcuts.move")
|
|
268
|
+
] }),
|
|
269
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
270
|
+
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "P" }),
|
|
271
|
+
" ",
|
|
272
|
+
t("shortcuts.pass")
|
|
273
|
+
] }),
|
|
274
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
275
|
+
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "Esc" }),
|
|
276
|
+
" ",
|
|
277
|
+
t("shortcuts.cancel")
|
|
278
|
+
] })
|
|
279
|
+
] });
|
|
280
|
+
}
|
|
281
|
+
var PITCH_COLS = 9;
|
|
282
|
+
var PITCH_ROWS = 12;
|
|
283
|
+
var isGoalAreaSquare = (x, y) => x >= 2 && x <= 6 && (y >= 0 && y <= 1 || y >= PITCH_ROWS - 2 && y <= PITCH_ROWS - 1);
|
|
284
|
+
var GOAL_AREA_SHADE_CLASS = "shadow-[inset_0_0_0_100vmax_rgba(0,0,0,0.32)]";
|
|
285
|
+
function pitchSquareClass(x, y) {
|
|
286
|
+
const isEven = (x + y) % 2 === 0;
|
|
287
|
+
return cn(
|
|
288
|
+
"relative aspect-square w-full",
|
|
289
|
+
isEven ? "bg-field-green-1" : "bg-field-green-2",
|
|
290
|
+
isGoalAreaSquare(x, y) && GOAL_AREA_SHADE_CLASS
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
var GRAIN_TILE_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="160" height="160"><filter id="g" x="0" y="0" width="100%" height="100%" color-interpolation-filters="sRGB"><feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="3" seed="7" stitchTiles="stitch"/><feColorMatrix type="saturate" values="0"/></filter><rect width="100%" height="100%" filter="url(#g)"/></svg>';
|
|
294
|
+
var GRAIN_TILE_URL = `url("data:image/svg+xml;utf8,${encodeURIComponent(GRAIN_TILE_SVG)}")`;
|
|
295
|
+
var VIGNETTE = "radial-gradient(120% 95% at 50% 38%, rgba(255,255,255,0.06) 0%, rgba(255,255,255,0) 42%, rgba(0,0,0,0.26) 100%)";
|
|
296
|
+
function GrassOverlay({ className }) {
|
|
297
|
+
return /* @__PURE__ */ jsxs(
|
|
298
|
+
"div",
|
|
299
|
+
{
|
|
300
|
+
"aria-hidden": "true",
|
|
301
|
+
"data-testid": "grass-overlay",
|
|
302
|
+
className: cn("absolute inset-0 pointer-events-none overflow-hidden", className),
|
|
303
|
+
children: [
|
|
304
|
+
/* @__PURE__ */ jsx(
|
|
305
|
+
"div",
|
|
306
|
+
{
|
|
307
|
+
"data-layer": "grain",
|
|
308
|
+
className: "absolute inset-0 mix-blend-overlay opacity-60",
|
|
309
|
+
style: { backgroundImage: GRAIN_TILE_URL, backgroundSize: "160px 160px" }
|
|
310
|
+
}
|
|
311
|
+
),
|
|
312
|
+
/* @__PURE__ */ jsx("div", { "data-layer": "light", className: "absolute inset-0", style: { background: VIGNETTE } })
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
var CHALK = "#f6f5ee";
|
|
318
|
+
function PitchMarkings({ className, children }) {
|
|
319
|
+
const id = useId();
|
|
320
|
+
const filterId = `${id}-chalk`;
|
|
321
|
+
return /* @__PURE__ */ jsxs(
|
|
322
|
+
"svg",
|
|
323
|
+
{
|
|
324
|
+
viewBox: "0 0 9 12",
|
|
325
|
+
preserveAspectRatio: "none",
|
|
326
|
+
className: cn("absolute inset-0 w-full h-full pointer-events-none", className),
|
|
327
|
+
"aria-hidden": "true",
|
|
328
|
+
"data-testid": "pitch-markings",
|
|
329
|
+
children: [
|
|
330
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
|
|
331
|
+
"filter",
|
|
332
|
+
{
|
|
333
|
+
id: filterId,
|
|
334
|
+
filterUnits: "userSpaceOnUse",
|
|
335
|
+
x: "-0.5",
|
|
336
|
+
y: "-0.5",
|
|
337
|
+
width: "10",
|
|
338
|
+
height: "13",
|
|
339
|
+
colorInterpolationFilters: "sRGB",
|
|
340
|
+
children: [
|
|
341
|
+
/* @__PURE__ */ jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "5.5", numOctaves: "2", seed: "3", result: "edgeNoise" }),
|
|
342
|
+
/* @__PURE__ */ jsx(
|
|
343
|
+
"feDisplacementMap",
|
|
344
|
+
{
|
|
345
|
+
in: "SourceGraphic",
|
|
346
|
+
in2: "edgeNoise",
|
|
347
|
+
scale: "0.045",
|
|
348
|
+
xChannelSelector: "R",
|
|
349
|
+
yChannelSelector: "G",
|
|
350
|
+
result: "rough"
|
|
351
|
+
}
|
|
352
|
+
),
|
|
353
|
+
/* @__PURE__ */ jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "14", numOctaves: "3", seed: "11", result: "dust" }),
|
|
354
|
+
/* @__PURE__ */ jsx(
|
|
355
|
+
"feColorMatrix",
|
|
356
|
+
{
|
|
357
|
+
in: "dust",
|
|
358
|
+
type: "matrix",
|
|
359
|
+
values: "0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.75 0 0 0 0.55",
|
|
360
|
+
result: "dustMask"
|
|
361
|
+
}
|
|
362
|
+
),
|
|
363
|
+
/* @__PURE__ */ jsx("feComposite", { in: "rough", in2: "dustMask", operator: "arithmetic", k1: "1", k2: "0", k3: "0", k4: "0" })
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
) }),
|
|
367
|
+
/* @__PURE__ */ jsx("g", { "data-layer": "halo", fill: "none", stroke: CHALK, strokeOpacity: "0.09", strokeWidth: "0.16", strokeLinecap: "round", children: /* @__PURE__ */ jsx(Markings, {}) }),
|
|
368
|
+
/* @__PURE__ */ jsx(
|
|
369
|
+
"g",
|
|
370
|
+
{
|
|
371
|
+
"data-layer": "chalk",
|
|
372
|
+
filter: `url(#${filterId})`,
|
|
373
|
+
fill: "none",
|
|
374
|
+
stroke: CHALK,
|
|
375
|
+
strokeOpacity: "0.82",
|
|
376
|
+
strokeWidth: "0.07",
|
|
377
|
+
strokeLinecap: "round",
|
|
378
|
+
strokeLinejoin: "round",
|
|
379
|
+
children: /* @__PURE__ */ jsx(Markings, {})
|
|
380
|
+
}
|
|
381
|
+
),
|
|
382
|
+
children
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
function Markings() {
|
|
388
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
389
|
+
/* @__PURE__ */ jsx("rect", { x: "0.06", y: "0.06", width: "8.88", height: "11.88" }),
|
|
390
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "0.06", width: "5", height: "1.94" }),
|
|
391
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "10", width: "5", height: "1.94" }),
|
|
392
|
+
/* @__PURE__ */ jsx("line", { x1: "0.06", y1: "6", x2: "8.94", y2: "6" }),
|
|
393
|
+
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "6", r: "1.5" }),
|
|
394
|
+
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "6", r: "0.09", fill: CHALK, fillOpacity: "0.9", stroke: "none" }),
|
|
395
|
+
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "1.5", r: "0.08", fill: CHALK, fillOpacity: "0.9", stroke: "none" }),
|
|
396
|
+
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "10.5", r: "0.08", fill: CHALK, fillOpacity: "0.9", stroke: "none" }),
|
|
397
|
+
/* @__PURE__ */ jsx("path", { d: "M 3.086,2 A 1.5,1.5 0 0 0 5.914,2" }),
|
|
398
|
+
/* @__PURE__ */ jsx("path", { d: "M 3.086,10 A 1.5,1.5 0 0 1 5.914,10" })
|
|
399
|
+
] });
|
|
400
|
+
}
|
|
401
|
+
function PitchSurface({ className, squareClassName, children }) {
|
|
402
|
+
const squares = [];
|
|
403
|
+
for (let y = PITCH_ROWS - 1; y >= 0; y--) {
|
|
404
|
+
for (let x = 0; x < PITCH_COLS; x++) {
|
|
405
|
+
squares.push(
|
|
406
|
+
/* @__PURE__ */ jsx("div", { className: cn(pitchSquareClass(x, y), squareClassName?.(x, y)) }, `${x}-${y}`)
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), style: { containerType: "inline-size" }, children: [
|
|
411
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-9 gap-[1px]", "data-testid": "pitch-squares", children: squares }),
|
|
412
|
+
/* @__PURE__ */ jsx(GrassOverlay, {}),
|
|
413
|
+
/* @__PURE__ */ jsx(PitchMarkings, {}),
|
|
414
|
+
children
|
|
415
|
+
] });
|
|
416
|
+
}
|
|
186
417
|
var COLS = 9;
|
|
187
418
|
var ROWS = 12;
|
|
188
419
|
var clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
189
|
-
|
|
420
|
+
var cellX = (x) => `${x * 100}%`;
|
|
421
|
+
var cellY = (y) => `${(ROWS - 1 - y) * 100}%`;
|
|
422
|
+
var PIECE_SLIDE = { type: "spring", stiffness: 190, damping: 28, mass: 1 };
|
|
423
|
+
var BALL_SLIDE = { type: "spring", stiffness: 300, damping: 26, mass: 0.6 };
|
|
424
|
+
function GameBoard({ userSide, showCoordinates = false, keyboardNav = true, toolbar = true }) {
|
|
190
425
|
const t = useGameT();
|
|
191
426
|
const prefersReducedMotion = useReducedMotion();
|
|
192
427
|
const {
|
|
@@ -218,6 +453,14 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
218
453
|
setInvalidClickAt({ x, y, nonce: invalidClickNonceRef.current });
|
|
219
454
|
};
|
|
220
455
|
const [hoveredPassAt, setHoveredPassAt] = useState(null);
|
|
456
|
+
const [movingIds, setMovingIds] = useState(() => /* @__PURE__ */ new Set());
|
|
457
|
+
const setMoving = (id, moving) => setMovingIds((prev) => {
|
|
458
|
+
if (prev.has(id) === moving) return prev;
|
|
459
|
+
const next = new Set(prev);
|
|
460
|
+
if (moving) next.add(id);
|
|
461
|
+
else next.delete(id);
|
|
462
|
+
return next;
|
|
463
|
+
});
|
|
221
464
|
useEffect(() => {
|
|
222
465
|
if (!invalidClickAt) return;
|
|
223
466
|
const id = setTimeout(() => setInvalidClickAt(null), 100);
|
|
@@ -414,8 +657,6 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
414
657
|
const squares = [];
|
|
415
658
|
for (let y = ROWS - 1; y >= 0; y--) {
|
|
416
659
|
for (let x = 0; x < COLS; x++) {
|
|
417
|
-
const isGoalArea = x >= 2 && x <= 6 && (y >= 0 && y <= 1 || y >= 10 && y <= 11);
|
|
418
|
-
const isEven = (x + y) % 2 === 0;
|
|
419
660
|
const isValidMove = validMoves.some((m) => m.x === x && m.y === y);
|
|
420
661
|
const isValidPass = validPasses.some((p) => p.x === x && p.y === y);
|
|
421
662
|
const isAmbiguous = isValidMove && isValidPass;
|
|
@@ -437,9 +678,8 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
437
678
|
},
|
|
438
679
|
onMouseLeave: () => setHoveredPassAt(null),
|
|
439
680
|
className: cn(
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
isGoalArea && "bg-[#1a3a18] ring-1 ring-inset ring-emerald-500/30",
|
|
681
|
+
pitchSquareClass(x, y),
|
|
682
|
+
"flex items-center justify-center cursor-pointer",
|
|
443
683
|
!isValidMove && !isValidPass && isLastMove && "bg-last-move-highlight/20",
|
|
444
684
|
// §8: pulsing warning ring on enemy goal area
|
|
445
685
|
isOffsideRisk && isEnemyGoalArea && !isValidMove && !isValidPass && "ring-2 ring-inset ring-warning/60",
|
|
@@ -508,7 +748,7 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
508
748
|
}
|
|
509
749
|
return squares;
|
|
510
750
|
};
|
|
511
|
-
const board = /* @__PURE__ */
|
|
751
|
+
const board = /* @__PURE__ */ jsxs(
|
|
512
752
|
"div",
|
|
513
753
|
{
|
|
514
754
|
className: cn(
|
|
@@ -525,26 +765,57 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
525
765
|
"aria-label": "Game board \u2014 arrow keys to move the cursor, Enter to act",
|
|
526
766
|
onKeyDown: handleKeyDown
|
|
527
767
|
} : {},
|
|
528
|
-
children:
|
|
529
|
-
/* @__PURE__ */
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
768
|
+
children: [
|
|
769
|
+
toolbar && /* @__PURE__ */ jsxs("div", { className: "hidden md:flex items-center justify-between gap-2 px-2.5 py-1", "data-testid": "board-toolbar", children: [
|
|
770
|
+
/* @__PURE__ */ jsx(BallHolderChip, {}),
|
|
771
|
+
keyboardNav && /* @__PURE__ */ jsxs(
|
|
772
|
+
"div",
|
|
773
|
+
{
|
|
774
|
+
ref: shortcutsRef,
|
|
775
|
+
className: "relative",
|
|
776
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
777
|
+
children: [
|
|
778
|
+
/* @__PURE__ */ jsx(
|
|
779
|
+
"button",
|
|
780
|
+
{
|
|
781
|
+
type: "button",
|
|
782
|
+
onClick: (e) => {
|
|
783
|
+
e.stopPropagation();
|
|
784
|
+
setShortcutsOpen((o) => !o);
|
|
785
|
+
},
|
|
786
|
+
"aria-label": t("shortcuts.buttonLabel"),
|
|
787
|
+
"aria-expanded": shortcutsOpen,
|
|
788
|
+
className: "w-8 h-8 flex items-center justify-center rounded-full bg-bg-secondary/80 border border-border-subtle text-fg-muted hover:text-fg-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-green",
|
|
789
|
+
children: /* @__PURE__ */ jsx(HelpCircle, { size: 16, strokeWidth: 2, "aria-hidden": "true" })
|
|
790
|
+
}
|
|
791
|
+
),
|
|
792
|
+
shortcutsOpen && /* @__PURE__ */ jsxs(
|
|
793
|
+
"div",
|
|
794
|
+
{
|
|
795
|
+
className: "absolute top-full right-0 mt-1 z-50 w-max max-w-[220px] bg-bg-secondary border border-border-subtle rounded-md shadow-xl p-2.5 pointer-events-auto",
|
|
796
|
+
onClick: (e) => e.stopPropagation(),
|
|
797
|
+
children: [
|
|
798
|
+
/* @__PURE__ */ jsx("p", { className: "font-inter text-[11px] font-semibold text-fg-primary mb-1.5", children: t("shortcuts.title") }),
|
|
799
|
+
/* @__PURE__ */ jsx(KeyboardShortcutsList, {})
|
|
800
|
+
]
|
|
801
|
+
}
|
|
802
|
+
)
|
|
803
|
+
]
|
|
804
|
+
}
|
|
805
|
+
)
|
|
806
|
+
] }),
|
|
807
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", style: { containerType: "inline-size" }, children: [
|
|
808
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-9 gap-[1px]", children: renderSquares() }),
|
|
809
|
+
/* @__PURE__ */ jsx(GrassOverlay, {}),
|
|
810
|
+
/* @__PURE__ */ jsx(PitchMarkings, {}),
|
|
811
|
+
/* @__PURE__ */ jsx(
|
|
812
|
+
"svg",
|
|
813
|
+
{
|
|
814
|
+
viewBox: "0 0 9 12",
|
|
815
|
+
preserveAspectRatio: "none",
|
|
816
|
+
className: "absolute inset-0 w-full h-full pointer-events-none",
|
|
817
|
+
"aria-hidden": "true",
|
|
818
|
+
children: hoveredPassAt && passCarrier && /* @__PURE__ */ jsx(
|
|
548
819
|
"line",
|
|
549
820
|
{
|
|
550
821
|
"data-testid": "pass-trajectory-line",
|
|
@@ -558,165 +829,110 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
558
829
|
strokeLinecap: "round"
|
|
559
830
|
}
|
|
560
831
|
)
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
832
|
+
}
|
|
833
|
+
),
|
|
834
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute inset-0 pointer-events-none", "data-testid": "pieces-layer", children: [
|
|
835
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "sync", children: boardState.pieces.map((piece) => {
|
|
836
|
+
const isPickupCarrier = pickupCarrierId === piece.id;
|
|
837
|
+
const pieceTransition = isPickupCarrier ? { duration: PICKUP_DURATION, ease: "linear" } : PIECE_SLIDE;
|
|
838
|
+
return /* @__PURE__ */ jsx(
|
|
839
|
+
motion.div,
|
|
840
|
+
{
|
|
841
|
+
"data-piece-id": piece.id,
|
|
842
|
+
initial: false,
|
|
843
|
+
animate: { x: cellX(piece.pos.x), y: cellY(piece.pos.y) },
|
|
844
|
+
transition: pieceTransition,
|
|
845
|
+
onAnimationStart: () => setMoving(piece.id, true),
|
|
846
|
+
onAnimationComplete: () => setMoving(piece.id, false),
|
|
847
|
+
style: {
|
|
848
|
+
position: "absolute",
|
|
849
|
+
left: 0,
|
|
850
|
+
top: 0,
|
|
851
|
+
width: `${100 / COLS}%`,
|
|
852
|
+
height: `${100 / ROWS}%`,
|
|
853
|
+
willChange: "transform"
|
|
854
|
+
},
|
|
855
|
+
className: "flex items-center justify-center pointer-events-auto",
|
|
856
|
+
children: /* @__PURE__ */ jsx(
|
|
857
|
+
GamePiece,
|
|
858
|
+
{
|
|
859
|
+
piece,
|
|
860
|
+
isSelected: selectedPieceId === piece.id,
|
|
861
|
+
hasBall: boardState.ball.holderId === piece.id,
|
|
862
|
+
isMoving: movingIds.has(piece.id),
|
|
863
|
+
onClick: (e) => handlePieceClick(piece.id, piece.pos.x, piece.pos.y, e)
|
|
864
|
+
}
|
|
865
|
+
)
|
|
576
866
|
},
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
867
|
+
piece.id
|
|
868
|
+
);
|
|
869
|
+
}) }),
|
|
870
|
+
(() => {
|
|
871
|
+
const targetX = cellX(ball.pos.x);
|
|
872
|
+
const targetY = cellY(ball.pos.y);
|
|
873
|
+
let animate;
|
|
874
|
+
let transition;
|
|
875
|
+
if (isPickupOnMove && prevBall) {
|
|
876
|
+
const prevX = cellX(prevBall.pos.x);
|
|
877
|
+
const prevY = cellY(prevBall.pos.y);
|
|
878
|
+
const pulseStart = Math.max(0.05, pickupProportion - 0.06);
|
|
879
|
+
animate = {
|
|
880
|
+
x: [prevX, prevX, prevX, targetX],
|
|
881
|
+
y: [prevY, prevY, prevY, targetY],
|
|
882
|
+
scale: [1, 1, 1.35, 1]
|
|
883
|
+
};
|
|
884
|
+
transition = { duration: PICKUP_DURATION, times: [0, pulseStart, pickupProportion, 1], ease: "linear" };
|
|
885
|
+
} else {
|
|
886
|
+
animate = { x: targetX, y: targetY, scale: 1 };
|
|
887
|
+
transition = ball.holderId ? PIECE_SLIDE : BALL_SLIDE;
|
|
888
|
+
}
|
|
889
|
+
return /* @__PURE__ */ jsx(
|
|
890
|
+
motion.div,
|
|
891
|
+
{
|
|
892
|
+
initial: false,
|
|
893
|
+
animate,
|
|
894
|
+
transition,
|
|
895
|
+
style: {
|
|
896
|
+
position: "absolute",
|
|
897
|
+
left: 0,
|
|
898
|
+
top: 0,
|
|
899
|
+
width: `${100 / COLS}%`,
|
|
900
|
+
height: `${100 / ROWS}%`,
|
|
901
|
+
zIndex: 50,
|
|
902
|
+
willChange: "transform"
|
|
903
|
+
},
|
|
904
|
+
className: "flex items-center justify-center pointer-events-none",
|
|
905
|
+
children: /* @__PURE__ */ jsx("div", { className: "w-[60%] h-[60%]", children: /* @__PURE__ */ jsx(Football, {}) })
|
|
582
906
|
},
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
piece,
|
|
588
|
-
isSelected: selectedPieceId === piece.id,
|
|
589
|
-
hasBall: boardState.ball.holderId === piece.id,
|
|
590
|
-
onClick: (e) => handlePieceClick(piece.id, piece.pos.x, piece.pos.y, e)
|
|
591
|
-
}
|
|
592
|
-
)
|
|
593
|
-
},
|
|
594
|
-
piece.id
|
|
595
|
-
);
|
|
596
|
-
}) }),
|
|
597
|
-
(() => {
|
|
598
|
-
const targetX = ball.pos.x / COLS * 100;
|
|
599
|
-
const targetY = (ROWS - 1 - ball.pos.y) / ROWS * 100;
|
|
600
|
-
let animate;
|
|
601
|
-
let transition;
|
|
602
|
-
if (isPickupOnMove && prevBall) {
|
|
603
|
-
const prevX = prevBall.pos.x / COLS * 100;
|
|
604
|
-
const prevY = (ROWS - 1 - prevBall.pos.y) / ROWS * 100;
|
|
605
|
-
const pulseStart = Math.max(0.05, pickupProportion - 0.06);
|
|
606
|
-
animate = {
|
|
607
|
-
left: [`${prevX}%`, `${prevX}%`, `${prevX}%`, `${targetX}%`],
|
|
608
|
-
top: [`${prevY}%`, `${prevY}%`, `${prevY}%`, `${targetY}%`],
|
|
609
|
-
scale: [1, 1, 1.35, 1]
|
|
610
|
-
};
|
|
611
|
-
transition = { duration: PICKUP_DURATION, times: [0, pulseStart, pickupProportion, 1], ease: "linear" };
|
|
612
|
-
} else {
|
|
613
|
-
animate = { left: `${targetX}%`, top: `${targetY}%`, scale: 1 };
|
|
614
|
-
transition = { type: "spring", stiffness: 300, damping: 30, mass: 0.5 };
|
|
615
|
-
}
|
|
616
|
-
return /* @__PURE__ */ jsx(
|
|
907
|
+
"ball"
|
|
908
|
+
);
|
|
909
|
+
})(),
|
|
910
|
+
invalidClickAt && /* @__PURE__ */ jsx(
|
|
617
911
|
motion.div,
|
|
618
912
|
{
|
|
913
|
+
"data-testid": "invalid-action-shake",
|
|
914
|
+
"aria-hidden": "true",
|
|
619
915
|
initial: false,
|
|
620
|
-
animate,
|
|
621
|
-
transition,
|
|
916
|
+
animate: prefersReducedMotion ? { opacity: [0.9, 0] } : { x: [0, -3, 3, -3, 3, 0] },
|
|
917
|
+
transition: { duration: 0.08 },
|
|
622
918
|
style: {
|
|
623
919
|
position: "absolute",
|
|
920
|
+
left: `${invalidClickAt.x / COLS * 100}%`,
|
|
921
|
+
top: `${(ROWS - 1 - invalidClickAt.y) / ROWS * 100}%`,
|
|
624
922
|
width: `${100 / COLS}%`,
|
|
625
|
-
height: `${100 / ROWS}
|
|
626
|
-
zIndex: 50
|
|
923
|
+
height: `${100 / ROWS}%`
|
|
627
924
|
},
|
|
628
|
-
className: "
|
|
629
|
-
children: /* @__PURE__ */ jsx("div", { className: "w-[60%] h-[60%]", children: /* @__PURE__ */ jsx(Football, {}) })
|
|
630
|
-
},
|
|
631
|
-
"ball"
|
|
632
|
-
);
|
|
633
|
-
})(),
|
|
634
|
-
invalidClickAt && /* @__PURE__ */ jsx(
|
|
635
|
-
motion.div,
|
|
636
|
-
{
|
|
637
|
-
"data-testid": "invalid-action-shake",
|
|
638
|
-
"aria-hidden": "true",
|
|
639
|
-
initial: false,
|
|
640
|
-
animate: prefersReducedMotion ? { opacity: [0.9, 0] } : { x: [0, -3, 3, -3, 3, 0] },
|
|
641
|
-
transition: { duration: 0.08 },
|
|
642
|
-
style: {
|
|
643
|
-
position: "absolute",
|
|
644
|
-
left: `${invalidClickAt.x / COLS * 100}%`,
|
|
645
|
-
top: `${(ROWS - 1 - invalidClickAt.y) / ROWS * 100}%`,
|
|
646
|
-
width: `${100 / COLS}%`,
|
|
647
|
-
height: `${100 / ROWS}%`
|
|
925
|
+
className: "ring-2 ring-inset ring-danger/70 rounded-sm"
|
|
648
926
|
},
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
keyboardNav && /* @__PURE__ */ jsxs(
|
|
659
|
-
"div",
|
|
660
|
-
{
|
|
661
|
-
ref: shortcutsRef,
|
|
662
|
-
className: "hidden md:block absolute top-2 right-2 z-40",
|
|
663
|
-
onKeyDown: (e) => e.stopPropagation(),
|
|
664
|
-
children: [
|
|
665
|
-
/* @__PURE__ */ jsx(
|
|
666
|
-
"button",
|
|
667
|
-
{
|
|
668
|
-
type: "button",
|
|
669
|
-
onClick: (e) => {
|
|
670
|
-
e.stopPropagation();
|
|
671
|
-
setShortcutsOpen((o) => !o);
|
|
672
|
-
},
|
|
673
|
-
"aria-label": t("shortcuts.buttonLabel"),
|
|
674
|
-
"aria-expanded": shortcutsOpen,
|
|
675
|
-
className: "w-11 h-11 flex items-center justify-center rounded-full bg-bg-secondary/80 border border-border-subtle text-fg-muted hover:text-fg-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-green backdrop-blur-sm",
|
|
676
|
-
children: /* @__PURE__ */ jsx(HelpCircle, { size: 16, strokeWidth: 2, "aria-hidden": "true" })
|
|
677
|
-
}
|
|
678
|
-
),
|
|
679
|
-
shortcutsOpen && /* @__PURE__ */ jsxs(
|
|
680
|
-
"div",
|
|
681
|
-
{
|
|
682
|
-
className: "absolute top-full right-0 mt-1 z-50 w-max max-w-[220px] bg-bg-secondary border border-border-subtle rounded-md shadow-xl p-2.5 pointer-events-auto",
|
|
683
|
-
onClick: (e) => e.stopPropagation(),
|
|
684
|
-
children: [
|
|
685
|
-
/* @__PURE__ */ jsx("p", { className: "font-inter text-[11px] font-semibold text-fg-primary mb-1.5", children: t("shortcuts.title") }),
|
|
686
|
-
/* @__PURE__ */ jsxs("ul", { className: "font-mono text-[10px] text-fg-secondary leading-relaxed", children: [
|
|
687
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
688
|
-
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "\u2191\u2193\u2190\u2192" }),
|
|
689
|
-
" ",
|
|
690
|
-
t("shortcuts.arrows")
|
|
691
|
-
] }),
|
|
692
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
693
|
-
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "Enter" }),
|
|
694
|
-
" ",
|
|
695
|
-
t("shortcuts.select")
|
|
696
|
-
] }),
|
|
697
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
698
|
-
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "M" }),
|
|
699
|
-
" ",
|
|
700
|
-
t("shortcuts.move")
|
|
701
|
-
] }),
|
|
702
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
703
|
-
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "P" }),
|
|
704
|
-
" ",
|
|
705
|
-
t("shortcuts.pass")
|
|
706
|
-
] }),
|
|
707
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
708
|
-
/* @__PURE__ */ jsx("kbd", { className: "text-fg-primary", children: "Esc" }),
|
|
709
|
-
" ",
|
|
710
|
-
t("shortcuts.cancel")
|
|
711
|
-
] })
|
|
712
|
-
] })
|
|
713
|
-
]
|
|
714
|
-
}
|
|
715
|
-
)
|
|
716
|
-
]
|
|
717
|
-
}
|
|
718
|
-
)
|
|
719
|
-
] })
|
|
927
|
+
invalidClickAt.nonce
|
|
928
|
+
)
|
|
929
|
+
] }),
|
|
930
|
+
isOffsideRisk && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 z-30 flex items-center gap-1.5 px-3 py-1.5 bg-warning/20 border border-warning/50 rounded-full font-inter text-xs font-semibold text-warning pointer-events-none whitespace-nowrap backdrop-blur-sm", children: [
|
|
931
|
+
"\u26A0 ",
|
|
932
|
+
t("offsideWarning")
|
|
933
|
+
] })
|
|
934
|
+
] })
|
|
935
|
+
]
|
|
720
936
|
}
|
|
721
937
|
);
|
|
722
938
|
if (!showCoordinates) return board;
|
|
@@ -1244,77 +1460,31 @@ var COLS2 = 9;
|
|
|
1244
1460
|
var ROWS2 = 12;
|
|
1245
1461
|
function StaticGameBoard() {
|
|
1246
1462
|
const boardState = useMemo(() => getInitialBoardState("white"), []);
|
|
1247
|
-
const renderSquares = () => {
|
|
1248
|
-
const squares = [];
|
|
1249
|
-
for (let y = ROWS2 - 1; y >= 0; y--) {
|
|
1250
|
-
for (let x = 0; x < COLS2; x++) {
|
|
1251
|
-
const isGoalArea = x >= 2 && x <= 6 && (y >= 0 && y <= 1 || y >= 10 && y <= 11);
|
|
1252
|
-
const isEven = (x + y) % 2 === 0;
|
|
1253
|
-
squares.push(
|
|
1254
|
-
/* @__PURE__ */ jsx(
|
|
1255
|
-
"div",
|
|
1256
|
-
{
|
|
1257
|
-
className: cn(
|
|
1258
|
-
"relative aspect-square w-full",
|
|
1259
|
-
isEven ? "bg-[#2d5a27]" : "bg-[#356a2d]",
|
|
1260
|
-
isGoalArea && "bg-[#1a3a18] ring-1 ring-inset ring-emerald-500/30"
|
|
1261
|
-
)
|
|
1262
|
-
},
|
|
1263
|
-
`${x}-${y}`
|
|
1264
|
-
)
|
|
1265
|
-
);
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
return squares;
|
|
1269
|
-
};
|
|
1270
1463
|
return /* @__PURE__ */ jsxs("div", { className: "relative w-full overflow-hidden rounded-xl shadow-2xl border-4 border-[#1a3317] bg-[#1a3317]", children: [
|
|
1271
|
-
/* @__PURE__ */
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
children: [
|
|
1281
|
-
/* @__PURE__ */ jsx("rect", { x: "2", y: "0", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
|
|
1282
|
-
/* @__PURE__ */ jsx("rect", { x: "2", y: "10", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
|
|
1283
|
-
/* @__PURE__ */ jsx("line", { x1: "0", y1: "6", x2: "9", y2: "6", stroke: "white", strokeOpacity: "0.35", strokeWidth: "0.05" }),
|
|
1284
|
-
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "6", r: "1.5", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
|
|
1285
|
-
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "6", r: "0.12", fill: "white", fillOpacity: "0.5" }),
|
|
1286
|
-
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "1.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
|
|
1287
|
-
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "10.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
|
|
1288
|
-
/* @__PURE__ */ jsx("path", { d: "M 3.086,2 A 1.5,1.5 0 0 0 5.914,2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
|
|
1289
|
-
/* @__PURE__ */ jsx("path", { d: "M 3.086,10 A 1.5,1.5 0 0 1 5.914,10", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" })
|
|
1290
|
-
]
|
|
1291
|
-
}
|
|
1292
|
-
),
|
|
1293
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 pointer-events-none", children: boardState.pieces.map((piece) => /* @__PURE__ */ jsx(
|
|
1294
|
-
"div",
|
|
1295
|
-
{
|
|
1296
|
-
style: {
|
|
1297
|
-
position: "absolute",
|
|
1298
|
-
left: `${piece.pos.x / COLS2 * 100}%`,
|
|
1299
|
-
top: `${(ROWS2 - 1 - piece.pos.y) / ROWS2 * 100}%`,
|
|
1300
|
-
width: `${100 / COLS2}%`,
|
|
1301
|
-
height: `${100 / ROWS2}%`
|
|
1302
|
-
},
|
|
1303
|
-
className: "flex items-center justify-center",
|
|
1304
|
-
children: /* @__PURE__ */ jsx(
|
|
1305
|
-
GamePiece,
|
|
1306
|
-
{
|
|
1307
|
-
piece,
|
|
1308
|
-
isSelected: false,
|
|
1309
|
-
hasBall: boardState.ball.holderId === piece.id,
|
|
1310
|
-
onClick: () => {
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
)
|
|
1464
|
+
/* @__PURE__ */ jsx(PitchSurface, { children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pointer-events-none", children: boardState.pieces.map((piece) => /* @__PURE__ */ jsx(
|
|
1465
|
+
"div",
|
|
1466
|
+
{
|
|
1467
|
+
style: {
|
|
1468
|
+
position: "absolute",
|
|
1469
|
+
left: `${piece.pos.x / COLS2 * 100}%`,
|
|
1470
|
+
top: `${(ROWS2 - 1 - piece.pos.y) / ROWS2 * 100}%`,
|
|
1471
|
+
width: `${100 / COLS2}%`,
|
|
1472
|
+
height: `${100 / ROWS2}%`
|
|
1314
1473
|
},
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1474
|
+
className: "flex items-center justify-center",
|
|
1475
|
+
children: /* @__PURE__ */ jsx(
|
|
1476
|
+
GamePiece,
|
|
1477
|
+
{
|
|
1478
|
+
piece,
|
|
1479
|
+
isSelected: false,
|
|
1480
|
+
hasBall: boardState.ball.holderId === piece.id,
|
|
1481
|
+
onClick: () => {
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
)
|
|
1485
|
+
},
|
|
1486
|
+
piece.id
|
|
1487
|
+
)) }) }),
|
|
1318
1488
|
/* @__PURE__ */ jsx(
|
|
1319
1489
|
"div",
|
|
1320
1490
|
{
|
|
@@ -1520,6 +1690,6 @@ function HistoryChip({ lastMove, onClick, className }) {
|
|
|
1520
1690
|
);
|
|
1521
1691
|
}
|
|
1522
1692
|
|
|
1523
|
-
export { ActionPoints, Avatar, AvatarFallback, AvatarImage, Button, ConfirmDialog, EventToast, Football, GAME_I18N_KEYS, GameBoard, GameControls, GameI18nProvider, GamePiece, MiniScoreboard, MobileHistory, MoveHistory, Scoreboard, SelectedPieceDetail, StaticGameBoard, TurnBanner, cn, useGameT };
|
|
1693
|
+
export { ActionPoints, Avatar, AvatarFallback, AvatarImage, BallHolderChip, Button, ConfirmDialog, EventToast, Football, GAME_I18N_KEYS, GOAL_AREA_SHADE_CLASS, GameBoard, GameControls, GameI18nProvider, GamePiece, GrassOverlay, KeyboardShortcutsList, MiniScoreboard, MobileHistory, MoveHistory, PITCH_COLS, PITCH_ROWS, PitchMarkings, PitchSurface, Scoreboard, SelectedPieceDetail, StaticGameBoard, TurnBanner, cn, isGoalAreaSquare, pitchSquareClass, useGameT };
|
|
1524
1694
|
//# sourceMappingURL=index.js.map
|
|
1525
1695
|
//# sourceMappingURL=index.js.map
|