2026-03-05 19:57:20 +00:00

436 lines
19 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const quizData = [
{
question: "Столица Беларуси — это…",
options: ["Гродно", "Минск", "Витебск", "Гомель"],
answer: 1,
fact: "Минск — самый большой город страны и её главный культурный центр.",
facts: [
"Минск впервые упоминается в летописях в 1067 году.",
"В городе находится Национальная библиотека с необычной формой ромбокубооктаэдра.",
"В Минске более 2 миллионов жителей — это крупнейший город Беларуси."
],
imagePath: "assets/pasted-20260305-185724-631e7f99.webp",
imageAlt: "Панорама Минска"
},
{
question: "Какие цвета есть на флаге Беларуси?",
options: ["Синий и жёлтый", "Белый и красный", "Красный и зелёный", "Белый и зелёный"],
answer: 2,
fact: "Красный и зелёный — основные цвета флага, а сбоку есть орнамент.",
facts: [
"Красный цвет на флаге символизирует мужество и историческую память.",
"Зелёный цвет связан с природой, лесами и полями страны.",
"Белорусский орнамент на флаге основан на традиционном народном узоре."
],
imagePath: "assets/images/quiz/q02-flag.jpg",
imageAlt: "Флаг Беларуси"
},
{
question: "Самое большое озеро Беларуси называется…",
options: ["Нарочь", "Свитязь", "Дривяты", "Кромань"],
answer: 0,
fact: "Озеро Нарочь — любимое место отдыха и часть Нарачанского парка.",
facts: [
"Площадь озера Нарочь — около 80 км², это крупнейшее озеро Беларуси.",
"Озеро входит в территорию Национального парка «Нарочанский».",
"Нарочь известна чистой водой и популярна для летнего отдыха."
],
imagePath: "assets/pasted-20260305-185926-dd9a5c42.webp",
imageAlt: "Озеро в Беларуси"
},
{
question: "Национальный символ животного Беларуси — это…",
options: ["Зубр", "Лось", "Медведь", "Лиса"],
answer: 0,
fact: "Зубр — редкое и сильное животное, живёт в Беловежской пуще.",
facts: [
"Зубр — самое тяжёлое наземное животное Европы.",
"После почти полного исчезновения популяцию зубров удалось восстановить.",
"В Беловежской пуще находится одна из самых известных популяций зубра."
],
imagePath: "assets/pasted-20260305-193021-7ef32b53.jpg",
imageAlt: "Зубр"
},
{
question: "Как называется главный заповедник Беларуси?",
options: ["Беловежская пуща", "Березинский парк", "Браславские озёра", "Припятский парк"],
answer: 0,
fact: "Беловежская пуща — старинный лес, который охраняется ЮНЕСКО.",
facts: [
"Беловежская пуща — один из самых древних лесов Европы.",
"Часть территории заповедника внесена в список Всемирного наследия ЮНЕСКО.",
"В пуще можно увидеть зубров, оленей и редкие виды птиц."
],
imagePath: "assets/pasted-20260305-190111-63cd8baa.jpg",
imageAlt: "Лес Беловежской пущи"
},
{
question: "Какой город называют «северной столицей» Беларуси?",
options: ["Витебск", "Гомель", "Брест", "Полоцк"],
answer: 0,
fact: "Витебск — родина художника Марка Шагала.",
facts: [
"В Витебске ежегодно проходит международный фестиваль «Славянский базар».",
"Город связан с именем художника Марка Шагала.",
"Витебск стоит на реке Западная Двина и имеет богатую историю."
],
imagePath: "assets/images/quiz/q06-vitebsk.jpg",
imageAlt: "Город Витебск"
},
{
question: "Как называется белорусский струнный ударный музыкальный инструмент?",
options: ["Цимбалы", "Скрипка", "Дудка", "Сопилка"],
answer: 0,
fact: "Цимбалы — это инструмент со струнами, по которым играют маленькими молоточками.",
facts: [
"Цимбалы похожи на большую деревянную трапецию со струнами.",
"По струнам ударяют двумя маленькими молоточками, и получается звонкий звук.",
"Цимбалы часто звучат в белорусской народной музыке."
],
imagePath: "assets/pasted-20260305-190344-ec46e879.jpg",
imageAlt: "Традиционный музыкальный инструмент"
},
{
question: "Какой замок стоит в городе Мир?",
options: ["Мирский замок", "Несвижский замок", "Лидский замок", "Гродненский замок"],
answer: 0,
fact: "Мирский замок — объект Всемирного наследия ЮНЕСКО.",
facts: [
"Мирский замок начали строить в начале XVI века.",
"Замок сочетает элементы готики, ренессанса и барокко.",
"Комплекс Мирского замка входит в список Всемирного наследия ЮНЕСКО."
],
imagePath: "assets/pasted-20260305-193451-5d1a5abc.jpg",
imageAlt: "Мирский замок"
},
{
question: "Главная река Беларуси — это…",
options: ["Западная Двина", "Днепр", "Нёман", "Припять"],
answer: 1,
fact: "Днепр проходит через южные регионы страны и впадает в Чёрное море.",
facts: [
"Днепр — одна из крупнейших рек Европы.",
"Река протекает через Беларусь, Россию и Украину.",
"В Беларуси Днепр важен для судоходства и водоснабжения."
],
imagePath: "assets/pasted-20260305-190627-76b2a1c1.jpg",
imageAlt: "Река Днепр"
},
{
question: "Как называется традиционный белорусский узор на ткани?",
options: ["Орнамент", "Гжель", "Петриковская роспись", "Хохлома"],
answer: 0,
fact: "Белорусский орнамент часто украшает флаг и народные костюмы.",
facts: [
"Орнамент передавался из поколения в поколение в народной вышивке.",
"В узорах часто встречаются ромбы, кресты и растительные элементы.",
"Белорусский орнамент используется в национальной символике и сувенирах."
],
imagePath: "assets/pasted-20260305-190855-a269e4b8.png",
imageAlt: "Белорусский орнамент"
},
{
question: "Самый древний город Беларуси — это…",
options: ["Полоцк", "Минск", "Брест", "Могилёв"],
answer: 0,
fact: "Полоцк впервые упоминается в летописях в 862 году.",
facts: [
"Полоцк — один из старейших городов восточных славян, известен с 862 года.",
"В городе находится Софийский собор — важный исторический памятник.",
"Полоцк был крупным культурным и торговым центром в Средние века."
],
imagePath: "assets/pasted-20260305-193618-2a0dd0c5.jpg",
imageAlt: "Город Полоцк"
},
{
question: "Как называется сладость из мёда и орехов, популярная в Беларуси?",
options: ["Пастила", "Печенье", "Козинаки", "Зефир"],
answer: 2,
fact: "Козинаки часто готовят из мёда и орехов.",
facts: [
"Козинаки делают из орехов или семечек, скреплённых мёдом или сиропом.",
"Эта сладость получается хрустящей и очень питательной.",
"Козинаки часто подают к чаю как традиционное лакомство."
],
imagePath: "assets/pasted-20260305-191522-fbd0d85f.jpg",
imageAlt: "Козинаки"
}
];
const startBtn = document.getElementById("startQuizBtn");
const quizSection = document.getElementById("quiz");
const summarySection = document.getElementById("summary");
const progressEl = document.getElementById("questionProgress");
const progressLabel = document.getElementById("progressLabel");
const progressFill = document.getElementById("progressFill");
const questionText = document.getElementById("questionText");
const optionList = document.getElementById("optionList");
const totalQuestions = document.getElementById("totalQuestions");
const classScore = document.getElementById("classScore");
const revealBtn = document.getElementById("revealBtn");
const nextBtn = document.getElementById("nextBtn");
const answerArea = document.getElementById("answerArea");
const answerImageTrigger = document.getElementById("answerImageTrigger");
const answerImage = document.getElementById("answerImage");
const correctAnswer = document.getElementById("correctAnswer");
const factList = document.getElementById("factList");
const answerResult = document.getElementById("answerResult");
const finalScore = document.getElementById("finalScore");
const summaryList = document.getElementById("summaryList");
const restartBtn = document.getElementById("restartBtn");
const imageLightbox = document.getElementById("imageLightbox");
const lightboxImage = document.getElementById("lightboxImage");
const closeImageLightbox = document.getElementById("closeImageLightbox");
const state = {
index: 0,
score: 0,
revealed: false,
selectedOption: null,
locked: false,
lastAnswerCorrect: false,
optionOrders: []
};
totalQuestions.textContent = quizData.length.toString();
function updateProgressBar() {
const completed = state.index + (state.revealed ? 1 : 0);
const percent = Math.max(0, Math.min(100, Math.round((completed / quizData.length) * 100)));
progressLabel.textContent = `${completed} из ${quizData.length}`;
progressFill.style.width = `${percent}%`;
progressFill.parentElement?.setAttribute("aria-valuenow", String(percent));
}
function shuffleArray(items) {
const arr = items.slice();
for (let i = arr.length - 1; i > 0; i -= 1) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
function buildOptionOrders() {
return quizData.map((item) => shuffleArray(item.options.map((_, idx) => idx)));
}
function renderQuestion() {
const current = quizData[state.index];
const currentOrder = state.optionOrders[state.index] || current.options.map((_, idx) => idx);
progressEl.textContent = `Вопрос ${state.index + 1} из ${quizData.length}`;
updateProgressBar();
questionText.textContent = current.question;
optionList.innerHTML = "";
optionList.classList.toggle("d-none", state.revealed);
optionList.setAttribute("aria-hidden", state.revealed ? "true" : "false");
currentOrder.forEach((originalIdx, displayIdx) => {
const option = current.options[originalIdx];
const li = document.createElement("li");
li.className = "option-item";
li.setAttribute("role", "button");
li.setAttribute("tabindex", "0");
li.dataset.index = String(originalIdx);
if (originalIdx === state.selectedOption) {
li.classList.add("option-item-selected");
}
if (state.revealed) {
if (originalIdx === current.answer) {
li.classList.add("option-item-correct");
} else if (originalIdx === state.selectedOption) {
li.classList.add("option-item-wrong");
}
}
li.innerHTML = `<span class="option-index">${String.fromCharCode(65 + displayIdx)}</span><span>${option}</span>`;
optionList.appendChild(li);
});
classScore.textContent = state.score.toString();
answerArea.classList.add("d-none");
answerResult.classList.remove("text-success", "text-danger");
nextBtn.classList.add("d-none");
}
function renderAnswer() {
const current = quizData[state.index];
answerImage.src = current.imagePath;
answerImage.alt = current.imageAlt;
correctAnswer.textContent = current.options[current.answer];
factList.innerHTML = "";
const facts = Array.isArray(current.facts) && current.facts.length ? current.facts.slice(0, 4) : [current.fact];
facts.forEach((fact) => {
const li = document.createElement("li");
li.textContent = fact;
factList.appendChild(li);
});
const isCorrect = state.selectedOption === current.answer;
answerResult.textContent = isCorrect ? "Верно!" : "Неверно. Правильный ответ показан выше.";
answerResult.classList.toggle("text-success", isCorrect);
answerResult.classList.toggle("text-danger", !isCorrect);
answerArea.classList.remove("d-none");
}
function showSummary() {
quizSection.classList.add("d-none");
summarySection.classList.remove("d-none");
finalScore.textContent = `${state.score} из ${quizData.length}`;
summaryList.innerHTML = "";
quizData.forEach((item, idx) => {
const div = document.createElement("div");
div.className = "summary-item";
div.innerHTML = `
<img src="${item.imagePath}" alt="${item.imageAlt}" class="summary-image" loading="lazy" width="420" height="220">
<p class="fw-semibold mb-1">Вопрос ${idx + 1}: ${item.question}</p>
<p class="text-muted mb-1">Правильный ответ: ${item.options[item.answer]}</p>
<p class="text-muted mb-0">${item.fact}</p>
`;
summaryList.appendChild(div);
});
}
startBtn.addEventListener("click", () => {
document.body.classList.add("quiz-live");
quizSection.classList.remove("d-none");
summarySection.classList.add("d-none");
state.index = 0;
state.score = 0;
state.revealed = false;
state.selectedOption = null;
state.locked = false;
state.lastAnswerCorrect = false;
state.optionOrders = buildOptionOrders();
renderQuestion();
quizSection.scrollIntoView({ behavior: "smooth" });
});
function goToNextQuestion() {
if (state.index < quizData.length - 1) {
state.index += 1;
state.revealed = false;
state.selectedOption = null;
state.locked = false;
state.lastAnswerCorrect = false;
renderQuestion();
} else {
showSummary();
summarySection.scrollIntoView({ behavior: "smooth" });
}
}
restartBtn.addEventListener("click", () => {
state.index = 0;
state.score = 0;
state.revealed = false;
state.selectedOption = null;
state.locked = false;
state.lastAnswerCorrect = false;
state.optionOrders = buildOptionOrders();
summarySection.classList.add("d-none");
quizSection.classList.remove("d-none");
renderQuestion();
quizSection.scrollIntoView({ behavior: "smooth" });
});
function playCorrectClickEffect() {
const selectedEl = optionList.querySelector(`.option-item[data-index="${state.selectedOption}"]`);
if (!selectedEl) return;
selectedEl.classList.remove("option-item-correct-pop");
void selectedEl.offsetWidth;
selectedEl.classList.add("option-item-correct-pop");
const rect = selectedEl.getBoundingClientRect();
const burstCount = 28;
const colors = ["#f59e0b", "#f97316", "#fb7185", "#22c55e", "#facc15"];
for (let i = 0; i < burstCount; i += 1) {
const spark = document.createElement("span");
spark.className = "correct-spark";
spark.style.left = `${rect.left + rect.width / 2}px`;
spark.style.top = `${rect.top + rect.height / 2}px`;
spark.style.background = colors[i % colors.length];
const angle = ((Math.PI * 2) / burstCount) * i + (Math.random() * 0.3 - 0.15);
const distance = 88 + Math.random() * 148;
const size = 12 + Math.random() * 18;
spark.style.setProperty("--dx", `${Math.cos(angle) * distance}px`);
spark.style.setProperty("--dy", `${Math.sin(angle) * distance}px`);
spark.style.setProperty("--rot", `${Math.random() * 280 - 140}deg`);
spark.style.setProperty("--size", `${size}px`);
document.body.appendChild(spark);
setTimeout(() => spark.remove(), 1250);
}
}
function closeLightbox() {
imageLightbox.classList.add("d-none");
document.body.classList.remove("lightbox-open");
}
answerImageTrigger.addEventListener("click", () => {
if (!answerImage.src) return;
lightboxImage.src = answerImage.src;
lightboxImage.alt = answerImage.alt;
imageLightbox.classList.remove("d-none");
document.body.classList.add("lightbox-open");
});
closeImageLightbox.addEventListener("click", closeLightbox);
imageLightbox.addEventListener("click", (event) => {
if (event.target === imageLightbox) {
closeLightbox();
}
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && !imageLightbox.classList.contains("d-none")) {
closeLightbox();
}
});
function selectOption(index) {
if (state.revealed || state.locked) return;
const current = quizData[state.index];
state.selectedOption = index;
state.lastAnswerCorrect = state.selectedOption === current.answer;
if (state.lastAnswerCorrect) {
playCorrectClickEffect();
state.score += 1;
}
state.revealed = true;
state.locked = true;
renderQuestion();
renderAnswer();
nextBtn.classList.remove("d-none");
}
optionList.addEventListener("click", (event) => {
const option = event.target.closest(".option-item");
if (!option) return;
selectOption(Number(option.dataset.index));
});
optionList.addEventListener("keydown", (event) => {
if (event.key !== "Enter" && event.key !== " ") return;
const option = event.target.closest(".option-item");
if (!option) return;
event.preventDefault();
selectOption(Number(option.dataset.index));
});
nextBtn.addEventListener("click", () => {
if (!state.revealed) return;
goToNextQuestion();
});