modified: app.py

modified:   templates/base.html.j2
	modified:   templates/daily_puzzle.html.j2
This commit is contained in:
Russell Ballestrini 2024-12-27 13:44:23 -05:00
parent e13b5ef5fa
commit bea0de1ecc
3 changed files with 80 additions and 41 deletions

10
app.py
View file

@ -708,8 +708,6 @@ def daily_puzzle_view(request):
user_id = user.id if user else None
display_name = user.username if (user and user.username) else guest_name
s = request.dbsession
# Check if user has already solved this puzzle
existing_solve = (
s.query(Attempt)
@ -788,19 +786,17 @@ def daily_puzzle_view(request):
user_rank = idx + 1
break
# Generate URLs for images
puzzle_image_url = request.route_url("puzzle_image", puzzle_id=puzzle.id)
return {
"request": request,
"puzzle": puzzle,
"attempt_state_json": attempt.state_json, # Now includes UUIDs
"attempt_state": json.loads(attempt.state_json),
"attempt_state_json": attempt.state_json,
"move_count": attempt.move_count,
"rotation_count": attempt.rotation_count,
"attempt_is_solved": attempt.is_solved or existing_solve is not None,
"puzzle_filename": puzzle_filename,
"user_rank": user_rank,
"puzzle_image_url": puzzle_image_url,
}

View file

@ -2,7 +2,7 @@
<html>
<head>
<title>{% block title %}My Puzzle Game{% endblock %}</title>
<link href="https://unpkg.com/@picocss/pico@1.*/css/pico.min.css" rel="stylesheet">
<!-- <link href="https://unpkg.com/@picocss/pico@1.*/css/pico.min.css" rel="stylesheet"> -->
<style>
/* Custom styles */
body { margin: 0; padding: 0; }

View file

@ -2,16 +2,19 @@
{% block content %}
{% if puzzle %}
<h1>{{ puzzle.title }}</h1>
<p>Date: {{ puzzle.date }}</p>
<p>
Moves: <span id="moveCount">{{ move_count }}</span><br>
Rotations: <span id="rotationCount">{{ rotation_count }}</span><br>
</p>
<div id="puzzle-page">
<div id="puzzle-stats">
<h1>{{ puzzle.title }}</h1>
<p>Date: {{ puzzle.date }}</p>
<p>
Moves: <span id="moveCount">{{ move_count }}</span><br>
Rotations: <span id="rotationCount">{{ rotation_count }}</span><br>
</p>
<button id="downloadButton" style="display:none;">Download Image</button>
</div>
<div id="puzzle-container"></div>
</div>
<div id="puzzle-container"></div>
<button id="downloadButton" style="display:none;">Download Image</button>
<!-- Win Modal -->
<div id="winModal" class="modal">
@ -30,29 +33,67 @@
<!-- Styles -->
<style>
/* Puzzle page layout */
#puzzle-page {
display: grid;
grid-template-columns: 1fr;
grid-gap: 20px;
max-width: 960;
margin: 20px auto;
}
@media screen and (min-width: 768px) {
#puzzle-page {
grid-template-columns: 1fr 2fr; /* Two columns */
align-items: start;
}
}
/* Puzzle stats styles */
#puzzle-stats {
text-align: center;
}
@media screen and (min-width: 768px) {
#puzzle-stats {
text-align: left;
}
}
/* Puzzle container styles */
#puzzle-container {
position: relative;
width: 100%;
max-width: 400px;
margin: 0 auto;
padding-bottom: 100%; /* Maintain square aspect ratio */
max-width: 640px;
min-width: 300px;
aspect-ratio: 1 / 1; /* Maintain square aspect ratio */
border: 1px solid #ccc;
background-color: #eee;
margin: 0 auto;
}
/* Puzzle piece styles */
.puzzle-piece {
position: absolute;
background-image: url('{{ puzzle_image_url }}');
background-size: {{ puzzle.size * 100 }}%;
background-image: url('data:image/png;base64,{{ puzzle.image_b64 }}');
background-size: {{ puzzle.size * 100 }}% {{ puzzle.size * 100 }}%;
background-repeat: no-repeat;
cursor: pointer;
box-sizing: border-box;
margin: 0;
padding: 0;
}
.puzzle-piece.selected {
outline: 2px solid red;
/* Confetti styles */
.confetti {
position: fixed;
width: 10px;
height: 10px;
top: 0;
animation: confetti-fall 3s linear infinite;
}
/* Modal styles */
.modal {
display: none; /* Hidden by default */
position: fixed;
@ -88,24 +129,18 @@
color: black;
}
.confetti {
position: fixed;
width: 10px;
height: 10px;
top: 0;
animation: confetti-fall 3s linear infinite;
}
/* Confetti animation */
@keyframes confetti-fall {
0% {transform: translateY(0);}
100% {transform: translateY(100vh);}
0% { transform: translateY(0); }
100% { transform: translateY(100vh); }
}
</style>
<!-- Scripts -->
<script>
// Ensure the script runs after the DOM is fully loaded
document.addEventListener("DOMContentLoaded", function() {
let pieces = {{ attempt_state_json | safe }};
let pieces = {{ attempt_state | tojson }};
const gridSize = {{ puzzle.size }};
let isSolved = {{ 'true' if attempt_is_solved else 'false' }};
let moveCount = {{ move_count }};
@ -129,6 +164,9 @@ document.addEventListener("DOMContentLoaded", function() {
function initBoard() {
puzzleContainer.innerHTML = '';
// Calculate the size of each piece in percentage
const pieceSizePercent = 100 / gridSize;
// Build the board
pieces.forEach(piece => {
const pieceElement = document.createElement("div");
@ -137,11 +175,11 @@ document.addEventListener("DOMContentLoaded", function() {
pieceElement.dataset.currentIndex = piece.currentIndex;
pieceElement.dataset.rotation = piece.rotation;
// Set size and position
const pieceSizePercent = 100 / gridSize;
// Set size of the piece
pieceElement.style.width = `${pieceSizePercent}%`;
pieceElement.style.height = `${pieceSizePercent}%`;
// Position the piece
const currentRow = Math.floor(piece.currentIndex / gridSize);
const currentCol = piece.currentIndex % gridSize;
pieceElement.style.left = `${currentCol * pieceSizePercent}%`;
@ -150,7 +188,12 @@ document.addEventListener("DOMContentLoaded", function() {
// Set background position
const correctRow = Math.floor(piece.correctIndex / gridSize);
const correctCol = piece.correctIndex % gridSize;
pieceElement.style.backgroundPosition = `${-correctCol * pieceSizePercent}% ${-correctRow * pieceSizePercent}%`;
const backgroundPositionX = (correctCol / (gridSize - 1)) * 100;
const backgroundPositionY = (correctRow / (gridSize - 1)) * 100;
pieceElement.style.backgroundPosition = `${backgroundPositionX}% ${backgroundPositionY}%`;
// Set background size
pieceElement.style.backgroundSize = `${gridSize * 100}% ${gridSize * 100}%`;
// Set rotation
pieceElement.style.transform = `rotate(${piece.rotation}deg)`;
@ -275,7 +318,7 @@ document.addEventListener("DOMContentLoaded", function() {
pieces.forEach(piece => {
piece.draggable = false;
piece.removeEventListener("click", rotatePiece);
// Optionally, reset rotation and position
// Reset rotation for solved puzzle display
piece.style.transform = 'rotate(0deg)';
});
downloadButton.style.display = "block";
@ -320,8 +363,8 @@ document.addEventListener("DOMContentLoaded", function() {
// Download button functionality
function downloadImage() {
const link = document.createElement('a');
link.href = "{{ puzzle_image_url }}";
link.download = "{{ puzzle_filename }}";
link.href = 'data:image/png;base64,{{ puzzle.image_b64 }}';
link.download = "{{ puzzle.filename }}";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);