@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.cjs
CHANGED
|
@@ -74,26 +74,66 @@ var BLACK_PIECE_STYLE = {
|
|
|
74
74
|
border: "1px solid rgba(0,0,0,0.55)",
|
|
75
75
|
color: "#fafafa"
|
|
76
76
|
};
|
|
77
|
+
var ON_BOARD_CHIP_STYLE = {
|
|
78
|
+
white: {
|
|
79
|
+
...WHITE_PIECE_STYLE,
|
|
80
|
+
boxShadow: [
|
|
81
|
+
"inset 0 1.5px 1px rgba(255,255,255,0.95)",
|
|
82
|
+
"inset 0 -2px 3px rgba(0,0,0,0.18)",
|
|
83
|
+
"0 1px 1px rgba(0,0,0,0.35)"
|
|
84
|
+
].join(", ")
|
|
85
|
+
},
|
|
86
|
+
black: {
|
|
87
|
+
...BLACK_PIECE_STYLE,
|
|
88
|
+
boxShadow: [
|
|
89
|
+
"inset 0 1.5px 1px rgba(255,255,255,0.22)",
|
|
90
|
+
"inset 0 -2px 3px rgba(0,0,0,0.6)",
|
|
91
|
+
"0 1px 1px rgba(0,0,0,0.5)"
|
|
92
|
+
].join(", ")
|
|
93
|
+
}
|
|
94
|
+
};
|
|
77
95
|
var MOVED_STYLE = {
|
|
78
96
|
filter: "saturate(0.15) brightness(0.75)"
|
|
79
97
|
};
|
|
80
|
-
function GamePiece({ piece, isSelected, hasBall, onClick }) {
|
|
81
|
-
const
|
|
82
|
-
const style = piece.hasMovedThisTurn ? { ...baseStyle, ...MOVED_STYLE } : baseStyle;
|
|
98
|
+
function GamePiece({ piece, isSelected, hasBall, onClick, isMoving = false }) {
|
|
99
|
+
const chipStyle = ON_BOARD_CHIP_STYLE[piece.side];
|
|
83
100
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
84
101
|
"div",
|
|
85
102
|
{
|
|
86
103
|
onClick,
|
|
87
|
-
style,
|
|
104
|
+
style: piece.hasMovedThisTurn ? MOVED_STYLE : void 0,
|
|
88
105
|
className: cn(
|
|
89
|
-
"relative w-[88%] h-[88%]
|
|
106
|
+
"relative w-[88%] h-[88%] rounded-full cursor-pointer z-10 transition-transform duration-200 ease-out motion-reduce:transition-none",
|
|
90
107
|
isSelected && "ring-4 ring-primary scale-110 z-30",
|
|
108
|
+
isMoving && "scale-[1.08] z-40",
|
|
91
109
|
piece.hasMovedThisTurn && "opacity-70"
|
|
92
110
|
),
|
|
93
111
|
children: [
|
|
94
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
95
|
-
|
|
96
|
-
|
|
112
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
113
|
+
"div",
|
|
114
|
+
{
|
|
115
|
+
"aria-hidden": "true",
|
|
116
|
+
"data-testid": "piece-shadow",
|
|
117
|
+
"data-lifted": isMoving ? "true" : "false",
|
|
118
|
+
className: cn(
|
|
119
|
+
"absolute inset-0 rounded-full bg-black pointer-events-none transition-all duration-200 ease-out motion-reduce:transition-none",
|
|
120
|
+
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]"
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
125
|
+
"div",
|
|
126
|
+
{
|
|
127
|
+
"data-testid": "piece-chip",
|
|
128
|
+
style: chipStyle,
|
|
129
|
+
className: "absolute inset-0 rounded-full flex items-center justify-center",
|
|
130
|
+
children: [
|
|
131
|
+
/* @__PURE__ */ jsxRuntime.jsx(PieceIcon, { type: piece.type, side: piece.side }),
|
|
132
|
+
hasBall && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 rounded-full ring-2 ring-orange-400 pointer-events-none" }),
|
|
133
|
+
isSelected && /* @__PURE__ */ jsxRuntime.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" })
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
)
|
|
97
137
|
]
|
|
98
138
|
}
|
|
99
139
|
);
|
|
@@ -149,6 +189,7 @@ var Football = ({ className }) => {
|
|
|
149
189
|
var STATIC_I18N_KEYS = [
|
|
150
190
|
"actionPointsAriaLabel",
|
|
151
191
|
"actionPointsShort",
|
|
192
|
+
"ballHolder",
|
|
152
193
|
"endTurn",
|
|
153
194
|
"endTurnConfirm",
|
|
154
195
|
"endTurnConfirmDescription",
|
|
@@ -204,10 +245,204 @@ function GameI18nProvider({ t, children }) {
|
|
|
204
245
|
function useGameT() {
|
|
205
246
|
return React.useContext(GameI18nContext);
|
|
206
247
|
}
|
|
248
|
+
function BallHolderChip({ className }) {
|
|
249
|
+
const t = useGameT();
|
|
250
|
+
const boardState = chunkLTFNSTAQ_cjs.useGameStore((s) => s.boardState);
|
|
251
|
+
const holder = boardState?.pieces.find((p) => p.id === boardState.ball.holderId) ?? null;
|
|
252
|
+
if (!holder) return null;
|
|
253
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-1.5 min-h-[1.75rem]", className), "aria-live": "polite", children: [
|
|
254
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
255
|
+
"div",
|
|
256
|
+
{
|
|
257
|
+
style: holder.side === "white" ? WHITE_PIECE_STYLE : BLACK_PIECE_STYLE,
|
|
258
|
+
className: "relative w-7 h-7 flex items-center justify-center rounded-full shrink-0",
|
|
259
|
+
children: [
|
|
260
|
+
/* @__PURE__ */ jsxRuntime.jsx(PieceIcon, { type: holder.type, side: holder.side }),
|
|
261
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("div", { className: "w-2.5 h-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) }) })
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
),
|
|
265
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-inter text-[11px] text-fg-secondary", children: [
|
|
266
|
+
t("ballHolder"),
|
|
267
|
+
": ",
|
|
268
|
+
t(`pieces.${holder.type}`)
|
|
269
|
+
] })
|
|
270
|
+
] });
|
|
271
|
+
}
|
|
272
|
+
function KeyboardShortcutsList({ className }) {
|
|
273
|
+
const t = useGameT();
|
|
274
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: cn("font-mono text-[10px] text-fg-secondary leading-relaxed", className), children: [
|
|
275
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
276
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "\u2191\u2193\u2190\u2192" }),
|
|
277
|
+
" ",
|
|
278
|
+
t("shortcuts.arrows")
|
|
279
|
+
] }),
|
|
280
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
281
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Enter" }),
|
|
282
|
+
" ",
|
|
283
|
+
t("shortcuts.select")
|
|
284
|
+
] }),
|
|
285
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
286
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "M" }),
|
|
287
|
+
" ",
|
|
288
|
+
t("shortcuts.move")
|
|
289
|
+
] }),
|
|
290
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
291
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "P" }),
|
|
292
|
+
" ",
|
|
293
|
+
t("shortcuts.pass")
|
|
294
|
+
] }),
|
|
295
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
296
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Esc" }),
|
|
297
|
+
" ",
|
|
298
|
+
t("shortcuts.cancel")
|
|
299
|
+
] })
|
|
300
|
+
] });
|
|
301
|
+
}
|
|
302
|
+
var PITCH_COLS = 9;
|
|
303
|
+
var PITCH_ROWS = 12;
|
|
304
|
+
var isGoalAreaSquare = (x, y) => x >= 2 && x <= 6 && (y >= 0 && y <= 1 || y >= PITCH_ROWS - 2 && y <= PITCH_ROWS - 1);
|
|
305
|
+
var GOAL_AREA_SHADE_CLASS = "shadow-[inset_0_0_0_100vmax_rgba(0,0,0,0.32)]";
|
|
306
|
+
function pitchSquareClass(x, y) {
|
|
307
|
+
const isEven = (x + y) % 2 === 0;
|
|
308
|
+
return cn(
|
|
309
|
+
"relative aspect-square w-full",
|
|
310
|
+
isEven ? "bg-field-green-1" : "bg-field-green-2",
|
|
311
|
+
isGoalAreaSquare(x, y) && GOAL_AREA_SHADE_CLASS
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
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>';
|
|
315
|
+
var GRAIN_TILE_URL = `url("data:image/svg+xml;utf8,${encodeURIComponent(GRAIN_TILE_SVG)}")`;
|
|
316
|
+
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%)";
|
|
317
|
+
function GrassOverlay({ className }) {
|
|
318
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
319
|
+
"div",
|
|
320
|
+
{
|
|
321
|
+
"aria-hidden": "true",
|
|
322
|
+
"data-testid": "grass-overlay",
|
|
323
|
+
className: cn("absolute inset-0 pointer-events-none overflow-hidden", className),
|
|
324
|
+
children: [
|
|
325
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
326
|
+
"div",
|
|
327
|
+
{
|
|
328
|
+
"data-layer": "grain",
|
|
329
|
+
className: "absolute inset-0 mix-blend-overlay opacity-60",
|
|
330
|
+
style: { backgroundImage: GRAIN_TILE_URL, backgroundSize: "160px 160px" }
|
|
331
|
+
}
|
|
332
|
+
),
|
|
333
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-layer": "light", className: "absolute inset-0", style: { background: VIGNETTE } })
|
|
334
|
+
]
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
var CHALK = "#f6f5ee";
|
|
339
|
+
function PitchMarkings({ className, children }) {
|
|
340
|
+
const id = React.useId();
|
|
341
|
+
const filterId = `${id}-chalk`;
|
|
342
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
343
|
+
"svg",
|
|
344
|
+
{
|
|
345
|
+
viewBox: "0 0 9 12",
|
|
346
|
+
preserveAspectRatio: "none",
|
|
347
|
+
className: cn("absolute inset-0 w-full h-full pointer-events-none", className),
|
|
348
|
+
"aria-hidden": "true",
|
|
349
|
+
"data-testid": "pitch-markings",
|
|
350
|
+
children: [
|
|
351
|
+
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
352
|
+
"filter",
|
|
353
|
+
{
|
|
354
|
+
id: filterId,
|
|
355
|
+
filterUnits: "userSpaceOnUse",
|
|
356
|
+
x: "-0.5",
|
|
357
|
+
y: "-0.5",
|
|
358
|
+
width: "10",
|
|
359
|
+
height: "13",
|
|
360
|
+
colorInterpolationFilters: "sRGB",
|
|
361
|
+
children: [
|
|
362
|
+
/* @__PURE__ */ jsxRuntime.jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "5.5", numOctaves: "2", seed: "3", result: "edgeNoise" }),
|
|
363
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
364
|
+
"feDisplacementMap",
|
|
365
|
+
{
|
|
366
|
+
in: "SourceGraphic",
|
|
367
|
+
in2: "edgeNoise",
|
|
368
|
+
scale: "0.045",
|
|
369
|
+
xChannelSelector: "R",
|
|
370
|
+
yChannelSelector: "G",
|
|
371
|
+
result: "rough"
|
|
372
|
+
}
|
|
373
|
+
),
|
|
374
|
+
/* @__PURE__ */ jsxRuntime.jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "14", numOctaves: "3", seed: "11", result: "dust" }),
|
|
375
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
376
|
+
"feColorMatrix",
|
|
377
|
+
{
|
|
378
|
+
in: "dust",
|
|
379
|
+
type: "matrix",
|
|
380
|
+
values: "0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.75 0 0 0 0.55",
|
|
381
|
+
result: "dustMask"
|
|
382
|
+
}
|
|
383
|
+
),
|
|
384
|
+
/* @__PURE__ */ jsxRuntime.jsx("feComposite", { in: "rough", in2: "dustMask", operator: "arithmetic", k1: "1", k2: "0", k3: "0", k4: "0" })
|
|
385
|
+
]
|
|
386
|
+
}
|
|
387
|
+
) }),
|
|
388
|
+
/* @__PURE__ */ jsxRuntime.jsx("g", { "data-layer": "halo", fill: "none", stroke: CHALK, strokeOpacity: "0.09", strokeWidth: "0.16", strokeLinecap: "round", children: /* @__PURE__ */ jsxRuntime.jsx(Markings, {}) }),
|
|
389
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
390
|
+
"g",
|
|
391
|
+
{
|
|
392
|
+
"data-layer": "chalk",
|
|
393
|
+
filter: `url(#${filterId})`,
|
|
394
|
+
fill: "none",
|
|
395
|
+
stroke: CHALK,
|
|
396
|
+
strokeOpacity: "0.82",
|
|
397
|
+
strokeWidth: "0.07",
|
|
398
|
+
strokeLinecap: "round",
|
|
399
|
+
strokeLinejoin: "round",
|
|
400
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Markings, {})
|
|
401
|
+
}
|
|
402
|
+
),
|
|
403
|
+
children
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
function Markings() {
|
|
409
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
410
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "0.06", y: "0.06", width: "8.88", height: "11.88" }),
|
|
411
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "0.06", width: "5", height: "1.94" }),
|
|
412
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "10", width: "5", height: "1.94" }),
|
|
413
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "0.06", y1: "6", x2: "8.94", y2: "6" }),
|
|
414
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "1.5" }),
|
|
415
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "0.09", fill: CHALK, fillOpacity: "0.9", stroke: "none" }),
|
|
416
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "1.5", r: "0.08", fill: CHALK, fillOpacity: "0.9", stroke: "none" }),
|
|
417
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "10.5", r: "0.08", fill: CHALK, fillOpacity: "0.9", stroke: "none" }),
|
|
418
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 3.086,2 A 1.5,1.5 0 0 0 5.914,2" }),
|
|
419
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 3.086,10 A 1.5,1.5 0 0 1 5.914,10" })
|
|
420
|
+
] });
|
|
421
|
+
}
|
|
422
|
+
function PitchSurface({ className, squareClassName, children }) {
|
|
423
|
+
const squares = [];
|
|
424
|
+
for (let y = PITCH_ROWS - 1; y >= 0; y--) {
|
|
425
|
+
for (let x = 0; x < PITCH_COLS; x++) {
|
|
426
|
+
squares.push(
|
|
427
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(pitchSquareClass(x, y), squareClassName?.(x, y)) }, `${x}-${y}`)
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", className), style: { containerType: "inline-size" }, children: [
|
|
432
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-9 gap-[1px]", "data-testid": "pitch-squares", children: squares }),
|
|
433
|
+
/* @__PURE__ */ jsxRuntime.jsx(GrassOverlay, {}),
|
|
434
|
+
/* @__PURE__ */ jsxRuntime.jsx(PitchMarkings, {}),
|
|
435
|
+
children
|
|
436
|
+
] });
|
|
437
|
+
}
|
|
207
438
|
var COLS = 9;
|
|
208
439
|
var ROWS = 12;
|
|
209
440
|
var clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
210
|
-
|
|
441
|
+
var cellX = (x) => `${x * 100}%`;
|
|
442
|
+
var cellY = (y) => `${(ROWS - 1 - y) * 100}%`;
|
|
443
|
+
var PIECE_SLIDE = { type: "spring", stiffness: 190, damping: 28, mass: 1 };
|
|
444
|
+
var BALL_SLIDE = { type: "spring", stiffness: 300, damping: 26, mass: 0.6 };
|
|
445
|
+
function GameBoard({ userSide, showCoordinates = false, keyboardNav = true, toolbar = true }) {
|
|
211
446
|
const t = useGameT();
|
|
212
447
|
const prefersReducedMotion = framerMotion.useReducedMotion();
|
|
213
448
|
const {
|
|
@@ -239,6 +474,14 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
239
474
|
setInvalidClickAt({ x, y, nonce: invalidClickNonceRef.current });
|
|
240
475
|
};
|
|
241
476
|
const [hoveredPassAt, setHoveredPassAt] = React.useState(null);
|
|
477
|
+
const [movingIds, setMovingIds] = React.useState(() => /* @__PURE__ */ new Set());
|
|
478
|
+
const setMoving = (id, moving) => setMovingIds((prev) => {
|
|
479
|
+
if (prev.has(id) === moving) return prev;
|
|
480
|
+
const next = new Set(prev);
|
|
481
|
+
if (moving) next.add(id);
|
|
482
|
+
else next.delete(id);
|
|
483
|
+
return next;
|
|
484
|
+
});
|
|
242
485
|
React.useEffect(() => {
|
|
243
486
|
if (!invalidClickAt) return;
|
|
244
487
|
const id = setTimeout(() => setInvalidClickAt(null), 100);
|
|
@@ -435,8 +678,6 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
435
678
|
const squares = [];
|
|
436
679
|
for (let y = ROWS - 1; y >= 0; y--) {
|
|
437
680
|
for (let x = 0; x < COLS; x++) {
|
|
438
|
-
const isGoalArea = x >= 2 && x <= 6 && (y >= 0 && y <= 1 || y >= 10 && y <= 11);
|
|
439
|
-
const isEven = (x + y) % 2 === 0;
|
|
440
681
|
const isValidMove = validMoves.some((m) => m.x === x && m.y === y);
|
|
441
682
|
const isValidPass = validPasses.some((p) => p.x === x && p.y === y);
|
|
442
683
|
const isAmbiguous = isValidMove && isValidPass;
|
|
@@ -458,9 +699,8 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
458
699
|
},
|
|
459
700
|
onMouseLeave: () => setHoveredPassAt(null),
|
|
460
701
|
className: cn(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
isGoalArea && "bg-[#1a3a18] ring-1 ring-inset ring-emerald-500/30",
|
|
702
|
+
pitchSquareClass(x, y),
|
|
703
|
+
"flex items-center justify-center cursor-pointer",
|
|
464
704
|
!isValidMove && !isValidPass && isLastMove && "bg-last-move-highlight/20",
|
|
465
705
|
// §8: pulsing warning ring on enemy goal area
|
|
466
706
|
isOffsideRisk && isEnemyGoalArea && !isValidMove && !isValidPass && "ring-2 ring-inset ring-warning/60",
|
|
@@ -529,7 +769,7 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
529
769
|
}
|
|
530
770
|
return squares;
|
|
531
771
|
};
|
|
532
|
-
const board = /* @__PURE__ */ jsxRuntime.
|
|
772
|
+
const board = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
533
773
|
"div",
|
|
534
774
|
{
|
|
535
775
|
className: cn(
|
|
@@ -546,26 +786,57 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
546
786
|
"aria-label": "Game board \u2014 arrow keys to move the cursor, Enter to act",
|
|
547
787
|
onKeyDown: handleKeyDown
|
|
548
788
|
} : {},
|
|
549
|
-
children:
|
|
550
|
-
/* @__PURE__ */ jsxRuntime.
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
789
|
+
children: [
|
|
790
|
+
toolbar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden md:flex items-center justify-between gap-2 px-2.5 py-1", "data-testid": "board-toolbar", children: [
|
|
791
|
+
/* @__PURE__ */ jsxRuntime.jsx(BallHolderChip, {}),
|
|
792
|
+
keyboardNav && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
793
|
+
"div",
|
|
794
|
+
{
|
|
795
|
+
ref: shortcutsRef,
|
|
796
|
+
className: "relative",
|
|
797
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
798
|
+
children: [
|
|
799
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
800
|
+
"button",
|
|
801
|
+
{
|
|
802
|
+
type: "button",
|
|
803
|
+
onClick: (e) => {
|
|
804
|
+
e.stopPropagation();
|
|
805
|
+
setShortcutsOpen((o) => !o);
|
|
806
|
+
},
|
|
807
|
+
"aria-label": t("shortcuts.buttonLabel"),
|
|
808
|
+
"aria-expanded": shortcutsOpen,
|
|
809
|
+
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",
|
|
810
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircle, { size: 16, strokeWidth: 2, "aria-hidden": "true" })
|
|
811
|
+
}
|
|
812
|
+
),
|
|
813
|
+
shortcutsOpen && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
814
|
+
"div",
|
|
815
|
+
{
|
|
816
|
+
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",
|
|
817
|
+
onClick: (e) => e.stopPropagation(),
|
|
818
|
+
children: [
|
|
819
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-inter text-[11px] font-semibold text-fg-primary mb-1.5", children: t("shortcuts.title") }),
|
|
820
|
+
/* @__PURE__ */ jsxRuntime.jsx(KeyboardShortcutsList, {})
|
|
821
|
+
]
|
|
822
|
+
}
|
|
823
|
+
)
|
|
824
|
+
]
|
|
825
|
+
}
|
|
826
|
+
)
|
|
827
|
+
] }),
|
|
828
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", style: { containerType: "inline-size" }, children: [
|
|
829
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-9 gap-[1px]", children: renderSquares() }),
|
|
830
|
+
/* @__PURE__ */ jsxRuntime.jsx(GrassOverlay, {}),
|
|
831
|
+
/* @__PURE__ */ jsxRuntime.jsx(PitchMarkings, {}),
|
|
832
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
833
|
+
"svg",
|
|
834
|
+
{
|
|
835
|
+
viewBox: "0 0 9 12",
|
|
836
|
+
preserveAspectRatio: "none",
|
|
837
|
+
className: "absolute inset-0 w-full h-full pointer-events-none",
|
|
838
|
+
"aria-hidden": "true",
|
|
839
|
+
children: hoveredPassAt && passCarrier && /* @__PURE__ */ jsxRuntime.jsx(
|
|
569
840
|
"line",
|
|
570
841
|
{
|
|
571
842
|
"data-testid": "pass-trajectory-line",
|
|
@@ -579,165 +850,110 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
|
579
850
|
strokeLinecap: "round"
|
|
580
851
|
}
|
|
581
852
|
)
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
853
|
+
}
|
|
854
|
+
),
|
|
855
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", "data-testid": "pieces-layer", children: [
|
|
856
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "sync", children: boardState.pieces.map((piece) => {
|
|
857
|
+
const isPickupCarrier = pickupCarrierId === piece.id;
|
|
858
|
+
const pieceTransition = isPickupCarrier ? { duration: PICKUP_DURATION, ease: "linear" } : PIECE_SLIDE;
|
|
859
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
860
|
+
framerMotion.motion.div,
|
|
861
|
+
{
|
|
862
|
+
"data-piece-id": piece.id,
|
|
863
|
+
initial: false,
|
|
864
|
+
animate: { x: cellX(piece.pos.x), y: cellY(piece.pos.y) },
|
|
865
|
+
transition: pieceTransition,
|
|
866
|
+
onAnimationStart: () => setMoving(piece.id, true),
|
|
867
|
+
onAnimationComplete: () => setMoving(piece.id, false),
|
|
868
|
+
style: {
|
|
869
|
+
position: "absolute",
|
|
870
|
+
left: 0,
|
|
871
|
+
top: 0,
|
|
872
|
+
width: `${100 / COLS}%`,
|
|
873
|
+
height: `${100 / ROWS}%`,
|
|
874
|
+
willChange: "transform"
|
|
875
|
+
},
|
|
876
|
+
className: "flex items-center justify-center pointer-events-auto",
|
|
877
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
878
|
+
GamePiece,
|
|
879
|
+
{
|
|
880
|
+
piece,
|
|
881
|
+
isSelected: selectedPieceId === piece.id,
|
|
882
|
+
hasBall: boardState.ball.holderId === piece.id,
|
|
883
|
+
isMoving: movingIds.has(piece.id),
|
|
884
|
+
onClick: (e) => handlePieceClick(piece.id, piece.pos.x, piece.pos.y, e)
|
|
885
|
+
}
|
|
886
|
+
)
|
|
597
887
|
},
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
888
|
+
piece.id
|
|
889
|
+
);
|
|
890
|
+
}) }),
|
|
891
|
+
(() => {
|
|
892
|
+
const targetX = cellX(ball.pos.x);
|
|
893
|
+
const targetY = cellY(ball.pos.y);
|
|
894
|
+
let animate;
|
|
895
|
+
let transition;
|
|
896
|
+
if (isPickupOnMove && prevBall) {
|
|
897
|
+
const prevX = cellX(prevBall.pos.x);
|
|
898
|
+
const prevY = cellY(prevBall.pos.y);
|
|
899
|
+
const pulseStart = Math.max(0.05, pickupProportion - 0.06);
|
|
900
|
+
animate = {
|
|
901
|
+
x: [prevX, prevX, prevX, targetX],
|
|
902
|
+
y: [prevY, prevY, prevY, targetY],
|
|
903
|
+
scale: [1, 1, 1.35, 1]
|
|
904
|
+
};
|
|
905
|
+
transition = { duration: PICKUP_DURATION, times: [0, pulseStart, pickupProportion, 1], ease: "linear" };
|
|
906
|
+
} else {
|
|
907
|
+
animate = { x: targetX, y: targetY, scale: 1 };
|
|
908
|
+
transition = ball.holderId ? PIECE_SLIDE : BALL_SLIDE;
|
|
909
|
+
}
|
|
910
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
911
|
+
framerMotion.motion.div,
|
|
912
|
+
{
|
|
913
|
+
initial: false,
|
|
914
|
+
animate,
|
|
915
|
+
transition,
|
|
916
|
+
style: {
|
|
917
|
+
position: "absolute",
|
|
918
|
+
left: 0,
|
|
919
|
+
top: 0,
|
|
920
|
+
width: `${100 / COLS}%`,
|
|
921
|
+
height: `${100 / ROWS}%`,
|
|
922
|
+
zIndex: 50,
|
|
923
|
+
willChange: "transform"
|
|
924
|
+
},
|
|
925
|
+
className: "flex items-center justify-center pointer-events-none",
|
|
926
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[60%] h-[60%]", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) })
|
|
603
927
|
},
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
piece,
|
|
609
|
-
isSelected: selectedPieceId === piece.id,
|
|
610
|
-
hasBall: boardState.ball.holderId === piece.id,
|
|
611
|
-
onClick: (e) => handlePieceClick(piece.id, piece.pos.x, piece.pos.y, e)
|
|
612
|
-
}
|
|
613
|
-
)
|
|
614
|
-
},
|
|
615
|
-
piece.id
|
|
616
|
-
);
|
|
617
|
-
}) }),
|
|
618
|
-
(() => {
|
|
619
|
-
const targetX = ball.pos.x / COLS * 100;
|
|
620
|
-
const targetY = (ROWS - 1 - ball.pos.y) / ROWS * 100;
|
|
621
|
-
let animate;
|
|
622
|
-
let transition;
|
|
623
|
-
if (isPickupOnMove && prevBall) {
|
|
624
|
-
const prevX = prevBall.pos.x / COLS * 100;
|
|
625
|
-
const prevY = (ROWS - 1 - prevBall.pos.y) / ROWS * 100;
|
|
626
|
-
const pulseStart = Math.max(0.05, pickupProportion - 0.06);
|
|
627
|
-
animate = {
|
|
628
|
-
left: [`${prevX}%`, `${prevX}%`, `${prevX}%`, `${targetX}%`],
|
|
629
|
-
top: [`${prevY}%`, `${prevY}%`, `${prevY}%`, `${targetY}%`],
|
|
630
|
-
scale: [1, 1, 1.35, 1]
|
|
631
|
-
};
|
|
632
|
-
transition = { duration: PICKUP_DURATION, times: [0, pulseStart, pickupProportion, 1], ease: "linear" };
|
|
633
|
-
} else {
|
|
634
|
-
animate = { left: `${targetX}%`, top: `${targetY}%`, scale: 1 };
|
|
635
|
-
transition = { type: "spring", stiffness: 300, damping: 30, mass: 0.5 };
|
|
636
|
-
}
|
|
637
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
928
|
+
"ball"
|
|
929
|
+
);
|
|
930
|
+
})(),
|
|
931
|
+
invalidClickAt && /* @__PURE__ */ jsxRuntime.jsx(
|
|
638
932
|
framerMotion.motion.div,
|
|
639
933
|
{
|
|
934
|
+
"data-testid": "invalid-action-shake",
|
|
935
|
+
"aria-hidden": "true",
|
|
640
936
|
initial: false,
|
|
641
|
-
animate,
|
|
642
|
-
transition,
|
|
937
|
+
animate: prefersReducedMotion ? { opacity: [0.9, 0] } : { x: [0, -3, 3, -3, 3, 0] },
|
|
938
|
+
transition: { duration: 0.08 },
|
|
643
939
|
style: {
|
|
644
940
|
position: "absolute",
|
|
941
|
+
left: `${invalidClickAt.x / COLS * 100}%`,
|
|
942
|
+
top: `${(ROWS - 1 - invalidClickAt.y) / ROWS * 100}%`,
|
|
645
943
|
width: `${100 / COLS}%`,
|
|
646
|
-
height: `${100 / ROWS}
|
|
647
|
-
zIndex: 50
|
|
944
|
+
height: `${100 / ROWS}%`
|
|
648
945
|
},
|
|
649
|
-
className: "
|
|
650
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[60%] h-[60%]", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) })
|
|
651
|
-
},
|
|
652
|
-
"ball"
|
|
653
|
-
);
|
|
654
|
-
})(),
|
|
655
|
-
invalidClickAt && /* @__PURE__ */ jsxRuntime.jsx(
|
|
656
|
-
framerMotion.motion.div,
|
|
657
|
-
{
|
|
658
|
-
"data-testid": "invalid-action-shake",
|
|
659
|
-
"aria-hidden": "true",
|
|
660
|
-
initial: false,
|
|
661
|
-
animate: prefersReducedMotion ? { opacity: [0.9, 0] } : { x: [0, -3, 3, -3, 3, 0] },
|
|
662
|
-
transition: { duration: 0.08 },
|
|
663
|
-
style: {
|
|
664
|
-
position: "absolute",
|
|
665
|
-
left: `${invalidClickAt.x / COLS * 100}%`,
|
|
666
|
-
top: `${(ROWS - 1 - invalidClickAt.y) / ROWS * 100}%`,
|
|
667
|
-
width: `${100 / COLS}%`,
|
|
668
|
-
height: `${100 / ROWS}%`
|
|
946
|
+
className: "ring-2 ring-inset ring-danger/70 rounded-sm"
|
|
669
947
|
},
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
keyboardNav && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
680
|
-
"div",
|
|
681
|
-
{
|
|
682
|
-
ref: shortcutsRef,
|
|
683
|
-
className: "hidden md:block absolute top-2 right-2 z-40",
|
|
684
|
-
onKeyDown: (e) => e.stopPropagation(),
|
|
685
|
-
children: [
|
|
686
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
687
|
-
"button",
|
|
688
|
-
{
|
|
689
|
-
type: "button",
|
|
690
|
-
onClick: (e) => {
|
|
691
|
-
e.stopPropagation();
|
|
692
|
-
setShortcutsOpen((o) => !o);
|
|
693
|
-
},
|
|
694
|
-
"aria-label": t("shortcuts.buttonLabel"),
|
|
695
|
-
"aria-expanded": shortcutsOpen,
|
|
696
|
-
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",
|
|
697
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircle, { size: 16, strokeWidth: 2, "aria-hidden": "true" })
|
|
698
|
-
}
|
|
699
|
-
),
|
|
700
|
-
shortcutsOpen && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
701
|
-
"div",
|
|
702
|
-
{
|
|
703
|
-
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",
|
|
704
|
-
onClick: (e) => e.stopPropagation(),
|
|
705
|
-
children: [
|
|
706
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-inter text-[11px] font-semibold text-fg-primary mb-1.5", children: t("shortcuts.title") }),
|
|
707
|
-
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "font-mono text-[10px] text-fg-secondary leading-relaxed", children: [
|
|
708
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
709
|
-
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "\u2191\u2193\u2190\u2192" }),
|
|
710
|
-
" ",
|
|
711
|
-
t("shortcuts.arrows")
|
|
712
|
-
] }),
|
|
713
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
714
|
-
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Enter" }),
|
|
715
|
-
" ",
|
|
716
|
-
t("shortcuts.select")
|
|
717
|
-
] }),
|
|
718
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
719
|
-
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "M" }),
|
|
720
|
-
" ",
|
|
721
|
-
t("shortcuts.move")
|
|
722
|
-
] }),
|
|
723
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
724
|
-
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "P" }),
|
|
725
|
-
" ",
|
|
726
|
-
t("shortcuts.pass")
|
|
727
|
-
] }),
|
|
728
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
729
|
-
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Esc" }),
|
|
730
|
-
" ",
|
|
731
|
-
t("shortcuts.cancel")
|
|
732
|
-
] })
|
|
733
|
-
] })
|
|
734
|
-
]
|
|
735
|
-
}
|
|
736
|
-
)
|
|
737
|
-
]
|
|
738
|
-
}
|
|
739
|
-
)
|
|
740
|
-
] })
|
|
948
|
+
invalidClickAt.nonce
|
|
949
|
+
)
|
|
950
|
+
] }),
|
|
951
|
+
isOffsideRisk && /* @__PURE__ */ jsxRuntime.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: [
|
|
952
|
+
"\u26A0 ",
|
|
953
|
+
t("offsideWarning")
|
|
954
|
+
] })
|
|
955
|
+
] })
|
|
956
|
+
]
|
|
741
957
|
}
|
|
742
958
|
);
|
|
743
959
|
if (!showCoordinates) return board;
|
|
@@ -1265,77 +1481,31 @@ var COLS2 = 9;
|
|
|
1265
1481
|
var ROWS2 = 12;
|
|
1266
1482
|
function StaticGameBoard() {
|
|
1267
1483
|
const boardState = React.useMemo(() => chunkLTFNSTAQ_cjs.getInitialBoardState("white"), []);
|
|
1268
|
-
const renderSquares = () => {
|
|
1269
|
-
const squares = [];
|
|
1270
|
-
for (let y = ROWS2 - 1; y >= 0; y--) {
|
|
1271
|
-
for (let x = 0; x < COLS2; x++) {
|
|
1272
|
-
const isGoalArea = x >= 2 && x <= 6 && (y >= 0 && y <= 1 || y >= 10 && y <= 11);
|
|
1273
|
-
const isEven = (x + y) % 2 === 0;
|
|
1274
|
-
squares.push(
|
|
1275
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1276
|
-
"div",
|
|
1277
|
-
{
|
|
1278
|
-
className: cn(
|
|
1279
|
-
"relative aspect-square w-full",
|
|
1280
|
-
isEven ? "bg-[#2d5a27]" : "bg-[#356a2d]",
|
|
1281
|
-
isGoalArea && "bg-[#1a3a18] ring-1 ring-inset ring-emerald-500/30"
|
|
1282
|
-
)
|
|
1283
|
-
},
|
|
1284
|
-
`${x}-${y}`
|
|
1285
|
-
)
|
|
1286
|
-
);
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
return squares;
|
|
1290
|
-
};
|
|
1291
1484
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full overflow-hidden rounded-xl shadow-2xl border-4 border-[#1a3317] bg-[#1a3317]", children: [
|
|
1292
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
children: [
|
|
1302
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "0", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
|
|
1303
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "10", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
|
|
1304
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "0", y1: "6", x2: "9", y2: "6", stroke: "white", strokeOpacity: "0.35", strokeWidth: "0.05" }),
|
|
1305
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "1.5", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
|
|
1306
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "0.12", fill: "white", fillOpacity: "0.5" }),
|
|
1307
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "1.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
|
|
1308
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "10.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
|
|
1309
|
-
/* @__PURE__ */ jsxRuntime.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" }),
|
|
1310
|
-
/* @__PURE__ */ jsxRuntime.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" })
|
|
1311
|
-
]
|
|
1312
|
-
}
|
|
1313
|
-
),
|
|
1314
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 pointer-events-none", children: boardState.pieces.map((piece) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1315
|
-
"div",
|
|
1316
|
-
{
|
|
1317
|
-
style: {
|
|
1318
|
-
position: "absolute",
|
|
1319
|
-
left: `${piece.pos.x / COLS2 * 100}%`,
|
|
1320
|
-
top: `${(ROWS2 - 1 - piece.pos.y) / ROWS2 * 100}%`,
|
|
1321
|
-
width: `${100 / COLS2}%`,
|
|
1322
|
-
height: `${100 / ROWS2}%`
|
|
1323
|
-
},
|
|
1324
|
-
className: "flex items-center justify-center",
|
|
1325
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1326
|
-
GamePiece,
|
|
1327
|
-
{
|
|
1328
|
-
piece,
|
|
1329
|
-
isSelected: false,
|
|
1330
|
-
hasBall: boardState.ball.holderId === piece.id,
|
|
1331
|
-
onClick: () => {
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
|
-
)
|
|
1485
|
+
/* @__PURE__ */ jsxRuntime.jsx(PitchSurface, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 pointer-events-none", children: boardState.pieces.map((piece) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1486
|
+
"div",
|
|
1487
|
+
{
|
|
1488
|
+
style: {
|
|
1489
|
+
position: "absolute",
|
|
1490
|
+
left: `${piece.pos.x / COLS2 * 100}%`,
|
|
1491
|
+
top: `${(ROWS2 - 1 - piece.pos.y) / ROWS2 * 100}%`,
|
|
1492
|
+
width: `${100 / COLS2}%`,
|
|
1493
|
+
height: `${100 / ROWS2}%`
|
|
1335
1494
|
},
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1495
|
+
className: "flex items-center justify-center",
|
|
1496
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1497
|
+
GamePiece,
|
|
1498
|
+
{
|
|
1499
|
+
piece,
|
|
1500
|
+
isSelected: false,
|
|
1501
|
+
hasBall: boardState.ball.holderId === piece.id,
|
|
1502
|
+
onClick: () => {
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
)
|
|
1506
|
+
},
|
|
1507
|
+
piece.id
|
|
1508
|
+
)) }) }),
|
|
1339
1509
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1340
1510
|
"div",
|
|
1341
1511
|
{
|
|
@@ -1545,23 +1715,33 @@ exports.ActionPoints = ActionPoints;
|
|
|
1545
1715
|
exports.Avatar = Avatar;
|
|
1546
1716
|
exports.AvatarFallback = AvatarFallback;
|
|
1547
1717
|
exports.AvatarImage = AvatarImage;
|
|
1718
|
+
exports.BallHolderChip = BallHolderChip;
|
|
1548
1719
|
exports.Button = Button;
|
|
1549
1720
|
exports.ConfirmDialog = ConfirmDialog;
|
|
1550
1721
|
exports.EventToast = EventToast;
|
|
1551
1722
|
exports.Football = Football;
|
|
1552
1723
|
exports.GAME_I18N_KEYS = GAME_I18N_KEYS;
|
|
1724
|
+
exports.GOAL_AREA_SHADE_CLASS = GOAL_AREA_SHADE_CLASS;
|
|
1553
1725
|
exports.GameBoard = GameBoard;
|
|
1554
1726
|
exports.GameControls = GameControls;
|
|
1555
1727
|
exports.GameI18nProvider = GameI18nProvider;
|
|
1556
1728
|
exports.GamePiece = GamePiece;
|
|
1729
|
+
exports.GrassOverlay = GrassOverlay;
|
|
1730
|
+
exports.KeyboardShortcutsList = KeyboardShortcutsList;
|
|
1557
1731
|
exports.MiniScoreboard = MiniScoreboard;
|
|
1558
1732
|
exports.MobileHistory = MobileHistory;
|
|
1559
1733
|
exports.MoveHistory = MoveHistory;
|
|
1734
|
+
exports.PITCH_COLS = PITCH_COLS;
|
|
1735
|
+
exports.PITCH_ROWS = PITCH_ROWS;
|
|
1736
|
+
exports.PitchMarkings = PitchMarkings;
|
|
1737
|
+
exports.PitchSurface = PitchSurface;
|
|
1560
1738
|
exports.Scoreboard = Scoreboard;
|
|
1561
1739
|
exports.SelectedPieceDetail = SelectedPieceDetail;
|
|
1562
1740
|
exports.StaticGameBoard = StaticGameBoard;
|
|
1563
1741
|
exports.TurnBanner = TurnBanner;
|
|
1564
1742
|
exports.cn = cn;
|
|
1743
|
+
exports.isGoalAreaSquare = isGoalAreaSquare;
|
|
1744
|
+
exports.pitchSquareClass = pitchSquareClass;
|
|
1565
1745
|
exports.useGameT = useGameT;
|
|
1566
1746
|
//# sourceMappingURL=index.cjs.map
|
|
1567
1747
|
//# sourceMappingURL=index.cjs.map
|