Refine chess board visual style
All checks were successful
Deploy blog-frontend / build-and-deploy (push) Successful in 2m10s
All checks were successful
Deploy blog-frontend / build-and-deploy (push) Successful in 2m10s
This commit is contained in:
8
LOG.md
8
LOG.md
@@ -1,5 +1,13 @@
|
||||
# Work Log
|
||||
|
||||
## 2026-06-24
|
||||
|
||||
- Refined the chess board visual style to match the app's glass/control surfaces instead of the previous heavy wood-and-token treatment.
|
||||
- Removed the circular chip backgrounds from pieces, kept high-contrast glyphs with subtle outlines, softened square/highlight colors, and tightened coordinate labels for a cleaner chess UI.
|
||||
- Rebalanced chess board sizing and layout columns so the board window, actual board, side panel, and Dock spacing feel less awkward on a 1280x720 desktop viewport.
|
||||
- Validation: `npm run lint` passed and `npm run build` passed. Browser verification on `http://localhost:3124/play/chess` with a temporary local puzzle API confirmed 64 squares, 32 rendered pieces, a 350px visible board above the Dock, balanced 480px/320px board-panel windows, and no console errors. The temporary API was stopped after verification.
|
||||
- Recommended next task: verify the real authenticated `/chess/play/{gameId}` board against the Maia backend at common laptop heights and tune only the board size formula if the live game info panel changes vertical rhythm.
|
||||
|
||||
## 2026-06-19
|
||||
|
||||
- Added Maia game resign and undo API wrappers, then wired the play screen with in-progress-only "무르기" and "기권" actions plus a persistent "새 게임" link back to the setup screen.
|
||||
|
||||
@@ -217,8 +217,8 @@ export default function ChessBoard({
|
||||
}, [fen, game, lastMoveSquares]);
|
||||
|
||||
return (
|
||||
<div className="relative aspect-square w-full rounded-xl border border-[#3f2d1f]/25 bg-[#4b3828] p-1.5 shadow-[0_20px_42px_rgb(49_35_24_/_0.22),0_1px_0_rgb(255_255_255_/_0.25)_inset] sm:p-2 dark:border-white/10 dark:bg-[#2a241f]">
|
||||
<div className="relative h-full w-full overflow-hidden rounded-lg border border-black/25 bg-[#1f2a24] shadow-[0_1px_0_rgb(255_255_255_/_0.18)_inset]">
|
||||
<div className="relative aspect-square w-full rounded-lg border border-[var(--color-line)] bg-[var(--color-control)] p-1 shadow-[var(--shadow-control)] backdrop-blur-[18px]">
|
||||
<div className="relative h-full w-full overflow-hidden rounded-md border border-white/60 bg-[var(--color-surface-strong)] shadow-[0_1px_0_rgb(255_255_255_/_0.46)_inset] dark:border-white/10">
|
||||
<div className="grid h-full w-full grid-cols-[repeat(8,minmax(0,1fr))] grid-rows-[repeat(8,minmax(0,1fr))]">
|
||||
{boardSquares.map((square) => {
|
||||
const piece = game.get(square);
|
||||
@@ -262,25 +262,25 @@ export default function ChessBoard({
|
||||
}}
|
||||
className={clsx(
|
||||
'relative min-h-0 min-w-0 overflow-hidden transition-[filter,box-shadow] duration-150',
|
||||
isLight ? 'bg-[#f0dfc1]' : 'bg-[#6f8f72]',
|
||||
isLight ? 'bg-[#edf2f5] dark:bg-[#c8d0d6]' : 'bg-[#7fa18b] dark:bg-[#415d52]',
|
||||
canDrag && 'cursor-grab active:cursor-grabbing',
|
||||
!disabled && 'hover:brightness-110 focus-visible:z-20',
|
||||
!disabled && 'hover:brightness-[1.04] focus-visible:z-20',
|
||||
disabled && 'cursor-not-allowed',
|
||||
)}
|
||||
aria-label={getSquareLabel(square, piece)}
|
||||
aria-pressed={isSelected}
|
||||
>
|
||||
{isLastMoveSquare && (
|
||||
<span className="absolute inset-1 rounded-md bg-amber-300/35 shadow-[0_0_0_1px_rgb(255_244_184_/_0.42)_inset,0_0_18px_rgb(245_158_11_/_0.28)]" />
|
||||
<span className="absolute inset-1 rounded bg-[var(--color-accent-soft)] shadow-[0_0_0_1px_rgb(255_255_255_/_0.34)_inset]" />
|
||||
)}
|
||||
{isSelected && (
|
||||
<span className="absolute inset-1 rounded-md border-2 border-sky-300 bg-sky-300/20 shadow-[0_0_18px_rgb(56_189_248_/_0.42)]" />
|
||||
<span className="absolute inset-1 rounded border-2 border-[var(--color-accent)] bg-[var(--color-accent-soft)] shadow-[0_0_0_2px_rgb(255_255_255_/_0.28)_inset]" />
|
||||
)}
|
||||
{file === firstFile && (
|
||||
<span
|
||||
className={clsx(
|
||||
'absolute left-1.5 top-1 text-[10px] font-bold leading-none',
|
||||
isLight ? 'text-[#6f8f72]' : 'text-[#f0dfc1]',
|
||||
'absolute left-1 top-1 text-[9px] font-bold leading-none sm:left-1.5 sm:top-1.5 sm:text-[10px]',
|
||||
isLight ? 'text-[#7a9a86]' : 'text-white/80',
|
||||
)}
|
||||
>
|
||||
{rank}
|
||||
@@ -289,8 +289,8 @@ export default function ChessBoard({
|
||||
{rank === lastRank && (
|
||||
<span
|
||||
className={clsx(
|
||||
'absolute bottom-1 right-1.5 text-[10px] font-bold leading-none',
|
||||
isLight ? 'text-[#6f8f72]' : 'text-[#f0dfc1]',
|
||||
'absolute bottom-1 right-1 text-[9px] font-bold leading-none sm:bottom-1.5 sm:right-1.5 sm:text-[10px]',
|
||||
isLight ? 'text-[#7a9a86]' : 'text-white/80',
|
||||
)}
|
||||
>
|
||||
{file}
|
||||
@@ -301,8 +301,8 @@ export default function ChessBoard({
|
||||
className={clsx(
|
||||
'absolute z-10 rounded-full transition',
|
||||
piece
|
||||
? 'inset-[12%] border-[3px] border-rose-500/55 shadow-[0_0_0_1px_rgb(255_255_255_/_0.26)_inset]'
|
||||
: 'left-1/2 top-1/2 h-[24%] w-[24%] -translate-x-1/2 -translate-y-1/2 bg-slate-950/35 shadow-[0_1px_3px_rgb(0_0_0_/_0.24)]',
|
||||
? 'inset-[13%] border-[2px] border-[var(--color-accent)]/70 shadow-[0_0_0_1px_rgb(255_255_255_/_0.28)_inset]'
|
||||
: 'left-1/2 top-1/2 h-[22%] w-[22%] -translate-x-1/2 -translate-y-1/2 bg-[var(--color-accent)]/42 shadow-[0_1px_3px_rgb(0_0_0_/_0.18)]',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
@@ -326,13 +326,13 @@ export default function ChessBoard({
|
||||
>
|
||||
<span
|
||||
className={clsx(
|
||||
'flex h-[82%] w-[82%] select-none items-center justify-center rounded-full font-serif text-[2rem] font-bold leading-none transition-[transform,filter] duration-200 sm:text-[2.45rem] md:text-[3.35rem]',
|
||||
'flex h-full w-full select-none items-center justify-center font-serif text-[2.5rem] font-bold leading-none transition-[transform,filter] duration-200 sm:text-[3rem] md:text-[3.6rem]',
|
||||
canDrag && 'cursor-grab active:cursor-grabbing',
|
||||
isSelected && 'scale-110 -translate-y-0.5 brightness-110',
|
||||
isLastMovePiece && 'scale-105',
|
||||
isLastMovePiece && 'scale-[1.04]',
|
||||
piece.color === 'w'
|
||||
? 'border border-[#6a4f31]/45 bg-[radial-gradient(circle_at_35%_28%,#fffdf7_0%,#f5ead7_62%,#dbc8a5_100%)] text-[#2f271f] shadow-[0_5px_10px_rgb(53_39_25_/_0.30),0_1px_0_rgb(255_255_255_/_0.75)_inset] [text-shadow:0_1px_0_rgb(255_255_255_/_0.65)]'
|
||||
: 'border border-black/45 bg-[radial-gradient(circle_at_35%_28%,#53565d_0%,#1f2329_64%,#090b0f_100%)] text-[#fff1d1] shadow-[0_7px_12px_rgb(0_0_0_/_0.42),0_1px_0_rgb(255_255_255_/_0.22)_inset] [text-shadow:0_1px_2px_rgb(0_0_0_/_0.8)]',
|
||||
? 'text-[#fffdf7] [text-shadow:0_1px_2px_rgb(0_0_0_/_0.48),0_0_1px_rgb(0_0_0_/_0.72),0_5px_9px_rgb(15_23_42_/_0.2)]'
|
||||
: 'text-[#151922] [text-shadow:0_1px_0_rgb(255_255_255_/_0.72),0_0_1px_rgb(255_255_255_/_0.82),0_5px_9px_rgb(15_23_42_/_0.2)]',
|
||||
)}
|
||||
>
|
||||
{PIECE_SYMBOLS[piece.color][piece.type]}
|
||||
|
||||
@@ -489,14 +489,14 @@ export default function ChessGamePlayClient({ gameId }: ChessGamePlayClientProps
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
<section className="grid min-w-0 items-start gap-5 xl:grid-cols-[minmax(0,1fr)_22rem]">
|
||||
<section className="grid min-w-0 items-start justify-center gap-5 xl:grid-cols-[minmax(0,30rem)_22rem]">
|
||||
<WindowSurface
|
||||
title="Board"
|
||||
subtitle={isPending ? 'Updating' : isPlayerTurn ? 'Your move' : 'Synced'}
|
||||
showTrafficLights={false}
|
||||
bodyClassName="p-3 md:p-5"
|
||||
bodyClassName="p-2 md:p-3"
|
||||
>
|
||||
<div className="relative mx-auto max-w-full" style={{ width: 'min(100%, clamp(18rem, calc(100svh - 23rem), 40rem))' }}>
|
||||
<div className="relative mx-auto max-w-full" style={{ width: 'min(100%, clamp(19rem, min(52vw, calc(100svh - 22.5rem)), 30rem))' }}>
|
||||
<ChessBoard
|
||||
fen={currentFen}
|
||||
orientation={game.playerColor}
|
||||
|
||||
@@ -23,7 +23,7 @@ type FeedbackTone = 'neutral' | 'success' | 'error';
|
||||
|
||||
const TIMEZONE = 'Asia/Seoul';
|
||||
const BOARD_SIZE_STYLE: CSSProperties = {
|
||||
width: 'min(100%, clamp(18rem, calc(100svh - 23rem), 40rem))',
|
||||
width: 'min(100%, clamp(19rem, min(52vw, calc(100svh - 22.5rem)), 30rem))',
|
||||
};
|
||||
|
||||
const turnLabel = (color: Color) => (color === 'w' ? '백' : '흑');
|
||||
@@ -83,7 +83,7 @@ function ChessPageFrame({ children }: { children: ReactNode }) {
|
||||
|
||||
function BoardWindow({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<WindowSurface title="Board" showTrafficLights={false} bodyClassName="p-3 md:p-5">
|
||||
<WindowSurface title="Board" showTrafficLights={false} bodyClassName="p-2 md:p-3">
|
||||
<div className="mx-auto max-w-full" style={BOARD_SIZE_STYLE}>
|
||||
{children}
|
||||
</div>
|
||||
@@ -95,7 +95,7 @@ function LoadingState() {
|
||||
return (
|
||||
<ChessPageFrame>
|
||||
<PageHeader />
|
||||
<section className="grid min-w-0 items-start gap-5 lg:grid-cols-[minmax(0,1fr)_20rem]">
|
||||
<section className="grid min-w-0 items-start justify-center gap-5 lg:grid-cols-[minmax(0,30rem)_20rem]">
|
||||
<BoardWindow>
|
||||
<div className="grid aspect-square w-full grid-cols-8 overflow-hidden rounded-lg border border-[var(--color-line)]">
|
||||
{BOARD_SQUARES.map((square, index) => (
|
||||
@@ -103,8 +103,9 @@ function LoadingState() {
|
||||
key={square}
|
||||
className={clsx(
|
||||
'aspect-square animate-pulse',
|
||||
(index + Math.floor(index / 8)) % 2 === 0 ? 'bg-black/[0.06]' : 'bg-black/[0.12]',
|
||||
'dark:bg-white/[0.08]',
|
||||
(index + Math.floor(index / 8)) % 2 === 0
|
||||
? 'bg-[#edf2f5] dark:bg-[#c8d0d6]'
|
||||
: 'bg-[#7fa18b] dark:bg-[#415d52]',
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
@@ -269,7 +270,7 @@ function ChessPuzzleBoard({ puzzle }: { puzzle: ChessPuzzle }) {
|
||||
<ChessPageFrame>
|
||||
<PageHeader />
|
||||
|
||||
<section className="grid min-w-0 items-start gap-5 lg:grid-cols-[minmax(0,1fr)_20rem]">
|
||||
<section className="grid min-w-0 items-start justify-center gap-5 lg:grid-cols-[minmax(0,30rem)_20rem]">
|
||||
<BoardWindow>
|
||||
<ChessBoard
|
||||
fen={currentFen}
|
||||
|
||||
Reference in New Issue
Block a user