- Add input validation and error handling across all API endpoints (malformed JSON, missing fields, invalid types return proper 4xx) - Add per-IP rate limiting (10/min new games, 60/min other requests) - Add session rollback on unhandled exceptions - Default debug=False, add --debug CLI flag to opt in - Frontend: add fetch error handling, fix feedback timeout stacking, disable buttons during requests, allow clicking found cells for overlapping word selection - Expand seed data to 7 categories with 25-35 words each Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
108 lines
3.9 KiB
HTML
108 lines
3.9 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block active_page %}{% set active_page = "play" %}{% end %}
|
|
|
|
{% block title %}Word Search — Play{% end %}
|
|
|
|
{% block content %}
|
|
<!-- Game Setup -->
|
|
<div id="game-setup">
|
|
<h2 class="mb-4">New Game</h2>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="row g-3 align-items-end">
|
|
<div class="col-md-3">
|
|
<label for="category-select" class="form-label">Category</label>
|
|
<select id="category-select" class="form-select"></select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="board-size" class="form-label">
|
|
Board Size: <span id="size-display">10</span>
|
|
</label>
|
|
<input type="range" id="board-size" class="form-range"
|
|
min="8" max="20" value="10">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="word-count" class="form-label">
|
|
Word Count: <span id="word-count-display">8</span>
|
|
</label>
|
|
<input type="range" id="word-count" class="form-range"
|
|
min="3" max="30" value="8">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button id="new-game-btn" class="btn btn-accent btn-lg w-100">
|
|
Start Game
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Game Board -->
|
|
<div id="game-board" class="d-none">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h2 class="mb-0">Word Search</h2>
|
|
<div class="d-flex align-items-center gap-3">
|
|
<span id="timer" class="badge bg-dark fs-6">0:00</span>
|
|
<button id="play-again-btn" class="btn btn-outline-light btn-sm d-none">
|
|
Play Again
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Completion Banner -->
|
|
<div id="completion-banner" class="alert alert-success d-none" role="alert">
|
|
<strong>Congratulations!</strong> You found all the words in
|
|
<span id="final-time"></span>!
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Grid -->
|
|
<div class="col-lg-8 mb-3">
|
|
<div class="card">
|
|
<div class="card-body p-2">
|
|
<table id="grid-table" class="game-grid mx-auto"></table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Input Area -->
|
|
<div class="card mt-3" id="input-area">
|
|
<div class="card-body">
|
|
<div class="row g-2">
|
|
<div class="col">
|
|
<input type="text" id="word-input"
|
|
class="form-control"
|
|
placeholder="Type a word..."
|
|
autocomplete="off">
|
|
</div>
|
|
<div class="col-auto">
|
|
<button id="guess-btn" class="btn btn-accent">
|
|
Submit
|
|
</button>
|
|
</div>
|
|
<div class="col-auto">
|
|
<button id="clear-selection-btn"
|
|
class="btn btn-outline-secondary d-none">
|
|
Clear
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="guess-feedback" class="mt-2"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Word List -->
|
|
<div class="col-lg-4">
|
|
<div class="card">
|
|
<div class="card-header">Words to Find</div>
|
|
<ul id="word-list" class="list-group list-group-flush"></ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="{{ static_url('js/game.js') }}"></script>
|
|
{% end %}
|