more frontend fixes
This commit is contained in:
@ -6,7 +6,7 @@ DEFAULT_WEBSOCKET_PORT = 8765
|
|||||||
DEFAULT_MIN_GRID_SIZE = 10
|
DEFAULT_MIN_GRID_SIZE = 10
|
||||||
DEFAULT_MAX_GRID_SIZE = 30
|
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
|
DEFAULT_MAX_SESSION_IDLE_TIME_SECONDS = 3600 * 48 # 2 days
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ export class CrosswordGrid extends LitElement {
|
|||||||
_selected: { state: true },
|
_selected: { state: true },
|
||||||
_inputMode: { state: true }, // 'horizontal' or 'vertical'
|
_inputMode: { state: true }, // 'horizontal' or 'vertical'
|
||||||
_solvedCells: { state: true }, // tracks which cells are solved
|
_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
|
// 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._selected = { r: 0, c: 0 };
|
||||||
this._inputMode = 'horizontal'; // default input mode
|
this._inputMode = 'horizontal'; // default input mode
|
||||||
this._solvedCells = new Set(); // set of "r,c" strings for solved cells
|
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
|
this.sessionId = null; // Session ID for sending updates to server
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +121,27 @@ export class CrosswordGrid extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`<div class="${classes.join(' ')}" @click=${() => this._onCellClick(r, c)} data-r="${r}" data-c="${c}">${value}</div>`;
|
// 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`<span class="clue-number">${clueNumberDisplay}</span><span class="cell-letter">${value}</span>`
|
||||||
|
: html`<span class="cell-letter">${value}</span>`;
|
||||||
|
|
||||||
|
return html`<div class="${classes.join(' ')}" @click=${() => this._onCellClick(r, c)} data-r="${r}" data-c="${c}">${cellContent}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -465,6 +487,41 @@ export class CrosswordGrid extends LitElement {
|
|||||||
console.log(`Letter update from server: [${row}, ${col}] = "${letter}" (solved: ${is_solved})`);
|
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);
|
customElements.define('crossword-grid', CrosswordGrid);
|
||||||
@ -178,6 +178,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate clue numbers for display
|
||||||
|
gridElement.populateClueNumbers(message.clue_positions_across, message.clue_positions_down);
|
||||||
|
|
||||||
gridElement.requestUpdate();
|
gridElement.requestUpdate();
|
||||||
|
|
||||||
console.log(`Grid created: ${gridRows}x${gridCols} with ${wallPositions.length} walls`);
|
console.log(`Grid created: ${gridRows}x${gridCols} with ${wallPositions.length} walls`);
|
||||||
|
|||||||
@ -36,24 +36,35 @@ main {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
padding: var(--page-padding);
|
padding: var(--page-padding);
|
||||||
padding-bottom: var(--keyboard-space);
|
padding-bottom: 0; /* Remove keyboard space by default (desktop) */
|
||||||
min-height: calc(100vh - 0px);
|
min-height: calc(100vh - 0px);
|
||||||
box-sizing: border-box;
|
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; }
|
crossword-grid { display: block; margin: 0 auto; }
|
||||||
mobile-keyboard { display: block; }
|
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; }
|
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 {
|
crossword-grid { display: block; margin: 0 auto; }
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
border-radius: 0px;
|
|
||||||
background: var(--ink-dark);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -139,6 +150,26 @@ crossword-grid {
|
|||||||
linear-gradient(135deg, #3a3530 0%, #2a2520 100%);
|
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 {
|
.cell.mode-highlighted {
|
||||||
background:
|
background:
|
||||||
repeating-linear-gradient(45deg, transparent, transparent 1px, rgba(100,180,200,.2) 1px, rgba(100,180,200,.2) 2px),
|
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 {
|
.game-content {
|
||||||
display: flex;
|
display: block;
|
||||||
justify-content: center;
|
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 */
|
/* Clue Area */
|
||||||
|
|||||||
Reference in New Issue
Block a user