115 lines
3.7 KiB
HTML
Executable File
115 lines
3.7 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="/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>
|