Files
vim-sudoku/src_failed/useBoard/SudokuRenderer.ts
T
pastilhas 9292b83dd0 feat: prepare vim-sudoku for unified API implementation
- Archive previous implementation attempt (src -> src_failed)
- Create comprehensive IMPLEMENTATION_PLAN.md with phased approach
- Create IMPLEMENTATION.md to track implementation progress
- Update example app to match vim-maze patterns:
  - Simplify UI to desktop-only (no mobile support)
  - Add score metrics display (time, keystrokes, final score)
  - Update instructions for sudoku-specific keys (hjkl, i for edit)
  - Remove unnecessary mobile hooks

Phase 5 complete. Ready to begin Phase 10 (Setup & Core Types).
2025-10-22 18:08:33 +01:00

110 lines
3.6 KiB
TypeScript

import type { SudokuBoard, SudokuCell } from './types';
export class SudokuRenderer {
static renderBoard(container: HTMLElement, board: SudokuBoard): void {
const sudokuDiv = document.createElement('div');
sudokuDiv.id = 'sudoku';
sudokuDiv.className = 'sudoku-board';
for (let row = 0; row < 9; row++) {
const rowDiv = document.createElement('div');
rowDiv.className = 'sudoku-row';
for (let col = 0; col < 9; col++) {
const cell = board[row][col];
const cellDiv = document.createElement('div');
cellDiv.className = 'sudoku-cell';
cellDiv.dataset.row = row.toString();
cellDiv.dataset.col = col.toString();
cellDiv.textContent = cell.value || '';
if (cell.isGiven) {
cellDiv.classList.add('given');
}
if (cell.hasConflict) {
cellDiv.classList.add('conflict');
}
if (col === 2 || col === 5) {
cellDiv.classList.add('border-right');
}
if (row === 2 || row === 5) {
cellDiv.classList.add('border-bottom');
}
rowDiv.appendChild(cellDiv);
}
sudokuDiv.appendChild(rowDiv);
}
container.innerHTML = '';
container.appendChild(sudokuDiv);
}
static renderEmptyBoard(container: HTMLElement): void {
const emptyBoard: SudokuBoard = Array(9).fill(null).map(() =>
Array(9).fill(null).map(() => ({
value: '',
isGiven: false,
hasConflict: false
}))
);
SudokuRenderer.renderBoard(container, emptyBoard);
}
static updateCell(container: HTMLElement, row: number, col: number, cell: SudokuCell): void {
const cellEl = container.querySelector(`.sudoku-cell[data-row="${row}"][data-col="${col}"]`) as HTMLElement;
if (!cellEl) return;
cellEl.textContent = cell.value || '';
cellEl.classList.toggle('given', cell.isGiven);
cellEl.classList.toggle('conflict', cell.hasConflict);
}
static highlightCursor(container: HTMLElement, row: number, col: number, editMode: boolean): void {
const cells = container.querySelectorAll('.sudoku-cell');
cells.forEach(cell => cell.classList.remove('cursor', 'edit-mode'));
const cursorCell = container.querySelector(`.sudoku-cell[data-row="${row}"][data-col="${col}"]`) as HTMLElement;
if (cursorCell) {
cursorCell.classList.add('cursor');
if (editMode) {
cursorCell.classList.add('edit-mode');
}
}
}
static flashCell(container: HTMLElement, row: number, col: number, className: string, duration: number = 300): void {
const cellEl = container.querySelector(`.sudoku-cell[data-row="${row}"][data-col="${col}"]`) as HTMLElement;
if (!cellEl) return;
cellEl.classList.add(className);
setTimeout(() => cellEl.classList.remove(className), duration);
}
static highlightConflicts(container: HTMLElement, conflictIndices: number[], duration: number = 2000): void {
conflictIndices.forEach((idx) => {
const row = Math.floor(idx / 9);
const col = idx % 9;
const cellEl = container.querySelector(`.sudoku-cell[data-row="${row}"][data-col="${col}"]`) as HTMLElement;
if (cellEl) {
cellEl.classList.add('conflict');
}
});
setTimeout(() => {
conflictIndices.forEach((idx) => {
const row = Math.floor(idx / 9);
const col = idx % 9;
const cellEl = container.querySelector(`.sudoku-cell[data-row="${row}"][data-col="${col}"]`) as HTMLElement;
if (cellEl) {
cellEl.classList.remove('conflict');
}
});
}, duration);
}
}