connections/app/templates/index.html

116 lines
3.8 KiB
HTML
Executable File

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Connections, but better</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<nav class="header-links">
<a href="/">home</a>
<a href="/0" class="{{ 'active' if current_puzzle == 0 else '' }}">0</a>
{% for number in puzzle_numbers %}
<a href="/{{ number }}" class="{{ 'active' if current_puzzle == number else '' }}">{{ number }}</a>
{% endfor %}
<a href="/new">new</a>
<a href="/delete">delete</a>
</nav>
<h1>Connections</h1>
<div class="puzzle-meta">By {{ author }} | {{ creation_date }}</div>
<div id="grid"></div>
<div class="controls">
<button id="shuffleBtn">Shuffle</button>
<button id="deselectBtn">Deselect All</button>
<button id="submitBtn" disabled>Submit</button>
</div>
<div id="message"></div>
<script>
const categories = {{ categories | tojson }};
let words = categories.flatMap(cat => cat.items).sort(() => Math.random() - 0.5);
let selected = [];
let solvedCategories = [];
const grid = document.getElementById('grid');
const submitBtn = document.getElementById('submitBtn');
const message = document.getElementById('message');
function render() {
grid.innerHTML = '';
// 1. Render rows for already solved categories
solvedCategories.forEach(cat => {
const row = document.createElement('div');
row.className = 'card solved';
row.style.backgroundColor = `var(--lvl-${cat.level})`;
row.innerHTML = `<strong>${cat.name}</strong><div>${cat.items.join(', ')}</div>`;
grid.appendChild(row);
});
// 2. Render remaining active word cards
words.forEach(word => {
const card = document.createElement('div');
card.className = 'card' + (selected.includes(word) ? ' selected' : '');
card.textContent = word;
card.onclick = () => toggleSelect(word);
grid.appendChild(card);
});
submitBtn.disabled = selected.length !== 4;
}
function toggleSelect(word) {
if (selected.includes(word)) {
selected = selected.filter(w => w !== word);
} else if (selected.length < 4) {
selected.push(word);
}
render();
}
document.getElementById('deselectBtn').onclick = () => {
selected = [];
render();
};
document.getElementById('shuffleBtn').onclick = () => {
words.sort(() => Math.random() - 0.5);
render();
};
document.getElementById('submitBtn').onclick = () => {
const match = categories.find(cat =>
selected.every(word => cat.items.includes(word))
);
if (match) {
solvedCategories.push(match);
words = words.filter(w => !selected.includes(w));
selected = [];
if (solvedCategories.length === 4) {
message.style.color = "green";
message.textContent = "Perfect!";
}
} else {
message.textContent = "Not a set!";
setTimeout(() => message.textContent = "", 2000);
}
render();
};
words.sort(() => Math.random() - 0.5);
words.sort(() => Math.random() - 0.5);
words.sort(() => Math.random() - 0.5);
render();
</script>
</body>
</html>