@scriptonita/chess-football-ui 0.1.1 → 0.2.1
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 +345 -148
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +348 -154
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -39,14 +39,18 @@ var PIECE_ICON = {
|
|
|
39
39
|
bishop: lucideReact.ChessBishop,
|
|
40
40
|
knight: lucideReact.ChessKnight
|
|
41
41
|
};
|
|
42
|
-
var
|
|
42
|
+
var EMBOSS_FILTER = {
|
|
43
|
+
white: "drop-shadow(0 -0.75px 0 rgba(255,255,255,0.65)) drop-shadow(0 1.25px 1px rgba(0,0,0,0.45))",
|
|
44
|
+
black: "drop-shadow(0 -0.5px 0 rgba(255,255,255,0.3)) drop-shadow(0 1.25px 1.5px rgba(0,0,0,0.8))"
|
|
45
|
+
};
|
|
46
|
+
var PieceIcon = ({ type, side }) => {
|
|
43
47
|
const Icon = PIECE_ICON[type] ?? lucideReact.ShieldQuestion;
|
|
44
48
|
const style = {
|
|
45
49
|
width: "clamp(16px, 7.4cqw, 44px)",
|
|
46
50
|
height: "clamp(16px, 7.4cqw, 44px)",
|
|
47
|
-
filter:
|
|
51
|
+
filter: EMBOSS_FILTER[side]
|
|
48
52
|
};
|
|
49
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Icon, { style, strokeWidth:
|
|
53
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Icon, { style, strokeWidth: 2, "aria-hidden": "true" });
|
|
50
54
|
};
|
|
51
55
|
var WHITE_PIECE_STYLE = {
|
|
52
56
|
background: "radial-gradient(circle at 30% 25%, #ffffff 0%, #f4f4f5 55%, #d4d4d8 100%)",
|
|
@@ -87,7 +91,7 @@ function GamePiece({ piece, isSelected, hasBall, onClick }) {
|
|
|
87
91
|
piece.hasMovedThisTurn && "opacity-70"
|
|
88
92
|
),
|
|
89
93
|
children: [
|
|
90
|
-
/* @__PURE__ */ jsxRuntime.jsx(PieceIcon, { type: piece.type }),
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx(PieceIcon, { type: piece.type, side: piece.side }),
|
|
91
95
|
hasBall && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 rounded-full ring-2 ring-orange-400 pointer-events-none" }),
|
|
92
96
|
isSelected && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 rounded-full animate-pulse ring-2 ring-yellow-400 ring-offset-2 ring-offset-transparent" })
|
|
93
97
|
]
|
|
@@ -142,20 +146,29 @@ var Football = ({ className }) => {
|
|
|
142
146
|
}
|
|
143
147
|
);
|
|
144
148
|
};
|
|
149
|
+
var fallback = (key) => key;
|
|
150
|
+
var GameI18nContext = React.createContext(fallback);
|
|
151
|
+
function GameI18nProvider({ t, children }) {
|
|
152
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GameI18nContext.Provider, { value: t, children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.MotionConfig, { reducedMotion: "user", children }) });
|
|
153
|
+
}
|
|
154
|
+
function useGameT() {
|
|
155
|
+
return React.useContext(GameI18nContext);
|
|
156
|
+
}
|
|
145
157
|
var COLS = 9;
|
|
146
158
|
var ROWS = 12;
|
|
147
159
|
var clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
148
|
-
function GameBoard({ userSide, showCoordinates = false, keyboardNav =
|
|
160
|
+
function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
|
|
161
|
+
const t = useGameT();
|
|
149
162
|
const {
|
|
150
163
|
boardState,
|
|
151
164
|
selectedPieceId,
|
|
152
165
|
setSelectedPieceId,
|
|
153
|
-
interactionMode,
|
|
154
166
|
setInteractionMode,
|
|
155
167
|
movePiece,
|
|
156
168
|
passBall
|
|
157
169
|
} = chunkJ2TBQPPC_cjs.useGameStore();
|
|
158
170
|
const [cursor, setCursor] = React.useState(null);
|
|
171
|
+
const [disambiguateAt, setDisambiguateAt] = React.useState(null);
|
|
159
172
|
const prevBallRef = React.useRef(boardState?.ball);
|
|
160
173
|
const prevBall = prevBallRef.current;
|
|
161
174
|
React.useEffect(() => {
|
|
@@ -164,19 +177,19 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
164
177
|
const validMoves = React.useMemo(() => {
|
|
165
178
|
if (!boardState) return [];
|
|
166
179
|
const sp = boardState.pieces.find((p) => p.id === selectedPieceId);
|
|
167
|
-
if (sp &&
|
|
180
|
+
if (sp && !sp.hasMovedThisTurn) {
|
|
168
181
|
return chessFootballEngine.getValidMoves(sp, boardState);
|
|
169
182
|
}
|
|
170
183
|
return [];
|
|
171
|
-
}, [boardState, selectedPieceId
|
|
184
|
+
}, [boardState, selectedPieceId]);
|
|
172
185
|
const validPasses = React.useMemo(() => {
|
|
173
186
|
if (!boardState) return [];
|
|
174
187
|
const sp = boardState.pieces.find((p) => p.id === selectedPieceId);
|
|
175
|
-
if (sp &&
|
|
188
|
+
if (sp && boardState.ball.holderId === sp.id) {
|
|
176
189
|
return chessFootballEngine.getValidPasses(sp, boardState);
|
|
177
190
|
}
|
|
178
191
|
return [];
|
|
179
|
-
}, [boardState, selectedPieceId
|
|
192
|
+
}, [boardState, selectedPieceId]);
|
|
180
193
|
if (!boardState) return null;
|
|
181
194
|
const lastMove = boardState.lastMove;
|
|
182
195
|
const ball = boardState.ball;
|
|
@@ -196,33 +209,41 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
196
209
|
);
|
|
197
210
|
pickupProportion = totalSteps > 0 ? Math.min(0.85, Math.max(0.15, stepsToBall / totalSteps)) : 0.5;
|
|
198
211
|
}
|
|
212
|
+
const ballCarrier = ball.holderId ? boardState.pieces.find((p) => p.id === ball.holderId) ?? null : null;
|
|
213
|
+
const isOffsideRisk = !!ballCarrier && ballCarrier.type !== "king" && userSide !== null && ballCarrier.side === userSide && boardState.turn === userSide && chessFootballEngine.isInEnemyArea(ballCarrier.pos, ballCarrier.side);
|
|
199
214
|
const handleSquareClick = (x, y) => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
215
|
+
setCursor(null);
|
|
216
|
+
const isValidMove = validMoves.some((m) => m.x === x && m.y === y);
|
|
217
|
+
const isValidPass = validPasses.some((p) => p.x === x && p.y === y);
|
|
218
|
+
if (isValidMove && isValidPass) {
|
|
219
|
+
setDisambiguateAt({ x, y });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (isValidMove && selectedPieceId) {
|
|
223
|
+
movePiece(selectedPieceId, { x, y });
|
|
224
|
+
setDisambiguateAt(null);
|
|
225
|
+
} else if (isValidPass) {
|
|
226
|
+
passBall({ x, y });
|
|
227
|
+
setDisambiguateAt(null);
|
|
228
|
+
} else {
|
|
229
|
+
setDisambiguateAt(null);
|
|
208
230
|
}
|
|
209
231
|
};
|
|
210
232
|
const handlePieceClick = (pieceId, x, y, e) => {
|
|
211
233
|
e.stopPropagation();
|
|
212
234
|
const pieceAt = boardState.pieces.find((p) => p.id === pieceId);
|
|
213
235
|
if (!pieceAt) return;
|
|
214
|
-
const
|
|
215
|
-
|
|
236
|
+
const isValidMove = validMoves.some((m) => m.x === x && m.y === y);
|
|
237
|
+
const isValidPass = validPasses.some((p) => p.x === x && p.y === y);
|
|
238
|
+
if (isValidMove || isValidPass) {
|
|
216
239
|
handleSquareClick(x, y);
|
|
217
240
|
} else if (boardState.turn === pieceAt.side && userSide === pieceAt.side) {
|
|
218
241
|
if (selectedPieceId === pieceAt.id) {
|
|
219
|
-
|
|
220
|
-
setInteractionMode(interactionMode === "move" ? "pass" : "move");
|
|
221
|
-
}
|
|
242
|
+
setSelectedPieceId(null);
|
|
222
243
|
} else {
|
|
223
244
|
setSelectedPieceId(pieceAt.id);
|
|
224
|
-
setInteractionMode("move");
|
|
225
245
|
}
|
|
246
|
+
setDisambiguateAt(null);
|
|
226
247
|
}
|
|
227
248
|
};
|
|
228
249
|
const defaultCursor = () => {
|
|
@@ -251,7 +272,6 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
251
272
|
case "ArrowUp":
|
|
252
273
|
step(0, 1);
|
|
253
274
|
break;
|
|
254
|
-
// visually up = higher rank (y grows toward the top)
|
|
255
275
|
case "ArrowDown":
|
|
256
276
|
step(0, -1);
|
|
257
277
|
break;
|
|
@@ -271,15 +291,25 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
271
291
|
}
|
|
272
292
|
case "m":
|
|
273
293
|
case "M":
|
|
274
|
-
|
|
294
|
+
if (disambiguateAt && selectedPieceId) {
|
|
295
|
+
movePiece(selectedPieceId, disambiguateAt);
|
|
296
|
+
setDisambiguateAt(null);
|
|
297
|
+
}
|
|
275
298
|
break;
|
|
276
299
|
case "p":
|
|
277
300
|
case "P":
|
|
278
|
-
|
|
301
|
+
if (disambiguateAt) {
|
|
302
|
+
passBall(disambiguateAt);
|
|
303
|
+
setDisambiguateAt(null);
|
|
304
|
+
}
|
|
279
305
|
break;
|
|
280
306
|
case "Escape":
|
|
281
|
-
|
|
282
|
-
|
|
307
|
+
if (disambiguateAt) {
|
|
308
|
+
setDisambiguateAt(null);
|
|
309
|
+
} else {
|
|
310
|
+
setSelectedPieceId(null);
|
|
311
|
+
setInteractionMode(null);
|
|
312
|
+
}
|
|
283
313
|
break;
|
|
284
314
|
}
|
|
285
315
|
};
|
|
@@ -289,9 +319,16 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
289
319
|
for (let x = 0; x < COLS; x++) {
|
|
290
320
|
const isGoalArea = x >= 2 && x <= 6 && (y >= 0 && y <= 1 || y >= 10 && y <= 11);
|
|
291
321
|
const isEven = (x + y) % 2 === 0;
|
|
292
|
-
const
|
|
322
|
+
const isValidMove = validMoves.some((m) => m.x === x && m.y === y);
|
|
323
|
+
const isValidPass = validPasses.some((p) => p.x === x && p.y === y);
|
|
324
|
+
const isAmbiguous = isValidMove && isValidPass;
|
|
325
|
+
const isLastMoveOrigin = lastMove?.from && lastMove.from.x === x && lastMove.from.y === y;
|
|
326
|
+
const isLastMoveDest = lastMove?.to && lastMove.to.x === x && lastMove.to.y === y;
|
|
327
|
+
const isLastMove = isLastMoveOrigin || isLastMoveDest;
|
|
328
|
+
const isEnemyGoalArea = userSide !== null && (x >= 2 && x <= 6) && (userSide === "white" ? y >= 10 && y <= 11 : y >= 0 && y <= 1);
|
|
293
329
|
const pieceAt = boardState.pieces.find((p) => p.pos.x === x && p.pos.y === y);
|
|
294
330
|
const isCursor = keyboardNav && cursor?.x === x && cursor?.y === y;
|
|
331
|
+
const isDisambiguateTarget = disambiguateAt?.x === x && disambiguateAt?.y === y;
|
|
295
332
|
squares.push(
|
|
296
333
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
297
334
|
"div",
|
|
@@ -299,16 +336,60 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
299
336
|
onClick: () => handleSquareClick(x, y),
|
|
300
337
|
className: cn(
|
|
301
338
|
"relative aspect-square w-full flex items-center justify-center cursor-pointer",
|
|
302
|
-
isEven ? "bg-
|
|
339
|
+
isEven ? "bg-field-green-1" : "bg-field-green-2",
|
|
303
340
|
isGoalArea && "bg-[#1a3a18] ring-1 ring-inset ring-emerald-500/30",
|
|
304
|
-
|
|
341
|
+
!isValidMove && !isValidPass && isLastMove && "bg-last-move-highlight/20",
|
|
342
|
+
// §8: pulsing warning ring on enemy goal area
|
|
343
|
+
isOffsideRisk && isEnemyGoalArea && !isValidMove && !isValidPass && "ring-2 ring-inset ring-warning/60",
|
|
344
|
+
isAmbiguous && "ring-[3px] ring-inset ring-yellow-400/90 bg-yellow-400/20",
|
|
345
|
+
!isAmbiguous && isValidMove && "ring-[3px] ring-inset ring-yellow-400/80 bg-yellow-400/15",
|
|
346
|
+
!isAmbiguous && isValidPass && "ring-[3px] ring-inset ring-sky-400/80 bg-sky-400/15"
|
|
305
347
|
),
|
|
306
348
|
children: [
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
349
|
+
!isAmbiguous && isValidMove && !pieceAt && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-3 h-3 rounded-full bg-yellow-400/65" }),
|
|
350
|
+
!isAmbiguous && isValidPass && !pieceAt && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-3 h-3 rounded-full bg-sky-400/65" }),
|
|
351
|
+
isAmbiguous && !pieceAt && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-0.5", children: [
|
|
352
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-yellow-400/80" }),
|
|
353
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-sky-400/80" })
|
|
354
|
+
] }),
|
|
355
|
+
isCursor && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 ring-2 ring-inset ring-white pointer-events-none z-20", "aria-hidden": "true" }),
|
|
356
|
+
isDisambiguateTarget && selectedPieceId && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
357
|
+
"div",
|
|
358
|
+
{
|
|
359
|
+
className: "absolute z-50 bottom-full mb-1 left-1/2 -translate-x-1/2 flex gap-1 bg-bg-secondary border border-border-subtle rounded-md p-1 shadow-xl pointer-events-auto whitespace-nowrap",
|
|
360
|
+
onClick: (e) => e.stopPropagation(),
|
|
361
|
+
children: [
|
|
362
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
363
|
+
"button",
|
|
364
|
+
{
|
|
365
|
+
className: "flex items-center gap-1 px-2 py-1 rounded text-[11px] font-semibold font-inter text-move-highlight bg-move-highlight/10 hover:bg-move-highlight/20 transition-colors",
|
|
366
|
+
onClick: () => {
|
|
367
|
+
movePiece(selectedPieceId, { x, y });
|
|
368
|
+
setDisambiguateAt(null);
|
|
369
|
+
},
|
|
370
|
+
children: [
|
|
371
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Move, { size: 11, strokeWidth: 2 }),
|
|
372
|
+
t("move")
|
|
373
|
+
]
|
|
374
|
+
}
|
|
375
|
+
),
|
|
376
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
377
|
+
"button",
|
|
378
|
+
{
|
|
379
|
+
className: "flex items-center gap-1 px-2 py-1 rounded text-[11px] font-semibold font-inter text-pass-highlight bg-pass-highlight/10 hover:bg-pass-highlight/20 transition-colors",
|
|
380
|
+
onClick: () => {
|
|
381
|
+
passBall({ x, y });
|
|
382
|
+
setDisambiguateAt(null);
|
|
383
|
+
},
|
|
384
|
+
children: [
|
|
385
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-3 h-3 inline-flex", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) }),
|
|
386
|
+
t("pass")
|
|
387
|
+
]
|
|
388
|
+
}
|
|
389
|
+
)
|
|
390
|
+
]
|
|
391
|
+
}
|
|
392
|
+
)
|
|
312
393
|
]
|
|
313
394
|
},
|
|
314
395
|
`${x}-${y}`
|
|
@@ -322,15 +403,18 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
322
403
|
"div",
|
|
323
404
|
{
|
|
324
405
|
className: cn(
|
|
325
|
-
|
|
406
|
+
// §6: Mobile edge-to-edge — thin 2px margin, no border, no radius
|
|
407
|
+
"w-full mx-0.5 bg-[#1a3317] overflow-hidden",
|
|
408
|
+
// §5+§6: Desktop — centered, rounded, bordered, height-based max-width
|
|
409
|
+
"md:mx-auto md:rounded-xl md:shadow-2xl md:border-4 md:border-[#1a3317]",
|
|
410
|
+
"md:max-w-[min(700px,calc((100dvh_-_150px)*0.75))]",
|
|
326
411
|
keyboardNav && "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-green focus-visible:ring-offset-2 focus-visible:ring-offset-bg-primary"
|
|
327
412
|
),
|
|
328
413
|
...keyboardNav ? {
|
|
329
414
|
tabIndex: 0,
|
|
330
415
|
role: "application",
|
|
331
416
|
"aria-label": "Game board \u2014 arrow keys to move the cursor, Enter to act",
|
|
332
|
-
onKeyDown: handleKeyDown
|
|
333
|
-
onFocus: () => setCursor((c) => c ?? defaultCursor())
|
|
417
|
+
onKeyDown: handleKeyDown
|
|
334
418
|
} : {},
|
|
335
419
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", style: { containerType: "inline-size" }, children: [
|
|
336
420
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-9 gap-[1px]", children: renderSquares() }),
|
|
@@ -357,12 +441,7 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
357
441
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", children: [
|
|
358
442
|
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "sync", children: boardState.pieces.map((piece) => {
|
|
359
443
|
const isPickupCarrier = pickupCarrierId === piece.id;
|
|
360
|
-
const pieceTransition = isPickupCarrier ? { duration: PICKUP_DURATION, ease: "linear" } : {
|
|
361
|
-
type: "spring",
|
|
362
|
-
stiffness: 200,
|
|
363
|
-
damping: 25,
|
|
364
|
-
mass: 1
|
|
365
|
-
};
|
|
444
|
+
const pieceTransition = isPickupCarrier ? { duration: PICKUP_DURATION, ease: "linear" } : { type: "spring", stiffness: 200, damping: 25, mass: 1 };
|
|
366
445
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
367
446
|
framerMotion.motion.div,
|
|
368
447
|
{
|
|
@@ -406,23 +485,10 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
406
485
|
top: [`${prevY}%`, `${prevY}%`, `${prevY}%`, `${targetY}%`],
|
|
407
486
|
scale: [1, 1, 1.35, 1]
|
|
408
487
|
};
|
|
409
|
-
transition = {
|
|
410
|
-
duration: PICKUP_DURATION,
|
|
411
|
-
times: [0, pulseStart, pickupProportion, 1],
|
|
412
|
-
ease: "linear"
|
|
413
|
-
};
|
|
488
|
+
transition = { duration: PICKUP_DURATION, times: [0, pulseStart, pickupProportion, 1], ease: "linear" };
|
|
414
489
|
} else {
|
|
415
|
-
animate = {
|
|
416
|
-
|
|
417
|
-
top: `${targetY}%`,
|
|
418
|
-
scale: 1
|
|
419
|
-
};
|
|
420
|
-
transition = {
|
|
421
|
-
type: "spring",
|
|
422
|
-
stiffness: 300,
|
|
423
|
-
damping: 30,
|
|
424
|
-
mass: 0.5
|
|
425
|
-
};
|
|
490
|
+
animate = { left: `${targetX}%`, top: `${targetY}%`, scale: 1 };
|
|
491
|
+
transition = { type: "spring", stiffness: 300, damping: 30, mass: 0.5 };
|
|
426
492
|
}
|
|
427
493
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
428
494
|
framerMotion.motion.div,
|
|
@@ -442,13 +508,17 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
442
508
|
"ball"
|
|
443
509
|
);
|
|
444
510
|
})()
|
|
511
|
+
] }),
|
|
512
|
+
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: [
|
|
513
|
+
"\u26A0 ",
|
|
514
|
+
t("offsideWarning")
|
|
445
515
|
] })
|
|
446
516
|
] })
|
|
447
517
|
}
|
|
448
518
|
);
|
|
449
519
|
if (!showCoordinates) return board;
|
|
450
520
|
const ranksTopToBottom = [...chessFootballEngine.RANK_LABELS].reverse();
|
|
451
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-[540px] mx-auto", "aria-hidden": "false", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
521
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-[540px] md:max-w-none mx-auto", "aria-hidden": "false", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
452
522
|
"div",
|
|
453
523
|
{
|
|
454
524
|
className: "grid gap-1 select-none",
|
|
@@ -471,26 +541,10 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = false }) {
|
|
|
471
541
|
) });
|
|
472
542
|
}
|
|
473
543
|
function FileRow({ files }) {
|
|
474
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-9 gap-[1px] px-[2px]", children: files.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
475
|
-
"span",
|
|
476
|
-
{
|
|
477
|
-
"aria-hidden": "true",
|
|
478
|
-
className: "flex items-center justify-center font-mono text-[9px] text-fg-muted/80 uppercase tracking-[0.5px]",
|
|
479
|
-
children: f
|
|
480
|
-
},
|
|
481
|
-
f
|
|
482
|
-
)) });
|
|
544
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-9 gap-[1px] px-[2px]", children: files.map((f) => /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "flex items-center justify-center font-mono text-[9px] text-fg-muted/80 uppercase tracking-[0.5px]", children: f }, f)) });
|
|
483
545
|
}
|
|
484
546
|
function RankColumn({ ranks }) {
|
|
485
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-rows-12 gap-[1px] py-[2px]", children: ranks.map((r) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
486
|
-
"span",
|
|
487
|
-
{
|
|
488
|
-
"aria-hidden": "true",
|
|
489
|
-
className: "flex items-center justify-center font-mono text-[9px] text-fg-muted/80 tabular-nums",
|
|
490
|
-
children: r
|
|
491
|
-
},
|
|
492
|
-
r
|
|
493
|
-
)) });
|
|
547
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-rows-12 gap-[1px] py-[2px]", children: ranks.map((r) => /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "flex items-center justify-center font-mono text-[9px] text-fg-muted/80 tabular-nums", children: r }, r)) });
|
|
494
548
|
}
|
|
495
549
|
function Avatar({ className, children }) {
|
|
496
550
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative w-9 h-9 rounded-full overflow-hidden shrink-0", className), children });
|
|
@@ -502,14 +556,6 @@ function AvatarImage({ src, alt, className }) {
|
|
|
502
556
|
function AvatarFallback({ className, children }) {
|
|
503
557
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("absolute inset-0 flex items-center justify-center text-xs font-semibold", className), children });
|
|
504
558
|
}
|
|
505
|
-
var fallback = (key) => key;
|
|
506
|
-
var GameI18nContext = React.createContext(fallback);
|
|
507
|
-
function GameI18nProvider({ t, children }) {
|
|
508
|
-
return /* @__PURE__ */ jsxRuntime.jsx(GameI18nContext.Provider, { value: t, children });
|
|
509
|
-
}
|
|
510
|
-
function useGameT() {
|
|
511
|
-
return React.useContext(GameI18nContext);
|
|
512
|
-
}
|
|
513
559
|
function ActionPoints({ total, remaining, size = 20, className, kingMustRelease }) {
|
|
514
560
|
const t = useGameT();
|
|
515
561
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center gap-1.5", className), "aria-label": t("actionPointsAriaLabel", { remaining, total }), children: Array.from({ length: total }).map((_, i) => {
|
|
@@ -567,6 +613,7 @@ function Scoreboard({
|
|
|
567
613
|
const isMyTurn = turn === userSide;
|
|
568
614
|
const myKingMustRelease = isMyTurn && kingMustRelease === turn;
|
|
569
615
|
const rivalKingMustRelease = !isMyTurn && kingMustRelease === turn;
|
|
616
|
+
const maxAP = boardState.maxActionPoints ?? 5;
|
|
570
617
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full bg-bg-secondary flex items-center justify-between px-5 py-2.5", children: [
|
|
571
618
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
572
619
|
PlayerInfo,
|
|
@@ -576,6 +623,7 @@ function Scoreboard({
|
|
|
576
623
|
avatarUrl: myAvatar,
|
|
577
624
|
isActive: isMyTurn,
|
|
578
625
|
actionPoints: isMyTurn ? actionPoints : 0,
|
|
626
|
+
maxActionPoints: maxAP,
|
|
579
627
|
kingMustRelease: myKingMustRelease,
|
|
580
628
|
align: "left"
|
|
581
629
|
}
|
|
@@ -593,13 +641,14 @@ function Scoreboard({
|
|
|
593
641
|
avatarUrl: rivalAvatar,
|
|
594
642
|
isActive: !isMyTurn,
|
|
595
643
|
actionPoints: !isMyTurn ? actionPoints : 0,
|
|
644
|
+
maxActionPoints: maxAP,
|
|
596
645
|
kingMustRelease: rivalKingMustRelease,
|
|
597
646
|
align: "right"
|
|
598
647
|
}
|
|
599
648
|
)
|
|
600
649
|
] });
|
|
601
650
|
}
|
|
602
|
-
function PlayerInfo({ name, team, avatarUrl, isActive, actionPoints, kingMustRelease, align }) {
|
|
651
|
+
function PlayerInfo({ name, team, avatarUrl, isActive, actionPoints, maxActionPoints, kingMustRelease, align }) {
|
|
603
652
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2.5", align === "right" && "flex-row-reverse"), children: [
|
|
604
653
|
/* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: cn(
|
|
605
654
|
"w-9 h-9 border-2 transition-colors duration-300",
|
|
@@ -620,7 +669,7 @@ function PlayerInfo({ name, team, avatarUrl, isActive, actionPoints, kingMustRel
|
|
|
620
669
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
621
670
|
ActionPoints,
|
|
622
671
|
{
|
|
623
|
-
total:
|
|
672
|
+
total: maxActionPoints,
|
|
624
673
|
remaining: actionPoints,
|
|
625
674
|
size: 12,
|
|
626
675
|
kingMustRelease,
|
|
@@ -741,78 +790,36 @@ function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, on
|
|
|
741
790
|
function GameControls({ isMyTurn }) {
|
|
742
791
|
const {
|
|
743
792
|
boardState,
|
|
744
|
-
selectedPieceId,
|
|
745
|
-
interactionMode,
|
|
746
|
-
setInteractionMode,
|
|
747
793
|
endTurn
|
|
748
794
|
} = chunkJ2TBQPPC_cjs.useGameStore();
|
|
749
795
|
const t = useGameT();
|
|
750
796
|
const [showEndTurnConfirm, setShowEndTurnConfirm] = React.useState(false);
|
|
751
797
|
if (!boardState) return null;
|
|
752
798
|
const actionPoints = boardState.actionPoints;
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
799
|
+
const handleEndTurn = () => {
|
|
800
|
+
if (actionPoints >= 2) {
|
|
801
|
+
setShowEndTurnConfirm(true);
|
|
802
|
+
} else {
|
|
803
|
+
endTurn();
|
|
804
|
+
}
|
|
805
|
+
};
|
|
757
806
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full bg-bg-secondary flex flex-col gap-3 px-5 pt-3 pb-5", children: [
|
|
758
|
-
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isMyTurn && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
759
|
-
framerMotion.motion.div,
|
|
760
|
-
{
|
|
761
|
-
initial: { opacity: 0, y: 8 },
|
|
762
|
-
animate: { opacity: 1, y: 0 },
|
|
763
|
-
exit: { opacity: 0, y: 8 },
|
|
764
|
-
className: "flex gap-2",
|
|
765
|
-
children: [
|
|
766
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
767
|
-
"button",
|
|
768
|
-
{
|
|
769
|
-
onClick: () => setInteractionMode("move"),
|
|
770
|
-
disabled: !canMove,
|
|
771
|
-
className: cn(
|
|
772
|
-
"flex-1 flex items-center justify-center gap-2 h-11 rounded-md border font-inter text-sm font-semibold",
|
|
773
|
-
"transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-move-highlight",
|
|
774
|
-
"disabled:opacity-40 disabled:cursor-not-allowed",
|
|
775
|
-
interactionMode === "move" ? "bg-move-highlight/10 border-move-highlight text-move-highlight" : "bg-bg-surface border-border-subtle text-move-highlight hover:bg-move-highlight/5"
|
|
776
|
-
),
|
|
777
|
-
"aria-pressed": interactionMode === "move",
|
|
778
|
-
children: [
|
|
779
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Move, { size: 16, strokeWidth: 2 }),
|
|
780
|
-
t("move")
|
|
781
|
-
]
|
|
782
|
-
}
|
|
783
|
-
),
|
|
784
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
785
|
-
"button",
|
|
786
|
-
{
|
|
787
|
-
onClick: () => setInteractionMode("pass"),
|
|
788
|
-
disabled: !canPass,
|
|
789
|
-
className: cn(
|
|
790
|
-
"flex-1 flex items-center justify-center gap-2 h-11 rounded-md border font-inter text-sm font-semibold",
|
|
791
|
-
"transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-pass-highlight",
|
|
792
|
-
"disabled:opacity-40 disabled:cursor-not-allowed",
|
|
793
|
-
interactionMode === "pass" ? "bg-pass-highlight/10 border-pass-highlight text-pass-highlight" : "bg-bg-surface border-border-subtle text-pass-highlight hover:bg-pass-highlight/5"
|
|
794
|
-
),
|
|
795
|
-
"aria-pressed": interactionMode === "pass",
|
|
796
|
-
children: [
|
|
797
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-4 h-4 inline-flex", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) }),
|
|
798
|
-
t("pass")
|
|
799
|
-
]
|
|
800
|
-
}
|
|
801
|
-
)
|
|
802
|
-
]
|
|
803
|
-
},
|
|
804
|
-
"action-btns"
|
|
805
|
-
) }),
|
|
806
807
|
isMyTurn && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
807
808
|
Button,
|
|
808
809
|
{
|
|
809
810
|
variant: "primary",
|
|
810
811
|
size: "default",
|
|
811
812
|
className: "w-full gap-2 tracking-[1.5px]",
|
|
812
|
-
onClick:
|
|
813
|
+
onClick: handleEndTurn,
|
|
813
814
|
children: [
|
|
814
815
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Flag, { size: 16, strokeWidth: 2 }),
|
|
815
|
-
t("endTurn")
|
|
816
|
+
t("endTurn"),
|
|
817
|
+
actionPoints >= 2 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-1 font-inter text-xs font-normal opacity-70 tracking-normal"), children: [
|
|
818
|
+
"\xB7 ",
|
|
819
|
+
actionPoints,
|
|
820
|
+
" ",
|
|
821
|
+
t("actionPointsShort")
|
|
822
|
+
] })
|
|
816
823
|
]
|
|
817
824
|
}
|
|
818
825
|
),
|
|
@@ -1103,6 +1110,193 @@ function StaticGameBoard() {
|
|
|
1103
1110
|
)
|
|
1104
1111
|
] });
|
|
1105
1112
|
}
|
|
1113
|
+
function TurnBanner({ isMyTurn, waitingLabel, className }) {
|
|
1114
|
+
const t = useGameT();
|
|
1115
|
+
const { boardState } = chunkJ2TBQPPC_cjs.useGameStore();
|
|
1116
|
+
if (!boardState) return null;
|
|
1117
|
+
const { actionPoints, maxActionPoints } = boardState;
|
|
1118
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1119
|
+
"div",
|
|
1120
|
+
{
|
|
1121
|
+
className: cn(
|
|
1122
|
+
"w-full h-9 flex items-center justify-between px-4 shrink-0 transition-colors duration-300",
|
|
1123
|
+
isMyTurn ? "bg-accent-green/15 border-b border-accent-green/30" : "bg-bg-surface border-b border-border-subtle",
|
|
1124
|
+
className
|
|
1125
|
+
),
|
|
1126
|
+
"aria-live": "polite",
|
|
1127
|
+
"aria-atomic": "true",
|
|
1128
|
+
children: [
|
|
1129
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1130
|
+
"span",
|
|
1131
|
+
{
|
|
1132
|
+
className: cn(
|
|
1133
|
+
"font-anton text-sm tracking-[1.5px] uppercase",
|
|
1134
|
+
isMyTurn ? "text-accent-green" : "text-fg-muted"
|
|
1135
|
+
),
|
|
1136
|
+
children: isMyTurn ? t("yourTurn") : waitingLabel ?? t("waitingRival")
|
|
1137
|
+
}
|
|
1138
|
+
),
|
|
1139
|
+
isMyTurn && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", "aria-label": t("actionPointsAriaLabel", { remaining: actionPoints, total: maxActionPoints }), children: [
|
|
1140
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { size: 12, className: "text-accent-green", "aria-hidden": "true" }),
|
|
1141
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-xs text-fg-secondary tabular-nums", children: [
|
|
1142
|
+
actionPoints,
|
|
1143
|
+
"/",
|
|
1144
|
+
maxActionPoints
|
|
1145
|
+
] })
|
|
1146
|
+
] })
|
|
1147
|
+
]
|
|
1148
|
+
}
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
var TOASTABLE = /* @__PURE__ */ new Set(["interception", "offside", "tackle"]);
|
|
1152
|
+
var TOAST_CONFIG = {
|
|
1153
|
+
interception: "bg-danger/20 border-danger/50 text-danger",
|
|
1154
|
+
offside: "bg-warning/20 border-warning/50 text-warning",
|
|
1155
|
+
tackle: "bg-warning/20 border-warning/50 text-warning"
|
|
1156
|
+
};
|
|
1157
|
+
function EventToast({ className }) {
|
|
1158
|
+
const t = useGameT();
|
|
1159
|
+
const { boardState } = chunkJ2TBQPPC_cjs.useGameStore();
|
|
1160
|
+
const [toast, setToast] = React.useState(null);
|
|
1161
|
+
React.useEffect(() => {
|
|
1162
|
+
const lastMove = boardState?.lastMove;
|
|
1163
|
+
if (!lastMove) return;
|
|
1164
|
+
if (!TOASTABLE.has(lastMove.type)) return;
|
|
1165
|
+
setToast({ type: lastMove.type, key: String(lastMove.at) });
|
|
1166
|
+
}, [boardState?.lastMove?.at]);
|
|
1167
|
+
React.useEffect(() => {
|
|
1168
|
+
if (!toast) return;
|
|
1169
|
+
const timer = setTimeout(() => setToast(null), 2500);
|
|
1170
|
+
return () => clearTimeout(timer);
|
|
1171
|
+
}, [toast?.key]);
|
|
1172
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1173
|
+
"div",
|
|
1174
|
+
{
|
|
1175
|
+
role: "status",
|
|
1176
|
+
"aria-live": "polite",
|
|
1177
|
+
"aria-atomic": "true",
|
|
1178
|
+
className: cn("pointer-events-none flex justify-center", className),
|
|
1179
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: toast && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1180
|
+
framerMotion.motion.div,
|
|
1181
|
+
{
|
|
1182
|
+
initial: { opacity: 0, y: -8 },
|
|
1183
|
+
animate: { opacity: 1, y: 0 },
|
|
1184
|
+
exit: { opacity: 0, y: -8 },
|
|
1185
|
+
transition: { duration: 0.15 },
|
|
1186
|
+
className: cn(
|
|
1187
|
+
"px-4 py-2 rounded-full border font-inter text-sm font-semibold shadow-lg backdrop-blur-sm text-center",
|
|
1188
|
+
TOAST_CONFIG[toast.type]
|
|
1189
|
+
),
|
|
1190
|
+
children: t(`eventToast.${toast.type}`)
|
|
1191
|
+
},
|
|
1192
|
+
toast.key
|
|
1193
|
+
) })
|
|
1194
|
+
}
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
function MobileHistory({ className }) {
|
|
1198
|
+
const { boardState } = chunkJ2TBQPPC_cjs.useGameStore();
|
|
1199
|
+
const [open, setOpen] = React.useState(false);
|
|
1200
|
+
const lastMove = boardState?.moveHistory?.at(-1);
|
|
1201
|
+
if (!lastMove) return null;
|
|
1202
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1203
|
+
/* @__PURE__ */ jsxRuntime.jsx(HistoryChip, { lastMove, onClick: () => setOpen(true), className }),
|
|
1204
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1205
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1206
|
+
framerMotion.motion.div,
|
|
1207
|
+
{
|
|
1208
|
+
initial: { opacity: 0 },
|
|
1209
|
+
animate: { opacity: 1 },
|
|
1210
|
+
exit: { opacity: 0 },
|
|
1211
|
+
transition: { duration: 0.2 },
|
|
1212
|
+
className: "fixed inset-0 z-40 bg-black/60 backdrop-blur-sm",
|
|
1213
|
+
onClick: () => setOpen(false),
|
|
1214
|
+
"aria-hidden": "true"
|
|
1215
|
+
},
|
|
1216
|
+
"backdrop"
|
|
1217
|
+
),
|
|
1218
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1219
|
+
framerMotion.motion.div,
|
|
1220
|
+
{
|
|
1221
|
+
initial: { y: "100%" },
|
|
1222
|
+
animate: { y: 0 },
|
|
1223
|
+
exit: { y: "100%" },
|
|
1224
|
+
transition: { type: "spring", stiffness: 300, damping: 32 },
|
|
1225
|
+
className: "fixed bottom-0 left-0 right-0 z-50 bg-bg-secondary rounded-t-2xl border-t border-border-subtle shadow-xl",
|
|
1226
|
+
role: "dialog",
|
|
1227
|
+
"aria-modal": "true",
|
|
1228
|
+
children: [
|
|
1229
|
+
/* @__PURE__ */ jsxRuntime.jsx(SheetHeader, { onClose: () => setOpen(false) }),
|
|
1230
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-6 max-h-[50dvh] overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(MoveHistory, { scrollable: false }) })
|
|
1231
|
+
]
|
|
1232
|
+
},
|
|
1233
|
+
"sheet"
|
|
1234
|
+
)
|
|
1235
|
+
] }) })
|
|
1236
|
+
] });
|
|
1237
|
+
}
|
|
1238
|
+
function SheetHeader({ onClose }) {
|
|
1239
|
+
const t = useGameT();
|
|
1240
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 pt-4 pb-3 border-b border-border-subtle", children: [
|
|
1241
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[10px] tracking-[0.5px] uppercase text-fg-muted", children: t("history.title") }),
|
|
1242
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1243
|
+
"button",
|
|
1244
|
+
{
|
|
1245
|
+
onClick: onClose,
|
|
1246
|
+
className: "w-8 h-8 flex items-center justify-center rounded-full bg-bg-surface hover:bg-bg-surface-elevated text-fg-muted hover:text-fg-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-green",
|
|
1247
|
+
"aria-label": "Close",
|
|
1248
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 14 })
|
|
1249
|
+
}
|
|
1250
|
+
)
|
|
1251
|
+
] });
|
|
1252
|
+
}
|
|
1253
|
+
function HistoryChip({ lastMove, onClick, className }) {
|
|
1254
|
+
const t = useGameT();
|
|
1255
|
+
const toSq = chessFootballEngine.squareName(lastMove.to);
|
|
1256
|
+
let label;
|
|
1257
|
+
switch (lastMove.type) {
|
|
1258
|
+
case "pass":
|
|
1259
|
+
label = `\u2295 ${toSq}`;
|
|
1260
|
+
break;
|
|
1261
|
+
case "tackle":
|
|
1262
|
+
label = `\u2715 ${toSq}`;
|
|
1263
|
+
break;
|
|
1264
|
+
case "interception":
|
|
1265
|
+
label = `\u26D4 ${toSq}`;
|
|
1266
|
+
break;
|
|
1267
|
+
case "goal":
|
|
1268
|
+
label = `\u26BD GOL`;
|
|
1269
|
+
break;
|
|
1270
|
+
case "offside":
|
|
1271
|
+
label = `\u26A0 OFS`;
|
|
1272
|
+
break;
|
|
1273
|
+
default: {
|
|
1274
|
+
const pieceShort = t(`pieces.${chessFootballEngine.SHORT_KEY[lastMove.pieceType]}`);
|
|
1275
|
+
const fromSq = lastMove.from ? chessFootballEngine.squareName(lastMove.from) : "";
|
|
1276
|
+
label = fromSq ? `${pieceShort}${fromSq}\u2192${toSq}` : `${pieceShort}\u2192${toSq}`;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1280
|
+
"button",
|
|
1281
|
+
{
|
|
1282
|
+
onClick,
|
|
1283
|
+
className: cn(
|
|
1284
|
+
"flex items-center gap-1.5 px-3 py-1.5 rounded-full",
|
|
1285
|
+
"bg-bg-surface border border-border-subtle",
|
|
1286
|
+
"font-mono text-[11px] text-fg-secondary",
|
|
1287
|
+
"hover:text-fg-primary hover:bg-bg-surface-elevated active:scale-95",
|
|
1288
|
+
"transition-all duration-150",
|
|
1289
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-green",
|
|
1290
|
+
className
|
|
1291
|
+
),
|
|
1292
|
+
"aria-label": t("history.viewAll"),
|
|
1293
|
+
children: [
|
|
1294
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
|
|
1295
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-fg-muted text-[10px]", "aria-hidden": "true", children: "\u25BE" })
|
|
1296
|
+
]
|
|
1297
|
+
}
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1106
1300
|
|
|
1107
1301
|
exports.ActionPoints = ActionPoints;
|
|
1108
1302
|
exports.Avatar = Avatar;
|
|
@@ -1110,16 +1304,19 @@ exports.AvatarFallback = AvatarFallback;
|
|
|
1110
1304
|
exports.AvatarImage = AvatarImage;
|
|
1111
1305
|
exports.Button = Button;
|
|
1112
1306
|
exports.ConfirmDialog = ConfirmDialog;
|
|
1307
|
+
exports.EventToast = EventToast;
|
|
1113
1308
|
exports.Football = Football;
|
|
1114
1309
|
exports.GameBoard = GameBoard;
|
|
1115
1310
|
exports.GameControls = GameControls;
|
|
1116
1311
|
exports.GameI18nProvider = GameI18nProvider;
|
|
1117
1312
|
exports.GamePiece = GamePiece;
|
|
1118
1313
|
exports.MiniScoreboard = MiniScoreboard;
|
|
1314
|
+
exports.MobileHistory = MobileHistory;
|
|
1119
1315
|
exports.MoveHistory = MoveHistory;
|
|
1120
1316
|
exports.Scoreboard = Scoreboard;
|
|
1121
1317
|
exports.SelectedPieceDetail = SelectedPieceDetail;
|
|
1122
1318
|
exports.StaticGameBoard = StaticGameBoard;
|
|
1319
|
+
exports.TurnBanner = TurnBanner;
|
|
1123
1320
|
exports.cn = cn;
|
|
1124
1321
|
exports.useGameT = useGameT;
|
|
1125
1322
|
//# sourceMappingURL=index.cjs.map
|