Frontend: rozmery a farby dosky centralizovane do boardTheme
Sizing konstanty (seat/standings/guess/totals) presunute do boardTheme.ts a farebne odlisenie tipu v PlayerCircle (nad tip = terakota). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { emit } from '../lib/socket';
|
||||
import { forbiddenGuess } from '../lib/gameRules';
|
||||
import { GUESS_BUTTON } from '../lib/boardTheme';
|
||||
|
||||
interface Props {
|
||||
cardsInRound: number;
|
||||
@@ -7,15 +8,16 @@ interface Props {
|
||||
myOrder: number;
|
||||
activePlayer: number;
|
||||
activePlayerName: string;
|
||||
desktop?: boolean;
|
||||
}
|
||||
|
||||
export default function GuessControls({ cardsInRound, guesses, myOrder, activePlayer, activePlayerName }: Props) {
|
||||
export default function GuessControls({ cardsInRound, guesses, myOrder, activePlayer, activePlayerName, desktop = true }: Props) {
|
||||
const isMyTurn = activePlayer === myOrder;
|
||||
const forbidden = forbiddenGuess(cardsInRound, guesses);
|
||||
|
||||
if (!isMyTurn) {
|
||||
return (
|
||||
<p className="text-center text-sm text-green-dim py-3">
|
||||
<p className="text-center text-[14px] text-green-dim py-3">
|
||||
Čaká sa na tip:{' '}
|
||||
<span className="font-serif text-gold">{activePlayerName}</span>
|
||||
</p>
|
||||
@@ -23,6 +25,7 @@ export default function GuessControls({ cardsInRound, guesses, myOrder, activePl
|
||||
}
|
||||
|
||||
const options = Array.from({ length: cardsInRound + 1 }, (_, i) => i);
|
||||
const btn = desktop ? GUESS_BUTTON.desktop : GUESS_BUTTON.mobile;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-3 py-3">
|
||||
@@ -36,8 +39,9 @@ export default function GuessControls({ cardsInRound, guesses, myOrder, activePl
|
||||
disabled={isForbidden}
|
||||
onClick={() => emit.addGuess(n)}
|
||||
title={isForbidden ? 'Zakázaná hodnota (súčet = počet kopiek)' : undefined}
|
||||
style={{ width: btn.size, height: btn.size, fontSize: btn.font }}
|
||||
className={[
|
||||
'w-11 h-11 rounded-full font-serif text-lg border-2 transition-colors',
|
||||
'rounded-full font-serif border-2 transition-colors',
|
||||
isForbidden
|
||||
? 'border-[#5a2a2a] text-[#7a4040] opacity-40 cursor-not-allowed'
|
||||
: 'border-gold/50 text-gold hover:bg-gold hover:text-table hover:border-gold active:scale-95',
|
||||
|
||||
@@ -12,6 +12,11 @@ interface Props {
|
||||
export default function PlayerCircle({ name, won, guess, active, size = 52 }: Props) {
|
||||
const nameFont = Math.max(9, Math.round(size * 0.17));
|
||||
const valueFont = Math.round(size * 0.32);
|
||||
// Bid status at a glance: terracotta once the player has taken more tricks
|
||||
// than bid (the bid is already lost), gold while exactly on target, cream
|
||||
// while still chasing. Scoring: exact match = 10 + bid, anything else = 0.
|
||||
const guessColor =
|
||||
guess === null ? '#d8cba6' : won > guess ? '#e08066' : won === guess ? '#e8c14a' : '#d8cba6';
|
||||
// Oval: height a touch shorter than size so it reads as an ellipse. Width
|
||||
// starts at `size` (a circle for short names) but grows with the name via
|
||||
// fit-content + padding, up to a cap beyond which the name is ellipsised
|
||||
@@ -58,7 +63,10 @@ export default function PlayerCircle({ name, won, guess, active, size = 52 }: Pr
|
||||
}}
|
||||
>
|
||||
{won}
|
||||
<span style={{ fontSize: valueFont * 0.6, color: '#b0a585' }}>/{guess ?? '?'}</span>
|
||||
{/* The bid matters as much as the tricks won — keep it nearly as big
|
||||
and in readable cream; only the slash separator stays muted. */}
|
||||
<span style={{ fontSize: valueFont * 0.7, color: '#b0a585' }}>/</span>
|
||||
<span style={{ fontSize: valueFont , color: guessColor }}>{guess ?? '?'}</span>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
||||
import type { PlayerInfo } from '../types';
|
||||
import { computeTotal } from '../lib/standings';
|
||||
import { displayName } from '../lib/names';
|
||||
import { STANDINGS_FONT } from '../lib/boardTheme';
|
||||
|
||||
interface Props {
|
||||
standings: number[][][];
|
||||
@@ -40,14 +41,8 @@ export default function Standings({ standings, guesses = [], players, myOrder, d
|
||||
const ROUNDS_PER_SERIES = 8;
|
||||
|
||||
// Bigger, more legible type on the wide desktop sidebar; compact on mobile.
|
||||
const fz = {
|
||||
head: desktop ? 11 : 10,
|
||||
idx: desktop ? 13 : 9,
|
||||
cell: desktop ? 19 : 14,
|
||||
dot: desktop ? 18 : 13,
|
||||
sigma: desktop ? 13 : 9,
|
||||
total: desktop ? 20 : 18,
|
||||
};
|
||||
// Sizes live in one place (boardTheme.ts) alongside the rest of the board.
|
||||
const fz = desktop ? STANDINGS_FONT.desktop : STANDINGS_FONT.mobile;
|
||||
|
||||
const gridCols = { gridTemplateColumns: `28px repeat(${cols.length}, 1fr)` };
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Single source of truth for the game board's fixed pixel sizes.
|
||||
//
|
||||
// The board deliberately uses fixed px (not rem) so it stays pixel-precise and
|
||||
// scales as one unit via `useFitScale` (desktop) — see index.css for why the
|
||||
// board opts out of the global rem type lever. These constants keep those px
|
||||
// values in one place instead of scattered as inline literals across the board
|
||||
// components (Standings / GameTable / …).
|
||||
//
|
||||
// PlayerCircle derives its own font/padding as ratios of the `size` it gets, so
|
||||
// its internal ratios stay local to that component; only the per-seat `size`
|
||||
// inputs live here.
|
||||
|
||||
/** Player-circle diameter per seat, by viewport. */
|
||||
export const SEAT_SIZE = {
|
||||
desktop: { top: 64, side: 64, me: 70 },
|
||||
mobile: { top: 52, side: 48, me: 60 },
|
||||
} as const;
|
||||
|
||||
/** Score list (Standings) type sizes. */
|
||||
export const STANDINGS_FONT = {
|
||||
desktop: { head: 12, idx: 13, cell: 18, dot: 18, sigma: 18, total: 20 },
|
||||
mobile: { head: 11, idx: 9, cell: 16, dot: 13, sigma: 15, total: 18 },
|
||||
} as const;
|
||||
|
||||
/** Header / score totals row (GameTable). The value size differs between the
|
||||
* compact desktop header and the mobile header. */
|
||||
export const TOTALS_FONT = {
|
||||
label: 12,
|
||||
valueDesktop: 18,
|
||||
valueMobile: 17,
|
||||
} as const;
|
||||
|
||||
/** Guess (tip) picker buttons (GuessControls): round button diameter + label
|
||||
* size, in px — kept fixed like the rest of the board (not rem Tailwind classes)
|
||||
* so they don't drift with the global font-size lever. */
|
||||
export const GUESS_BUTTON = {
|
||||
desktop: { size: 48, font: 22 },
|
||||
mobile: { size: 40, font: 18 },
|
||||
} as const;
|
||||
Reference in New Issue
Block a user