diff --git a/app/__pycache__/app.cpython-314.pyc b/app/__pycache__/app.cpython-314.pyc index 69cd1f4..eb9c683 100644 Binary files a/app/__pycache__/app.cpython-314.pyc and b/app/__pycache__/app.cpython-314.pyc differ diff --git a/app/app.py b/app/app.py index 5fe75f5..2ca5b70 100755 --- a/app/app.py +++ b/app/app.py @@ -40,6 +40,9 @@ def get_puzzle_numbers(cursor): rows = cursor.execute("SELECT number FROM puzzle ORDER BY number").fetchall() return [row[0] for row in rows] +def get_nav_numbers(puzzle_numbers, center): + return [number for number in puzzle_numbers if center - 2 <= number <= center + 2] + def get_puzzle_summaries(cursor): rows = cursor.execute( "SELECT number, author, creation_date FROM puzzle ORDER BY number" @@ -53,6 +56,12 @@ def get_puzzle_summaries(cursor): for row in rows ] +def get_all_puzzle_rows(cursor): + return [ + {"number": 0, "author": DEFAULT_AUTHOR, "creation_date": DEFAULT_CREATION_DATE}, + *get_puzzle_summaries(cursor), + ] + def get_puzzle_record(cursor, puzzle_number): row = cursor.execute( "SELECT author, creation_date, data FROM puzzle WHERE number = ?", @@ -82,6 +91,7 @@ def render_puzzle(puzzle_number): if record is None: abort(404) + nav_numbers = get_nav_numbers(puzzle_numbers, puzzle_number) if puzzle_number == 0: categories = DEFAULT_CATEGORIES author = DEFAULT_AUTHOR @@ -96,7 +106,7 @@ def render_puzzle(puzzle_number): categories=categories, author=author, creation_date=creation_date, - puzzle_numbers=puzzle_numbers, + nav_numbers=nav_numbers, current_puzzle=puzzle_number, ) @@ -108,15 +118,28 @@ def index(): def puzzle_by_number(puzzle_number): return render_puzzle(puzzle_number) +@app.route('/all') +def all_puzzles(): + with sqlite3.connect(config.db_file) as connection: + cursor = connection.cursor() + puzzle_numbers = get_puzzle_numbers(cursor) + nav_center = puzzle_numbers[-1] if puzzle_numbers else 0 + nav_numbers = get_nav_numbers(puzzle_numbers, nav_center) + puzzles = get_all_puzzle_rows(cursor) + + return render_template('all.html', nav_numbers=nav_numbers, puzzles=puzzles) + @app.route('/new', methods=['GET', 'POST']) def new_puzzle(): with sqlite3.connect(config.db_file) as connection: cursor = connection.cursor() puzzle_numbers = get_puzzle_numbers(cursor) + nav_center = puzzle_numbers[-1] if puzzle_numbers else 0 + nav_numbers = get_nav_numbers(puzzle_numbers, nav_center) default_creation_date = today_display_date() if request.method == 'GET': - return render_template('new.html', creation_date=default_creation_date, puzzle_numbers=puzzle_numbers) + return render_template('new.html', creation_date=default_creation_date, nav_numbers=nav_numbers) author = request.form.get("author", "").strip() raw_creation_date = request.form.get("creation_date", "").strip() or default_creation_date @@ -136,7 +159,7 @@ def new_puzzle(): 'new.html', error="Author is required.", creation_date=raw_creation_date, - puzzle_numbers=puzzle_numbers, + nav_numbers=nav_numbers, form=request.form ), 400 @@ -145,7 +168,7 @@ def new_puzzle(): 'new.html', error='Creation date must be in the format "Day Month Year" (example: 15 March 2026).', creation_date=raw_creation_date, - puzzle_numbers=puzzle_numbers, + nav_numbers=nav_numbers, form=request.form ), 400 @@ -154,7 +177,7 @@ def new_puzzle(): 'new.html', error="Each category needs a name and exactly 4 words.", creation_date=raw_creation_date, - puzzle_numbers=puzzle_numbers, + nav_numbers=nav_numbers, form=request.form ), 400 @@ -174,7 +197,7 @@ def new_puzzle(): 'new.html', success=f"Saved puzzle #{number}.", creation_date=creation_date, - puzzle_numbers=puzzle_numbers + [number], + nav_numbers=get_nav_numbers(puzzle_numbers + [number], number), ) @app.route('/delete', methods=['GET', 'POST']) @@ -204,7 +227,7 @@ def delete_puzzle(): return render_template( 'delete.html', puzzles=puzzles, - puzzle_numbers=[puzzle["number"] for puzzle in puzzles], + nav_numbers=get_nav_numbers([puzzle["number"] for puzzle in puzzles], puzzles[-1]["number"] if puzzles else 0), deleted=request.args.get("deleted"), error=request.args.get("error"), ) diff --git a/app/static/css/style.css b/app/static/css/style.css index 2a9f17e..4035793 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -114,7 +114,7 @@ button:disabled { color: #2b7d32; } .subtitle { - margin-top: -8px; + margin-top: 0; margin-bottom: 18px; font-weight: bold; letter-spacing: 1px; @@ -237,6 +237,34 @@ button:disabled { margin: 0; font-weight: bold; } +.all-table-wrap { + width: 100%; + max-width: 900px; + overflow-x: auto; +} +.all-table { + width: 100%; + border-collapse: collapse; + background: #fff; +} +.all-table th, +.all-table td { + border-bottom: 1px solid #ddd; + padding: 10px 12px; + text-align: left; +} +.all-table th { + text-transform: uppercase; + letter-spacing: 0.7px; + font-size: 12px; +} +.table-link-btn { + display: inline-block; + padding: 6px 12px; + border-radius: 999px; + font-size: 12px; + line-height: 1; +} @media (max-width: 640px) { .meta-row { grid-template-columns: 1fr; diff --git a/app/templates/all.html b/app/templates/all.html new file mode 100644 index 0000000..02f254e --- /dev/null +++ b/app/templates/all.html @@ -0,0 +1,49 @@ + + + + + + + All Connections Puzzles + + + + + + +

Connections

+

All Puzzles

+ +
+ + + + + + + + + + + {% for puzzle in puzzles %} + + + + + + + {% endfor %} + +
Puzzle NumberAuthorCreation DateLink
{{ puzzle.number }}{{ puzzle.author }}{{ puzzle.creation_date }}Open
+
+ + + diff --git a/app/templates/delete.html b/app/templates/delete.html index ea9b738..fa442f9 100644 --- a/app/templates/delete.html +++ b/app/templates/delete.html @@ -10,8 +10,9 @@