From 66dd3c825e64d666d4df70dfec2c0c52c34e4619 Mon Sep 17 00:00:00 2001 From: Kuz Khrystyna Date: Wed, 18 Jun 2025 11:27:33 +0300 Subject: [PATCH 1/2] KhrKuz_lab4 --- index.html | 112 +++++++++++++++++++++ src/main.js | 15 +++ style/style.css | 255 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 382 insertions(+) diff --git a/index.html b/index.html index 09c6dc0..a691f31 100644 --- a/index.html +++ b/index.html @@ -8,6 +8,118 @@ +
+ +
+
+ + +
+ +
+
+
+
Яка ваша улюблена мова програмування?
+
+
JavaScript
+
+
+
+
45%
+
+
+
Python
+
+
+
+
45%
+
+
+
Java
+
+
+
+
45%
+
+
+
C++
+
+
+
+
3%
+
+
150 votes
+
+
+
Яку соціальну мережу ви використовуєте найбільше?
+
+
Facebook
+
+
+
+
35%
+
+
+
Twitter
+
+
+
+
25%
+
+
+
Instagram
+
+
+
+
30%
+
+
+
Linkedln
+
+
+
+
10%
+
+ +
180 votes
+
+
+
+ + + + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index e69de29..4ab5497 100644 --- a/src/main.js +++ b/src/main.js @@ -0,0 +1,15 @@ +document.getElementById('createPoll').addEventListener('click', () => { + document.getElementById('createPollModal').style.display = 'flex'; +}); + +document.querySelectorAll('.poll-container').forEach(container => { + container.addEventListener('click', () => { + document.getElementById('votePollModal').style.display = 'flex'; + }); +}); + +window.addEventListener('click', (e) => { + if (e.target.classList.contains('modal')) { + e.target.style.display = 'none'; + } +}); \ No newline at end of file diff --git a/style/style.css b/style/style.css index e69de29..c5241c4 100644 --- a/style/style.css +++ b/style/style.css @@ -0,0 +1,255 @@ +body { + font-family: sans-serif; + background: #d6dde1;; + color: #212121; + display: flex; + justify-content: center; + align-items: flex-start; + min-height: 100vh; +} + +.main { + display: flex; + flex-direction: column; + align-items: stretch; + width: 100%; + max-width: 900px; + padding: 20px; + margin-top: 40px; + box-sizing: border-box; + border-radius: 15px; + background-color: #f3f3f3; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.34); +} + +#createPoll { + width: 100%; + color: white; + border: none; + padding: 10px 20px; + margin-bottom: 20px; + font-size: 16px; + font-weight: bold; + cursor: pointer; + border-radius: 6px; + background-color: #3b82f6; + box-shadow: -1px -4px rgba(29, 14, 195, 0.278) inset; +} + +.search-category { + display: flex; + flex-direction: row; + gap: 10px; + margin-bottom: 20px; + width: 100%; +} + +.search-category input[type="text"], +.search-category select.category { + padding: 10px; + font-size: 14px; + border: 1px solid #d1d5db; + border-radius: 6px; + box-sizing: border-box; +} + +.search-category input[type="text"] { + flex: 2; +} + +.search-category select.category { + flex: 1; +} + +.search-wrapper { + position: relative; + flex: 2; + display: flex; +} + +.search-wrapper input[type="text"] { + width: 100%; + padding: 10px 0 10px 10px; + font-size: 14px; + border: 1px solid #d1d5db; + border-radius: 6px 0 0 6px; + box-sizing: border-box; + outline: none; +} + +.search-wrapper .search-button { + color: white; + border: 1px solid #3b82f6; + border-left: none; + padding: 10px 16px; + font-size: 14px; + font-weight: bold; + cursor: pointer; + border-radius: 0 6px 6px 0; + background-color: #3b82f6; + box-shadow: -1px -4px rgba(29, 14, 195, 0.247) inset; +} + +.polls { + display: flex; + flex-wrap: wrap; + gap: 20px; + width: 100%; + box-sizing: border-box; +} + +.poll-container { + flex: 1 1 300px; + min-width: 250px; + max-width: 100%; + box-sizing: border-box; + border: 1px solid #e5e7eb; + border-radius: 12px; + padding: 20px; + background-color: white; + box-shadow: 0 2px 2px rgba(0,0,0,0.05); +} + +.poll-container:hover { + transform: scale(1.02); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + background-color: #f9f9f9; +} + +@media (max-width: 400px) { + .polls { + flex-direction: column; + align-items: center; + } + .poll-container { + flex-basis: 100%; + min-width: 100%; + } + .modal-content { + padding: 1rem; + font-size: 15px; + width: 70%; + } + + .modal-content input[type="text"], + .modal-content button { + padding: 0.4rem; + font-size: 14px; + } +} + +.question { + font-weight: 600; + margin-bottom: 20px; + font-size: 16px; +} + +.option { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; + font-size: 14px; +} + +.option-main { + flex: 1; +} + +.option-bar-wrapper { + flex: 2; + margin-left: 10px; + background-color: #e5e7eb; + border-radius: 6px; + overflow: hidden; + height: 8px; + position: relative; + margin-right: 10px; +} + +.option-bar { + height: 100%; + background-color: #3b82f6; + transition: width 0.3s ease-in-out; +} + +.option-percent { + min-width: 30px; + text-align: right; + font-size: 14px; +} + +.votes { + text-align: right; + font-size: 13px; + color: #6b7280; + margin-top: 10px; +} + +.modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.6); + justify-content: center; + align-items: center; +} + +.modal-content { + background-color: #fff; + padding: 2rem; + border-radius: 8px; + width: 80%; + max-width: 400px; + position: relative; + font-size: 17px; +} + +.modal-content h2 { + margin-top: 0; + text-align: center; +} + +.modal-content p { + margin-bottom: 0; +} + +.modal-content input[type="text"], +.modal-content button { + width: 100%; + padding: 0.5rem; + margin: 0.3rem 0; + border-radius: 5px; + box-sizing: border-box; +} + +.modal-content input[type="text"] { + border: 1px solid #ccc; +} + +.modal-content a { + color: #1b50a4;; + text-decoration: none; + font-size: 0.9rem; +} + +.modal-content a:hover { + text-decoration: underline; +} + +.modal-content button { + background-color: #3b82f6; + color: white; + border: none; + padding: 0.6rem 1.2rem; + margin-top: 1rem; + border-radius: 5px; + cursor: pointer; +} + +.modal-content button:hover { + background-color: #3970ca; +} \ No newline at end of file From 87826b70db9b896e2562eafdd47b2b84f4978dae Mon Sep 17 00:00:00 2001 From: Kuz Khrystyna Date: Wed, 25 Jun 2025 10:15:52 +0300 Subject: [PATCH 2/2] KhrKuz_polls --- index.html | 46 ++++----- report.html | 24 +++++ src/main.js | 248 +++++++++++++++++++++++++++++++++++++++++++++++- src/polls.json | 76 +++++++++++++++ src/report.js | 40 ++++++++ style/style.css | 37 ++------ 6 files changed, 412 insertions(+), 59 deletions(-) create mode 100644 report.html create mode 100644 src/polls.json create mode 100644 src/report.js diff --git a/index.html b/index.html index a691f31..22deb23 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - Simple HTML Page + Polls @@ -11,17 +11,13 @@
-
- - -
+
-
+
Яка ваша улюблена мова програмування?
JavaScript
@@ -88,6 +84,7 @@
180 votes
+ Переглянути звіт
@@ -95,31 +92,28 @@
+ +
\ No newline at end of file diff --git a/report.html b/report.html new file mode 100644 index 0000000..97d8617 --- /dev/null +++ b/report.html @@ -0,0 +1,24 @@ + + + + + Звіт по опитуваннях + + + + + +

Звіт по опитуваннях

+
+ + + + diff --git a/src/main.js b/src/main.js index 4ab5497..1f0a244 100644 --- a/src/main.js +++ b/src/main.js @@ -1,10 +1,12 @@ document.getElementById('createPoll').addEventListener('click', () => { document.getElementById('createPollModal').style.display = 'flex'; -}); - -document.querySelectorAll('.poll-container').forEach(container => { - container.addEventListener('click', () => { - document.getElementById('votePollModal').style.display = 'flex'; + const baseOptions = document.querySelectorAll('.pollOption'); + baseOptions.forEach((input, index) => { + if (index < 4) { + input.value = ''; + } else { + input.remove(); + } }); }); @@ -12,4 +14,240 @@ window.addEventListener('click', (e) => { if (e.target.classList.contains('modal')) { e.target.style.display = 'none'; } +}); + + +// Завантаження опитування з json +fetch('./src/polls.json') + .then(response => response.json()) + .then(data => { + const pollsContainer = document.querySelector('.polls'); + pollsContainer.innerHTML = ''; + + const select = document.querySelector('.category'); + const uniqueCategories = new Set(); + + data.forEach(poll => { + const pollEl = document.createElement('div'); + pollEl.classList.add('poll-container'); + + if (poll.category) { + pollEl.setAttribute('data-category', poll.category); + uniqueCategories.add(poll.category); + } + + const questionHTML = `
${poll.question}
`; + + const optionsHTML = poll.options.map(opt => { + const votesCount = Math.round(poll.votes * (opt.percent / 100)); + return ` +
+
${opt.text}
+
+
+
+
${opt.percent}%
+
+ `; + }).join(''); + + const votesHTML = `
${poll.votes} votes
`; + + pollEl.innerHTML = questionHTML + optionsHTML + votesHTML; + + pollEl.addEventListener('click', () => openVoteModal(pollEl)); + + pollsContainer.appendChild(pollEl); + }); + + uniqueCategories.forEach(cat => { + const option = document.createElement('option'); + option.textContent = cat; + option.value = cat; + select.appendChild(option); + }); + }); + +// Створення нового опитування + document.getElementById('submitPoll').addEventListener('click', () => { + const question = document.getElementById('pollQuestion').value.trim(); + const category = document.getElementById('pollCategory').value.trim(); + + const options = Array.from(document.querySelectorAll('.pollOption')) + .map(input => input.value.trim()) + .filter(opt => opt !== ''); + + if (question === '' || options.length < 2) { + alert('Заповніть запитання та мінімум 2 варіанти!'); + return; + } + + const pollContainer = document.createElement('div'); + pollContainer.className = 'poll-container'; + pollContainer.setAttribute('data-category', category); + + const questionHTML = `
${question}
`; + + const optionsHTML = options.map(opt => ` +
+
${opt}
+
+
+
+
0%
+
+ `).join(''); + + const votesHTML = `
0 votes
`; + + pollContainer.innerHTML = questionHTML + optionsHTML + votesHTML; + + document.querySelector('.polls').prepend(pollContainer); + + document.getElementById('pollQuestion').value = ''; + document.getElementById('pollCategory').value = ''; + document.querySelectorAll('.pollOption').forEach(input => input.value = ''); + + document.getElementById('createPollModal').style.display = 'none'; + addCategoryOption(category); + pollContainer.addEventListener('click', () => openVoteModal(pollContainer)); +}); + +// Додавання нового варіанта до опитування +document.getElementById('addOption').addEventListener('click', (e) => { + e.preventDefault(); + + const optionInputs = document.querySelectorAll('.pollOption'); + + const newOptionNumber = optionInputs.length + 1; + + const newInput = document.createElement('input'); + newInput.type = 'text'; + newInput.className = 'pollOption'; + newInput.placeholder = `Варіант ${newOptionNumber}`; + + const addOptionLink = document.getElementById('addOption'); + addOptionLink.parentNode.insertBefore(newInput, addOptionLink); +}); + +// Пошук за категоріями +document.querySelector('.category').addEventListener('change', function () { + const selectedCategory = this.value; + const polls = document.querySelectorAll('.poll-container'); + + polls.forEach(poll => { + if (selectedCategory === 'Категорія' || poll.dataset.category === selectedCategory) { + poll.style.display = 'block'; + } else { + poll.style.display = 'none'; + } + }); +}); + +// Додавання нової категорії +function addCategoryOption(category) { + const select = document.querySelector('.category'); + const options = Array.from(select.options).map(opt => opt.value); + if (!options.includes(category)) { + const option = document.createElement('option'); + option.value = category; + option.textContent = category; + select.appendChild(option); + } +} + +let currentPoll = null; + +// Голосування — натиснути кнопку "Проголосувати" +document.querySelector('#votePollModal button').addEventListener('click', () => { + if (!currentPoll) return alert('Опитування не вибране.'); + + const selectedOption = document.querySelector('input[name="voteOption"]:checked'); + if (!selectedOption) { + alert('Будь ласка, виберіть варіант для голосування.'); + return; + } + + const optionIndex = Number(selectedOption.value); + const optionEls = currentPoll.querySelectorAll('.option'); + const votesEl = currentPoll.querySelector('.votes'); + + let totalVotesBefore = parseInt(votesEl.textContent) || 0; + if (totalVotesBefore === 0) { + optionEls.forEach(optEl => { + const percent = parseInt(optEl.querySelector('.option-percent').textContent) || 0; + const votes = Math.round((percent / 100) * 100); // груба оцінка + optEl.dataset.votes = votes; + }); + } + + const currentVotes = Number(optionEls[optionIndex].dataset.votes || 0); + optionEls[optionIndex].dataset.votes = currentVotes + 1; + + let totalVotes = 0; + optionEls.forEach(optEl => { + totalVotes += Number(optEl.dataset.votes); + }); + + optionEls.forEach(optEl => { + const votes = Number(optEl.dataset.votes); + const percent = Math.round((votes / totalVotes) * 100); + optEl.querySelector('.option-percent').textContent = percent + '%'; + optEl.querySelector('.option-bar').style.width = percent + '%'; + }); + + votesEl.textContent = totalVotes + ' votes'; + + document.getElementById('votePollModal').style.display = 'none'; +}); + +// Відкриття вікна для голосування +function openVoteModal(pollEl) { + currentPoll = pollEl; + + const questionText = pollEl.querySelector('.question').textContent; + document.getElementById('voteQuestion').textContent = questionText; + + const optionsContainer = document.getElementById('voteOptionsContainer'); + optionsContainer.innerHTML = ''; + + const optionElements = pollEl.querySelectorAll('.option-main'); + optionElements.forEach((optEl, idx) => { + const label = document.createElement('label'); + label.style.display = 'block'; + + const radio = document.createElement('input'); + radio.type = 'radio'; + radio.name = 'voteOption'; + radio.value = idx; + + label.appendChild(radio); + label.appendChild(document.createTextNode(' ' + optEl.textContent)); + + optionsContainer.appendChild(label); + }); + + document.getElementById('votePollModal').style.display = 'flex'; +} + +// Пошук опитувань за словами +document.getElementById('searchInput').addEventListener('input', function () { + const query = this.value.toLowerCase(); + const polls = document.querySelectorAll('.poll-container'); + + polls.forEach(poll => { + const question = poll.querySelector('.question').textContent.toLowerCase(); + + const options = Array.from(poll.querySelectorAll('.option-main')) + .map(opt => opt.textContent.toLowerCase()); + + const matchInQuestion = question.includes(query); + const matchInOptions = options.some(opt => opt.includes(query)); + + if (matchInQuestion || matchInOptions) { + poll.style.display = 'block'; + } else { + poll.style.display = 'none'; + } + }); }); \ No newline at end of file diff --git a/src/polls.json b/src/polls.json new file mode 100644 index 0000000..39e2ec5 --- /dev/null +++ b/src/polls.json @@ -0,0 +1,76 @@ +[ + { + "question": "Яка ваша улюблена мова програмування?", + "category": "Програмування", + "options": [ + { "text": "JavaScript", "percent": 40 }, + { "text": "Python", "percent": 30 }, + { "text": "Java", "percent": 20 }, + { "text": "C++", "percent": 10 } + ], + "votes": 150 + }, + { + "question": "Яку соціальну мережу ви використовуєте найбільше?", + "category": "Технології", + "options": [ + { "text": "Facebook", "percent": 35 }, + { "text": "Twitter", "percent": 25 }, + { "text": "Instagram", "percent": 30 }, + { "text": "LinkedIn", "percent": 10 } + ], + "votes": 180 + }, + { + "question": "Коли ви зазвичай починаєте готуватися до сесії?", + "category": "Навчання", + "options": [ + { "text": "Готуюсь весь семестр", "percent": 20 }, + { "text": "За тиждень", "percent": 30 }, + { "text": "У ніч перед екзаменом", "percent": 50 } + ], + "votes": 200 + }, + { + "question": "Що краще?", + "category": "Технології", + "options": [ + { "text": "iOS", "percent": 45 }, + { "text": "Android", "percent": 55 } + ], + "votes": 130 + }, + { + "question": "Чи дотримуєтесь ви здорового харчування?", + "category": "Здоровʼя", + "options": [ + { "text": "Так", "percent": 10 }, + { "text": "Частково", "percent": 40 }, + { "text": "Ні", "percent": 30 }, + { "text": "Я люблю піцу", "percent": 20 } + ], + "votes": 90 + }, + { + "question": "Чи пробували ви створювати власну гру?", + "category": "Програмування", + "options": [ + { "text": "Так", "percent": 30 }, + { "text": "Ні", "percent": 25 }, + { "text": "В процесі", "percent": 25 }, + { "text": "Планую", "percent": 20 } + ], + "votes": 140 + }, + { + "question": "Як часто ви чистите зуби?", + "category": "Здоровʼя", + "options": [ + { "text": "Двічі на день", "percent": 20 }, + { "text": "Один раз зранку", "percent": 35 }, + { "text": "Один раз ввечері", "percent": 30 }, + { "text": "Ніколи", "percent": 15 } + ], + "votes": 80 + } +] diff --git a/src/report.js b/src/report.js new file mode 100644 index 0000000..6a63c4a --- /dev/null +++ b/src/report.js @@ -0,0 +1,40 @@ +fetch('./src/polls.json') + .then(response => response.json()) + .then(data => { + const reportData = []; + + data.forEach(poll => { + poll.options.forEach(opt => { + reportData.push({ + "Питання": poll.question, + "Категорія": poll.category || "Без категорії", + "Варіант": opt.text, + "Відсоток": opt.percent, + "Голосів (приблизно)": Math.round(poll.votes * (opt.percent / 100)) + }); + }); + }); + + new WebDataRocks({ + container: "#wdr-component", + toolbar: true, + report: { + dataSource: { + data: reportData + }, + slice: { + rows: [ + { uniqueName: "Питання" }, + { uniqueName: "Варіант" } + ], + columns: [ + { uniqueName: "Категорія" } + ], + measures: [ + { uniqueName: "Відсоток", aggregation: "average" }, + { uniqueName: "Голосів (приблизно)", aggregation: "sum" } + ] + } + } + }); + }); diff --git a/style/style.css b/style/style.css index c5241c4..7cb7057 100644 --- a/style/style.css +++ b/style/style.css @@ -53,48 +53,24 @@ body { box-sizing: border-box; } -.search-category input[type="text"] { - flex: 2; -} - .search-category select.category { flex: 1; } -.search-wrapper { - position: relative; - flex: 2; - display: flex; -} - -.search-wrapper input[type="text"] { +#searchInput { width: 100%; padding: 10px 0 10px 10px; font-size: 14px; border: 1px solid #d1d5db; - border-radius: 6px 0 0 6px; + border-radius: 6px; box-sizing: border-box; outline: none; } -.search-wrapper .search-button { - color: white; - border: 1px solid #3b82f6; - border-left: none; - padding: 10px 16px; - font-size: 14px; - font-weight: bold; - cursor: pointer; - border-radius: 0 6px 6px 0; - background-color: #3b82f6; - box-shadow: -1px -4px rgba(29, 14, 195, 0.247) inset; -} - .polls { display: flex; flex-wrap: wrap; gap: 20px; - width: 100%; box-sizing: border-box; } @@ -130,7 +106,6 @@ body { font-size: 15px; width: 70%; } - .modal-content input[type="text"], .modal-content button { padding: 0.4rem; @@ -161,7 +136,6 @@ body { margin-left: 10px; background-color: #e5e7eb; border-radius: 6px; - overflow: hidden; height: 8px; position: relative; margin-right: 10px; @@ -224,6 +198,7 @@ body { margin: 0.3rem 0; border-radius: 5px; box-sizing: border-box; + font-size: 16px; } .modal-content input[type="text"] { @@ -252,4 +227,10 @@ body { .modal-content button:hover { background-color: #3970ca; +} + +.report-link { + margin-top: 20px; + color: #1b50a4; + font-size: 0.9rem; } \ No newline at end of file