From 9f02bc18887b90f11f205ab789c3ff3b00792ce3 Mon Sep 17 00:00:00 2001 From: Jonas Weinz Date: Thu, 13 Nov 2025 18:41:34 +0100 Subject: [PATCH] more frontend fixes --- .../server/server_config.py | 2 +- multiplayer_crosswords/webui/grid.js | 59 +++++++++++++++- multiplayer_crosswords/webui/index.html | 3 + multiplayer_crosswords/webui/styles.css | 68 +++++++++++++++---- 4 files changed, 118 insertions(+), 14 deletions(-) diff --git a/multiplayer_crosswords/server/server_config.py b/multiplayer_crosswords/server/server_config.py index f0b5daa..0b0458f 100644 --- a/multiplayer_crosswords/server/server_config.py +++ b/multiplayer_crosswords/server/server_config.py @@ -6,7 +6,7 @@ DEFAULT_WEBSOCKET_PORT = 8765 DEFAULT_MIN_GRID_SIZE = 10 DEFAULT_MAX_GRID_SIZE = 30 -DEFAULT_GRID_BLOCK_RATIO = 0.38 +DEFAULT_GRID_BLOCK_RATIO = 0.39 DEFAULT_MAX_SESSION_IDLE_TIME_SECONDS = 3600 * 48 # 2 days diff --git a/multiplayer_crosswords/webui/grid.js b/multiplayer_crosswords/webui/grid.js index 88372a4..0f70a46 100644 --- a/multiplayer_crosswords/webui/grid.js +++ b/multiplayer_crosswords/webui/grid.js @@ -17,6 +17,7 @@ export class CrosswordGrid extends LitElement { _selected: { state: true }, _inputMode: { state: true }, // 'horizontal' or 'vertical' _solvedCells: { state: true }, // tracks which cells are solved + _clueNumbers: { state: true }, // map of "row,col" -> { across: number, down: number } }; // styles moved to webui/styles.css; render into light DOM so external CSS applies @@ -29,6 +30,7 @@ export class CrosswordGrid extends LitElement { this._selected = { r: 0, c: 0 }; this._inputMode = 'horizontal'; // default input mode this._solvedCells = new Set(); // set of "r,c" strings for solved cells + this._clueNumbers = new Map(); // map of "row,col" -> { across: number, down: number } this.sessionId = null; // Session ID for sending updates to server } @@ -119,7 +121,27 @@ export class CrosswordGrid extends LitElement { } } - return html`
this._onCellClick(r, c)} data-r="${r}" data-c="${c}">${value}
`; + // Get clue numbers for this cell + const clueInfo = this._clueNumbers.get(cellKey); + let clueNumberDisplay = ''; + if (clueInfo) { + if (clueInfo.across !== null && clueInfo.down !== null) { + // Both across and down clues: show "across/down" format + clueNumberDisplay = `${clueInfo.across}/${clueInfo.down}`; + } else if (clueInfo.across !== null) { + // Only across clue + clueNumberDisplay = String(clueInfo.across); + } else if (clueInfo.down !== null) { + // Only down clue + clueNumberDisplay = String(clueInfo.down); + } + } + + const cellContent = clueNumberDisplay + ? html`${clueNumberDisplay}${value}` + : html`${value}`; + + return html`
this._onCellClick(r, c)} data-r="${r}" data-c="${c}">${cellContent}
`; } /** @@ -465,6 +487,41 @@ export class CrosswordGrid extends LitElement { console.log(`Letter update from server: [${row}, ${col}] = "${letter}" (solved: ${is_solved})`); } } + + /** + * Populate clue numbers from server data + * @param {Object} cluePositionsAcross - dict of clue_number -> [col, row] + * @param {Object} cluePositionsDown - dict of clue_number -> [col, row] + */ + populateClueNumbers(cluePositionsAcross = {}, cluePositionsDown = {}) { + this._clueNumbers.clear(); + + // Add across clues + for (const [clueNum, position] of Object.entries(cluePositionsAcross)) { + const [col, row] = position; + const cellKey = `${row},${col}`; + + if (!this._clueNumbers.has(cellKey)) { + this._clueNumbers.set(cellKey, { across: null, down: null }); + } + + this._clueNumbers.get(cellKey).across = parseInt(clueNum); + } + + // Add down clues + for (const [clueNum, position] of Object.entries(cluePositionsDown)) { + const [col, row] = position; + const cellKey = `${row},${col}`; + + if (!this._clueNumbers.has(cellKey)) { + this._clueNumbers.set(cellKey, { across: null, down: null }); + } + + this._clueNumbers.get(cellKey).down = parseInt(clueNum); + } + + this.requestUpdate(); + } } customElements.define('crossword-grid', CrosswordGrid); \ No newline at end of file diff --git a/multiplayer_crosswords/webui/index.html b/multiplayer_crosswords/webui/index.html index 0ee0cb6..30d4252 100644 --- a/multiplayer_crosswords/webui/index.html +++ b/multiplayer_crosswords/webui/index.html @@ -178,6 +178,9 @@ } } + // Populate clue numbers for display + gridElement.populateClueNumbers(message.clue_positions_across, message.clue_positions_down); + gridElement.requestUpdate(); console.log(`Grid created: ${gridRows}x${gridCols} with ${wallPositions.length} walls`); diff --git a/multiplayer_crosswords/webui/styles.css b/multiplayer_crosswords/webui/styles.css index a05ad51..104dd7c 100644 --- a/multiplayer_crosswords/webui/styles.css +++ b/multiplayer_crosswords/webui/styles.css @@ -36,24 +36,35 @@ main { justify-content: center; align-items: flex-start; padding: var(--page-padding); - padding-bottom: var(--keyboard-space); + padding-bottom: 0; /* Remove keyboard space by default (desktop) */ min-height: calc(100vh - 0px); box-sizing: border-box; } -.container { width: 100%; max-width: var(--max-container-width); } + +/* Add keyboard space on mobile devices */ +@media (max-width: 900px) { + main { + padding-bottom: var(--keyboard-space); + } +} +.container { + width: fit-content; /* Size exactly to content */ + max-width: 100%; /* But don't exceed viewport */ +} + +#grid-container { + width: 100%; + overflow-x: auto; + overflow-y: auto; + display: flex; + justify-content: center; /* Center small grids */ +} crossword-grid { display: block; margin: 0 auto; } mobile-keyboard { display: block; } h2, h3 { margin: 0.5rem 0; color: #f5f1ed; text-align: center; text-shadow: 0 2px 4px rgba(0,0,0,0.7); font-weight: 600; } -crossword-grid { - display: block; - max-width: 100%; - margin: 0 auto; +crossword-grid { display: block; margin: 0 auto; } - border-radius: 0px; - background: var(--ink-dark); - position: relative; -} .grid { display: grid; @@ -139,6 +150,26 @@ crossword-grid { linear-gradient(135deg, #3a3530 0%, #2a2520 100%); } +/* Clue number styling - only in grid cells */ +.cell .clue-number { + position: absolute; + top: 2px; + left: 2px; + font-size: 0.55rem; + font-weight: 700; + line-height: 1; + color: #000000 !important; + pointer-events: none; +} + +.cell-letter { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; +} + .cell.mode-highlighted { background: repeating-linear-gradient(45deg, transparent, transparent 1px, rgba(100,180,200,.2) 1px, rgba(100,180,200,.2) 2px), @@ -783,8 +814,21 @@ crossword-menu { } .game-content { - display: flex; - justify-content: center; + display: block; + overflow-y: auto; + overflow-x: auto; + max-height: calc(100vh - 200px); /* Leave space for header, clue area, and keyboard */ + width: 100%; + padding: 1rem 0; /* Add some padding for breathing room */ + text-align: center; /* Center inline-block children */ +} + +crossword-grid { + display: inline-block; + min-width: fit-content; /* Ensure grid takes its full needed width */ + border-radius: 0px; + background: var(--ink-dark); + position: relative; } /* Clue Area */