All puzzle list
This commit is contained in:
parent
5a6bb5577b
commit
63f2ccebbf
Binary file not shown.
37
app/app.py
37
app/app.py
|
|
@ -40,6 +40,9 @@ def get_puzzle_numbers(cursor):
|
||||||
rows = cursor.execute("SELECT number FROM puzzle ORDER BY number").fetchall()
|
rows = cursor.execute("SELECT number FROM puzzle ORDER BY number").fetchall()
|
||||||
return [row[0] for row in rows]
|
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):
|
def get_puzzle_summaries(cursor):
|
||||||
rows = cursor.execute(
|
rows = cursor.execute(
|
||||||
"SELECT number, author, creation_date FROM puzzle ORDER BY number"
|
"SELECT number, author, creation_date FROM puzzle ORDER BY number"
|
||||||
|
|
@ -53,6 +56,12 @@ def get_puzzle_summaries(cursor):
|
||||||
for row in rows
|
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):
|
def get_puzzle_record(cursor, puzzle_number):
|
||||||
row = cursor.execute(
|
row = cursor.execute(
|
||||||
"SELECT author, creation_date, data FROM puzzle WHERE number = ?",
|
"SELECT author, creation_date, data FROM puzzle WHERE number = ?",
|
||||||
|
|
@ -82,6 +91,7 @@ def render_puzzle(puzzle_number):
|
||||||
if record is None:
|
if record is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
nav_numbers = get_nav_numbers(puzzle_numbers, puzzle_number)
|
||||||
if puzzle_number == 0:
|
if puzzle_number == 0:
|
||||||
categories = DEFAULT_CATEGORIES
|
categories = DEFAULT_CATEGORIES
|
||||||
author = DEFAULT_AUTHOR
|
author = DEFAULT_AUTHOR
|
||||||
|
|
@ -96,7 +106,7 @@ def render_puzzle(puzzle_number):
|
||||||
categories=categories,
|
categories=categories,
|
||||||
author=author,
|
author=author,
|
||||||
creation_date=creation_date,
|
creation_date=creation_date,
|
||||||
puzzle_numbers=puzzle_numbers,
|
nav_numbers=nav_numbers,
|
||||||
current_puzzle=puzzle_number,
|
current_puzzle=puzzle_number,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -108,15 +118,28 @@ def index():
|
||||||
def puzzle_by_number(puzzle_number):
|
def puzzle_by_number(puzzle_number):
|
||||||
return render_puzzle(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'])
|
@app.route('/new', methods=['GET', 'POST'])
|
||||||
def new_puzzle():
|
def new_puzzle():
|
||||||
with sqlite3.connect(config.db_file) as connection:
|
with sqlite3.connect(config.db_file) as connection:
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
puzzle_numbers = get_puzzle_numbers(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()
|
default_creation_date = today_display_date()
|
||||||
if request.method == 'GET':
|
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()
|
author = request.form.get("author", "").strip()
|
||||||
raw_creation_date = request.form.get("creation_date", "").strip() or default_creation_date
|
raw_creation_date = request.form.get("creation_date", "").strip() or default_creation_date
|
||||||
|
|
@ -136,7 +159,7 @@ def new_puzzle():
|
||||||
'new.html',
|
'new.html',
|
||||||
error="Author is required.",
|
error="Author is required.",
|
||||||
creation_date=raw_creation_date,
|
creation_date=raw_creation_date,
|
||||||
puzzle_numbers=puzzle_numbers,
|
nav_numbers=nav_numbers,
|
||||||
form=request.form
|
form=request.form
|
||||||
), 400
|
), 400
|
||||||
|
|
||||||
|
|
@ -145,7 +168,7 @@ def new_puzzle():
|
||||||
'new.html',
|
'new.html',
|
||||||
error='Creation date must be in the format "Day Month Year" (example: 15 March 2026).',
|
error='Creation date must be in the format "Day Month Year" (example: 15 March 2026).',
|
||||||
creation_date=raw_creation_date,
|
creation_date=raw_creation_date,
|
||||||
puzzle_numbers=puzzle_numbers,
|
nav_numbers=nav_numbers,
|
||||||
form=request.form
|
form=request.form
|
||||||
), 400
|
), 400
|
||||||
|
|
||||||
|
|
@ -154,7 +177,7 @@ def new_puzzle():
|
||||||
'new.html',
|
'new.html',
|
||||||
error="Each category needs a name and exactly 4 words.",
|
error="Each category needs a name and exactly 4 words.",
|
||||||
creation_date=raw_creation_date,
|
creation_date=raw_creation_date,
|
||||||
puzzle_numbers=puzzle_numbers,
|
nav_numbers=nav_numbers,
|
||||||
form=request.form
|
form=request.form
|
||||||
), 400
|
), 400
|
||||||
|
|
||||||
|
|
@ -174,7 +197,7 @@ def new_puzzle():
|
||||||
'new.html',
|
'new.html',
|
||||||
success=f"Saved puzzle #{number}.",
|
success=f"Saved puzzle #{number}.",
|
||||||
creation_date=creation_date,
|
creation_date=creation_date,
|
||||||
puzzle_numbers=puzzle_numbers + [number],
|
nav_numbers=get_nav_numbers(puzzle_numbers + [number], number),
|
||||||
)
|
)
|
||||||
|
|
||||||
@app.route('/delete', methods=['GET', 'POST'])
|
@app.route('/delete', methods=['GET', 'POST'])
|
||||||
|
|
@ -204,7 +227,7 @@ def delete_puzzle():
|
||||||
return render_template(
|
return render_template(
|
||||||
'delete.html',
|
'delete.html',
|
||||||
puzzles=puzzles,
|
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"),
|
deleted=request.args.get("deleted"),
|
||||||
error=request.args.get("error"),
|
error=request.args.get("error"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ button:disabled {
|
||||||
color: #2b7d32;
|
color: #2b7d32;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
margin-top: -8px;
|
margin-top: 0;
|
||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
|
|
@ -237,6 +237,34 @@ button:disabled {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-weight: bold;
|
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) {
|
@media (max-width: 640px) {
|
||||||
.meta-row {
|
.meta-row {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>All Connections Puzzles</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="header-links">
|
||||||
|
<a href="/all" class="active">all</a>
|
||||||
|
<a href="/0">0</a>
|
||||||
|
{% for number in nav_numbers %}
|
||||||
|
<a href="/{{ number }}">{{ number }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
<a href="/new">new</a>
|
||||||
|
<a href="/delete">delete</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<h1>Connections</h1>
|
||||||
|
<p class="subtitle">All Puzzles</p>
|
||||||
|
|
||||||
|
<div class="all-table-wrap">
|
||||||
|
<table class="all-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Puzzle Number</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Creation Date</th>
|
||||||
|
<th>Link</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for puzzle in puzzles %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ puzzle.number }}</td>
|
||||||
|
<td>{{ puzzle.author }}</td>
|
||||||
|
<td>{{ puzzle.creation_date }}</td>
|
||||||
|
<td><a class="ghost-link table-link-btn" href="/{{ puzzle.number }}">Open</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -10,8 +10,9 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="header-links">
|
<nav class="header-links">
|
||||||
|
<a href="/all">all</a>
|
||||||
<a href="/0">0</a>
|
<a href="/0">0</a>
|
||||||
{% for number in puzzle_numbers %}
|
{% for number in nav_numbers %}
|
||||||
<a href="/{{ number }}">{{ number }}</a>
|
<a href="/{{ number }}">{{ number }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<a href="/new">new</a>
|
<a href="/new">new</a>
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="header-links">
|
<nav class="header-links">
|
||||||
|
<a href="/all">all</a>
|
||||||
<a href="/0" class="{{ 'active' if current_puzzle == 0 else '' }}">0</a>
|
<a href="/0" class="{{ 'active' if current_puzzle == 0 else '' }}">0</a>
|
||||||
{% for number in puzzle_numbers %}
|
{% for number in nav_numbers %}
|
||||||
<a href="/{{ number }}" class="{{ 'active' if current_puzzle == number else '' }}">{{ number }}</a>
|
<a href="/{{ number }}" class="{{ 'active' if current_puzzle == number else '' }}">{{ number }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<a href="/new">new</a>
|
<a href="/new">new</a>
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="header-links">
|
<nav class="header-links">
|
||||||
|
<a href="/all">all</a>
|
||||||
<a href="/0">0</a>
|
<a href="/0">0</a>
|
||||||
{% for number in puzzle_numbers %}
|
{% for number in nav_numbers %}
|
||||||
<a href="/{{ number }}">{{ number }}</a>
|
<a href="/{{ number }}">{{ number }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<a href="/new" class="active">new</a>
|
<a href="/new" class="active">new</a>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue