From a301ddf4cb5ee1e7025d36ec61bcce6e2b854fe5 Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 18 Jun 2025 09:57:28 +0300 Subject: [PATCH 1/3] last version --- index.html | 141 ++++++++- src/main.js | 100 +++++++ style/style.css | 781 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1020 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 09c6dc0..3f6d285 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,150 @@ + - Simple HTML Page + Опитування - + +
+ +
+ +
+ + +
+
+ + +
+
    +
  • +
    Яка ваша улюблена мова програмування?
    +
    +
      +
    • + +
      + +
      + 30% +
    • +
    • + +
      + +
      + 50% +
    • +
    • + +
      + +
      + 15% +
    • +
    • + +
      + +
      + 5% +
    • +
    +
    + 150 votes +
  • + +
  • +
    Якою соціальною мережею ви користуєтесь частіше над усе?
    +
    +
      +
    • + +
      + +
      + 30% +
    • +
    • + +
      + +
      + 50% +
    • +
    • + +
      + +
      + 15% +
    • +
    • + +
      + +
      + 5% +
    • +
    +
    + 180 votes +
  • +
+
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+ +
+
+ +
+ \ No newline at end of file diff --git a/src/main.js b/src/main.js index e69de29..3218cf7 100644 --- a/src/main.js +++ b/src/main.js @@ -0,0 +1,100 @@ +const storeOriginalPollContent = () => { + const polls = document.querySelectorAll('.poll-container'); + polls.forEach(poll => { + poll.dataset.originalContent = poll.innerHTML; + }); + }; + + const convertToRadioView = (poll) => { + const title = poll.querySelector('.poll-title').textContent; + const options = poll.querySelectorAll('.options-results-row label'); + + let radioHTML = ` +
${title}
+
+ `; + + options.forEach((option, index) => { + radioHTML += ` +
+ + +
+ `; + }); + + poll.innerHTML = radioHTML; + poll.classList.remove('stats-view'); + poll.classList.add('radio-view'); + }; + + const convertToStatsView = (poll) => { + poll.innerHTML = poll.dataset.originalContent; + poll.classList.remove('radio-view'); + poll.classList.add('stats-view'); + }; + + const togglePollView = (poll) => { + if (poll.classList.contains('stats-view')) { + convertToRadioView(poll); + } else { + convertToStatsView(poll); + } + }; + + const openPollCreator = document.getElementById('open-poll-creator'); + const pollCreator = document.querySelector('.poll-creator'); + const content = document.querySelector('.content-container'); + const closeBtn = document.querySelector('.close-btn'); + const createNewPoll = document.getElementById('create-new-poll'); + const pollContainers = document.querySelectorAll('.poll-container'); + + document.addEventListener('DOMContentLoaded', () => { + storeOriginalPollContent(); + }); + + openPollCreator.addEventListener('click', () => { + pollCreator.classList.toggle('appear'); + content.classList.toggle('disappear'); + }); + + closeBtn.addEventListener('click', () => { + pollCreator.classList.remove('appear'); + content.classList.remove('disappear'); + }); + + createNewPoll.addEventListener('click', () => { + pollCreator.classList.remove('appear'); + content.classList.remove('disappear'); + }); + + pollCreator.addEventListener('click', (event) => { + if (event.target === pollCreator) { + pollCreator.classList.remove('appear'); + content.classList.remove('disappear'); + } + }); + + pollContainers.forEach((poll) => { + poll.addEventListener('click', (event) => { + if (event.target.tagName === 'INPUT' || event.target.tagName === 'LABEL') { + return; + } + + pollContainers.forEach((anotherPoll) => { + if (anotherPoll !== poll) { + anotherPoll.classList.toggle('disappear'); + anotherPoll.classList.add('slowly'); + } + }); + + poll.classList.toggle('big'); + + const pollUpper = document.querySelector('.create-poll-container'); + pollUpper.classList.toggle('disappear'); + + poll.classList.remove('slowly'); + + togglePollView(poll); + }); + }); \ No newline at end of file diff --git a/style/style.css b/style/style.css index e69de29..92bd08c 100644 --- a/style/style.css +++ b/style/style.css @@ -0,0 +1,781 @@ +:root { + --main-color: white; + --secondary-color: #4277d7; + --additional-color: #dbe3ea; + --border-radius: 5px; + --margin-percentage: 2%; + --padding-percentage: 3% 3%; + --shadow: 0.5vw 0.5vw 1vw var(--additional-color); +} + +* { + box-sizing: border-box; + font-size: large; + font-family: Verdana, Geneva, Tahoma, sans-serif; + margin: 0; + padding: 0; +} + +body { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + min-height: 100vh; + background-color: #f5f7fa; + padding: 20px; +} + +.content-container { + width: 100%; + max-width: 800px; + opacity: 1; + transition: opacity 1s ease-in-out; +} + +.create-poll-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + opacity: 1; + transition: opacity 1s ease-in-out; + margin-bottom: 20px; +} + +.create-poll-container #open-poll-creator { + padding: 12px 20px; + border-radius: var(--border-radius); + border: none; + background-color: var(--secondary-color); + color: white; + font-size: 1.1em; + width: 100%; + font-weight: bold; + margin-bottom: 15px; + cursor: pointer; +} + +.create-poll-container #open-poll-creator:hover { + background-color: #3566c5; + box-shadow: 0 4px 8px rgba(66, 119, 215, 0.4); +} + +.create-poll-container .category-container { + width: 100%; + display: flex; + gap: 15px; +} + +/* + Poll-creator animation + */ + + + +.category-container input, +.category-container select { + padding: 12px; + border: 1px solid var(--additional-color); + border-radius: var(--border-radius); + font-size: 1rem; +} + +.category-container input { + flex: 1; +} + +.category-container select { + width: 25%; +} + +.poll-list { + width: 100%; +} + +.poll-list ul { + display: flex; + flex-direction: column; + gap: 20px; +} + +.poll-container { + outline: thin solid var(--additional-color); + display: flex; + flex-direction: column; + padding: 20px; + border-radius: var(--border-radius); + box-shadow: var(--shadow); + background-color: var(--main-color); + cursor: pointer; + transition: all 0.3s; +} + +.poll-container:hover { + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); +} + +.poll-container.big { + transform: scale(1.05); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15); + z-index: 10; +} + +.poll-title { + font-size: 1.3em; + margin-bottom: 15px; + font-weight: 600; + color: #2c3e50; +} + +.options-results { + margin-bottom: 15px; +} + +/* Statistics view styles */ +.stats-view .options-results-row { + display: grid; + grid-template-columns: 30% 1fr auto; + gap: 15px; + align-items: center; + margin-bottom: 10px; +} + +.stats-view label { + font-weight: 500; +} + +.slidecontainer { + width: 100%; +} + +.slider { + width: 100%; + height: 10px; + border-radius: 5px; + background: #e0e7ff; + outline: none; +} + +.slider::-webkit-slider-thumb { + -webkit-appearance: none; + opacity: 0; + pointer-events: none; + width: 18px; + height: 18px; + border-radius: 50%; + background: var(--secondary-color); + cursor: pointer; +} + +.percent { + min-width: 50px; + text-align: right; +} + +/* Radio view styles */ +.radio-view .options-results { + display: flex; + flex-direction: column; + gap: 12px; +} + +.radio-view .option-row { + display: flex; + align-items: center; + padding: 12px; + border: 1px solid var(--additional-color); + border-radius: var(--border-radius); + transition: all 0.3s; + background: none; +} + +.radio-view .option-row:hover { + background: #eef5ff; + border-color: #a3c0ff; +} + +.radio-view .option-row input[type="radio"] { + margin-right: 12px; + width: 18px; + height: 18px; + cursor: pointer; + outline: none; + border: none; +} + +.radio-view .option-row label { + flex: 1; + cursor: pointer; +} + +.votes-quantity { + align-self: flex-end; + font-size: 0.9em; + color: #7f8c8d; +} + +.poll-creator { + background-color: var(--main-color); + width: 100%; + max-width: 600px; + border: 1px solid var(--additional-color); + border-radius: var(--border-radius); + padding: 25px; + flex-direction: column; + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); + position: fixed; + transform: translateY(200%); + transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1), opacity 0s 2s; + z-index: 1000; + opacity: 0; +} + +.poll-creator.appear { + display: flex; + transform: translateY(0%); + transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1); + opacity: 1; +} + +.poll-creator .poll-creator-container { + width: 100%; + margin-bottom: 20px; +} + +.poll-creator .question-input-container, +.poll-creator .category-selector-container { + margin-bottom: 15px; +} + +.poll-creator label.text { + display: block; + margin-bottom: 8px; + font-weight: 600; +} + +.poll-creator input, +.poll-creator select { + width: 100%; + padding: 12px; + border: 1px solid var(--additional-color); + border-radius: var(--border-radius); + font-size: 1rem; +} + +.options-input-container { + width: 100%; + margin-bottom: 20px; +} + +.options-input-container ul { + display: flex; + flex-direction: column; + gap: 15px; +} + +.options-input-container li.option { + display: flex; +} + +.options-input-container li.option input { + flex: 1; +} + +#add-new-option { + align-self: flex-start; + border: none; + background: none; + color: var(--secondary-color); + padding: 10px 0; + font-weight: bold; + cursor: pointer; +} + +#create-new-poll { + border-radius: var(--border-radius); + background-color: var(--secondary-color); + color: white; + border: none; + font-size: 1em; + font-weight: bold; + padding: 12px; + width: 100%; + cursor: pointer; + transition: all 0.3s; +} + +#create-new-poll:hover { + background-color: #3566c5; +} + +.slowly { + opacity: 1; + transition: opacity 0.5s ease-in-out; +} + +.disappear { + opacity: 0; + transition: opacity 0.5s ease-in-out, transform 0s 0.5s; + transform: translateX(250%); +} + +.close-btn { + position: absolute; + top: 15px; + right: 15px; + width: 30px; + height: 30px; + cursor: pointer; + background: #f1f3f9; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +.close-btn::before, +.close-btn::after { + content: ''; + position: absolute; + width: 15px; + height: 2px; + background: #7f8c8d; +} + +.close-btn::before { + transform: rotate(45deg); +} + +.close-btn::after { + transform: rotate(-45deg); +} + +@media (max-width: 768px) { + .create-poll-container .category-container { + flex-direction: column; + } + + .category-container select { + width: 100%; + } + + .poll-container { + padding: 15px; + } + + .poll-title { + font-size: 1.1em; + } + + .stats-view .options-results-row { + grid-template-columns: 25% 1fr auto; + gap: 10px; + } +} + +@media (max-width: 480px) { + body { + padding: 15px; + } + + .poll-container { + padding: 12px; + } + + .stats-view .options-results-row { + grid-template-columns: 1fr; + gap: 8px; + } + + .slidecontainer, + .percent { + grid-column: 1; + } + + .percent { + text-align: left; + } + + .radio-view .option-row { + padding: 10px; + } +} + +@media (max-width: 320px) { + .poll-creator { + width: 95%; + padding: 3%; + } + + .question-input-container input, + .category-selector-container select, + .options-input-container li input { + padding: 8px; + } +} + +@media (max-width: 270px) { + + * { + font-size: 1em; + } + + .poll-creator { + width: 95%; + padding: 3%; + } + + .question-input-container input, + .category-selector-container select, + .options-input-container li input { + width: 95%; + } +} + +@media (max-width: 634px) and (min-width: 482px) { + .options-results-row { + grid-template-columns: 35% 1fr auto; + gap: 8px; + } + + .options-results-row label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .slidecontainer { + min-width: 100px; + } + + .percent { + min-width: 40px; + text-align: right; + } + + .poll-container { + padding: 12px; + } +} + +@media (max-width: 482px) { + .options-results-row { + grid-template-columns: 1fr; + grid-template-rows: auto auto auto; + gap: 5px; + } + + .options-results-row label { + grid-row: 1; + } + + .slidecontainer { + grid-row: 2; + width: 100%; + } + + .percent { + grid-row: 3; + text-align: left; + } +} + +@media (max-width: 210px) { + * { + font-size: 14px !important; + font-weight: 300 !important; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + + +@media (max-width: 180px) { + * { + font-size: 12px !important; + } + + body { + padding: 2px; + } + + .content-container { + margin-top: 5px; + } + + .create-poll-container #open-poll-creator { + padding: 4px; + font-size: 0.9em; + } + + .create-poll-container .category-container { + flex-direction: column; + margin: 5px 0; + gap: 3px; + } + + .category-container input, + .category-container select { + width: 100%; + padding: 3px; + } + + .poll-container { + padding: 5px; + margin-bottom: 5px; + } + + .poll-title { + font-size: 0.9em; + line-height: 1.2; + } + + .options-results-row { + grid-template-columns: 1fr; + gap: 3px; + margin-bottom: 5px; + } + + .options-results-row label { + font-size: 0.8em; + } + + .slidecontainer { + width: 100%; + } + + .slider { + width: 100%; + min-width: auto; + } + + .percent { + font-size: 0.8em; + text-align: left; + } + + .votes-quantity { + font-size: 0.7em; + } + + .poll-creator { + width: 95%; + padding: 5px; + height: auto; + } + + .poll-creator .question-input-container input, + .poll-creator .category-selector-container select, + .poll-creator .options-input-container li input { + padding: 3px; + margin-bottom: 3px; + font-size: 0.8em; + } + + .poll-creator #create-new-poll { + padding: 4px; + font-size: 0.9em; + } +} + +@media (max-width: 120px) { + * { + font-size: 6px !important; + } + + body { + padding: 1px; + } + + .content-container { + margin-top: 3px; + } + + .create-poll-container #open-poll-creator { + padding: 3px; + font-size: 0.8em; + } + + .create-poll-container .category-container { + margin: 3px 0; + gap: 2px; + } + + .category-container input, + .category-container select { + padding: 2px; + font-size: 0.7em; + } + + .poll-container { + padding: 4px; + margin-bottom: 4px; + } + + .poll-title { + font-size: 0.8em; + line-height: 1.1; + margin-bottom: 2px; + } + + .options-results-row { + gap: 2px; + margin-bottom: 3px; + } + + .options-results-row label { + font-size: 0.7em; + } + + .slider { + height: 8px; + } + + .percent { + font-size: 0.7em; + } + + .votes-quantity { + font-size: 0.6em; + } + + .poll-creator { + width: 98%; + padding: 3px; + } + + .poll-creator .text { + font-size: 0.8em; + margin-bottom: 2px; + } + + .poll-creator .question-input-container input, + .poll-creator .category-selector-container select, + .poll-creator .options-input-container li input { + padding: 0px; + font-size: 0.7em; + margin-bottom: 0px; + } + + .poll-creator #add-new-option { + font-size: 0.7em; + } + + .poll-creator #create-new-poll { + padding: 3px; + font-size: 0.8em; + } + + select>option:first-child, + #add-new-option span { + display: none; + } + + button, + input, + select { + max-height: 16px; + } +} + +@media (max-width: 70px) { + * { + font-size: 4px !important; + } + + body { + padding: 0px; + } + + .content-container { + margin-top: 0px; + } + + .create-poll-container #open-poll-creator { + padding: 3px; + font-size: 0.8em; + } + + .create-poll-container .category-container { + margin: 3px 0; + gap: 2px; + } + + .category-container input, + .category-container select { + padding: 2px; + font-size: 0.7em; + } + + .poll-container { + padding: 4px; + margin-bottom: 4px; + } + + .poll-title { + font-size: 0.8em; + line-height: 1.1; + margin-bottom: 2px; + } + + .options-results-row { + gap: 2px; + margin-bottom: 3px; + } + + .options-results-row label { + font-size: 0.7em; + } + + .slider { + height: 8px; + } + + .percent { + font-size: 0.7em; + } + + .votes-quantity { + font-size: 0.6em; + } + + .poll-creator { + width: 98%; + padding: 3px; + } + + .poll-creator .text { + font-size: 0.8em; + margin-bottom: 2px; + } + + .poll-creator .question-input-container input, + .poll-creator .category-selector-container select, + .poll-creator .options-input-container li input { + padding: 0px; + font-size: 0.7em; + margin-bottom: 0px; + } + + .poll-creator #add-new-option { + font-size: 0.7em; + } + + .poll-creator #create-new-poll { + padding: 3px; + font-size: 0.8em; + } + + select>option:first-child, + #add-new-option span { + display: none; + } + + button, + input, + select { + max-height: 16px; + } +} \ No newline at end of file From 9cc5d983f6b7b28fd7cb92e06a5604b18f180c2a Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 23 Jun 2025 09:48:15 +0300 Subject: [PATCH 2/3] last version of 5 h/w --- .vscode/settings.json | 3 + data/polls.json | 98 ++++++++++ index.html | 106 +++-------- report.html | 65 +++++++ src/main.js | 429 +++++++++++++++++++++++++++++++++--------- src/report.js | 86 +++++++++ style/style.css | 27 ++- 7 files changed, 641 insertions(+), 173 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 data/polls.json create mode 100644 report.html create mode 100644 src/report.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9607d34 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "livePreview.defaultPreviewPath": "/index.html" +} \ No newline at end of file diff --git a/data/polls.json b/data/polls.json new file mode 100644 index 0000000..76af66e --- /dev/null +++ b/data/polls.json @@ -0,0 +1,98 @@ +[ + { + "id": "1", + "question": "Яка ваша улюблена мова програмування?", + "category": "Програмування", + "options": [ + { "text": "Python", "votes": 30 }, + { "text": "Java", "votes": 50 }, + { "text": "Javascript", "votes": 15 }, + { "text": "Swift", "votes": 5 } + ], + "totalVotes": 100 + }, + { + "id": "2", + "question": "Якою соціальною мережею ви користуєтесь частіше над усе?", + "category": "Інше", + "options": [ + { "text": "Instagram", "votes": 30 }, + { "text": "Tiktok", "votes": 50 }, + { "text": "Facebook", "votes": 15 }, + { "text": "LinkedIn", "votes": 5 } + ], + "totalVotes": 100 + }, + { + "id": "3", + "question": "Ваша улюблена пора року?", + "category": "Інше", + "options": [ + { "text": "Весна", "votes": 25 }, + { "text": "Літо", "votes": 40 }, + { "text": "Осінь", "votes": 20 }, + { "text": "Зима", "votes": 15 } + ], + "totalVotes": 100 + }, + { + "id": "4", + "question": "Який ваш улюблений жанр літератури?", + "category": "Література", + "options": [ + { "text": "Фантастика", "votes": 35 }, + { "text": "Фентезі", "votes": 30 }, + { "text": "Детектив", "votes": 20 }, + { "text": "Роман", "votes": 15 } + ], + "totalVotes": 100 + }, + { + "id": "5", + "question": "Яка ваша улюблена тварина?", + "category": "Тварини", + "options": [ + { "text": "Собака", "votes": 45 }, + { "text": "Кішка", "votes": 35 }, + { "text": "Папуга", "votes": 10 }, + { "text": "Рибка", "votes": 10 } + ], + "totalVotes": 100 + }, + { + "id": "6", + "question": "Який філософський напрямок вам найближчий?", + "category": "Філософія", + "options": [ + { "text": "Екзистенціалізм", "votes": 20 }, + { "text": "Стоїцизм", "votes": 40 }, + { "text": "Раціоналізм", "votes": 25 }, + { "text": "Емпіризм", "votes": 15 } + ], + "totalVotes": 100 + }, + { + "id": "7", + "question": "Найважливіша історична подія 20 століття?", + "category": "Історія", + "options": [ + { "text": "Перша світова війна", "votes": 20 }, + { "text": "Друга світова війна", "votes": 60 }, + { "text": "Холодна війна", "votes": 10 }, + { "text": "Розпад СРСР", "votes": 10 } + ], + "totalVotes": 100 + }, + { + "id": "8", + "question": "Яка математична операція найважливіша?", + "category": "Математика", + "options": [ + { "text": "Додавання", "votes": 25 }, + { "text": "Віднімання", "votes": 25 }, + { "text": "Множення", "votes": 25 }, + { "text": "Ділення", "votes": 25 } + ], + "totalVotes": 100 + } +] \ No newline at end of file diff --git a/index.html b/index.html index 3f6d285..4b60a2d 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,10 @@ + + + + Опитування @@ -10,10 +14,12 @@ +
+
- +
+
-
-
    -
  • -
    Яка ваша улюблена мова програмування?
    -
    -
      -
    • - -
      - -
      - 30% -
    • -
    • - -
      - -
      - 50% -
    • -
    • - -
      - -
      - 15% -
    • -
    • - -
      - -
      - 5% -
    • -
    -
    - 150 votes -
  • - -
  • -
    Якою соціальною мережею ви користуєтесь частіше над усе?
    -
    -
      -
    • - -
      - -
      - 30% -
    • -
    • - -
      - -
      - 50% -
    • -
    • - -
      - -
      - 15% -
    • -
    • - -
      - -
      - 5% -
    • -
    -
    - 180 votes -
  • +
    +
@@ -115,29 +53,33 @@
- + + + +
-
    +
    • - +
    • - +
    • - +
    • - +
    diff --git a/report.html b/report.html new file mode 100644 index 0000000..6ae8989 --- /dev/null +++ b/report.html @@ -0,0 +1,65 @@ + + + + + + Аналітика опитувань + + + + + + +
    +

    Аналітика опитувань

    + ← Повернутись +
    + +
    +
    +
    + + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 3218cf7..2173894 100644 --- a/src/main.js +++ b/src/main.js @@ -1,100 +1,359 @@ +let pollsData = []; + +const openPollCreator = document.getElementById('open-poll-creator'); +const pollCreator = document.querySelector('.poll-creator'); +const content = document.querySelector('.content-container'); +const closeBtn = document.querySelector('.close-btn'); +const createNewPoll = document.getElementById('create-new-poll'); +let pollContainers = document.querySelectorAll('.poll-container'); + +const loadPolls = async () => { + try { + const savedPolls = localStorage.getItem('polls'); + if (savedPolls) { + pollsData = JSON.parse(savedPolls); + } else { + const response = await fetch('data/polls.json'); + const data = await response.json(); + pollsData = data; + localStorage.setItem('polls', JSON.stringify(data)); + } + renderPolls(pollsData); + } catch (error) { + console.error('Помилка завантаження опитувань:', error); + pollsData = [ + { + id: "1", + question: "Яка ваша улюблена мова програмування?", + category: "Програмування", + options: [ + { text: "Python", votes: 30 }, + { text: "Java", votes: 50 }, + { text: "Javascript", votes: 15 }, + { text: "Swift", votes: 5 } + ], + totalVotes: 100 + }, + { + id: "2", + question: "Якою соціальною мережею ви користуєтесь частіше над усе?", + category: "Інше", + options: [ + { text: "Instagram", votes: 30 }, + { text: "Tiktok", votes: 50 }, + { text: "Facebook", votes: 15 }, + { text: "LinkedIn", votes: 5 } + ], + totalVotes: 100 + } + ]; + renderPolls(pollsData); + } +}; + +const renderPolls = (polls) => { + const pollList = document.getElementById('poll-list'); + pollList.innerHTML = ''; + + polls.forEach(poll => { + const pollElement = document.createElement('li'); + pollElement.className = 'poll-container stats-view'; + pollElement.dataset.id = poll.id; + pollElement.dataset.category = poll.category; + + let optionsHTML = ''; + poll.options.forEach(option => { + const percent = poll.totalVotes > 0 + ? Math.round((option.votes / poll.totalVotes) * 100) + : 0; + + optionsHTML += ` +
  • + +
    + +
    + ${percent}% +
  • + `; + }); + + pollElement.innerHTML = ` +
    ${poll.question}
    +
    +
      ${optionsHTML}
    +
    + ${poll.totalVotes} votes + `; + + pollList.appendChild(pollElement); + }); + + storeOriginalPollContent(); + bindPollEvents(); +}; + const storeOriginalPollContent = () => { - const polls = document.querySelectorAll('.poll-container'); - polls.forEach(poll => { - poll.dataset.originalContent = poll.innerHTML; - }); - }; + const polls = document.querySelectorAll('.poll-container'); + polls.forEach(poll => { + poll.dataset.originalContent = poll.innerHTML; + }); +}; - const convertToRadioView = (poll) => { - const title = poll.querySelector('.poll-title').textContent; - const options = poll.querySelectorAll('.options-results-row label'); - - let radioHTML = ` -
    ${title}
    -
    +const convertToRadioView = (poll) => { + const pollId = poll.dataset.id; + const pollData = pollsData.find(p => p.id === pollId); + + if (!pollData) return; + + let radioHTML = ` +
    ${pollData.question}
    +
    + `; + + pollData.options.forEach((option, index) => { + radioHTML += ` +
    + + +
    + `; + }); + + radioHTML += ` +
    + ${pollData.totalVotes} votes + `; + + poll.innerHTML = radioHTML; + poll.classList.remove('stats-view'); + poll.classList.add('radio-view'); +}; + +const convertToStatsView = (poll) => { + const pollId = poll.dataset.id; + const pollData = pollsData.find(p => p.id === pollId); + + if (pollData) { + let optionsHTML = ''; + pollData.options.forEach(option => { + const percent = pollData.totalVotes > 0 + ? Math.round((option.votes / pollData.totalVotes) * 100) + : 0; + + optionsHTML += ` +
  • + +
    + +
    + ${percent}% +
  • `; + }); + + const newContent = ` +
    ${pollData.question}
    +
    +
      ${optionsHTML}
    +
    + ${pollData.totalVotes} votes + `; + + poll.innerHTML = newContent; + poll.dataset.originalContent = newContent; + } + + poll.classList.remove('radio-view'); + poll.classList.add('stats-view'); +}; + +const togglePollView = (poll) => { + if (poll.classList.contains('stats-view')) { + convertToRadioView(poll); + } else { + convertToStatsView(poll); + } +}; + +const filterPolls = () => { + const searchInput = document.querySelector('.category-container input'); + const categorySelect = document.querySelector('.category-container select'); + + const searchText = searchInput.value.toLowerCase(); + const selectedCategory = categorySelect.value; + + const filtered = pollsData.filter(poll => { + const matchesCategory = selectedCategory === 'Категорія' || + poll.category === selectedCategory; + const matchesSearch = poll.question.toLowerCase().includes(searchText); + return matchesCategory && matchesSearch; + }); + + renderPolls(filtered); +}; + +const addNewPoll = () => { + const questionInput = document.getElementById('question'); + const categorySelect = document.getElementById('category'); + const optionInputs = document.querySelectorAll('.option-input'); + + const question = questionInput.value.trim(); + const category = categorySelect.value; + const options = Array.from(optionInputs) + .map(input => input.value.trim()) + .filter(text => text !== ''); + + if (!question || options.length < 2) { + alert('Будь ласка, введіть питання та щонайменше два варіанти'); + return; + } + + const newPoll = { + id: Date.now().toString(), + question: question, + category: category, + options: options.map(text => ({ text, votes: 0 })), + totalVotes: 0 + }; + + pollsData.push(newPoll); + localStorage.setItem('polls', JSON.stringify(pollsData)); + renderPolls(pollsData); + + questionInput.value = ''; + categorySelect.value = 'Категорія'; + const optionsList = document.getElementById('options-list'); + optionsList.innerHTML = ` +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • + `; +}; + +const addNewOption = () => { + const optionsList = document.getElementById('options-list'); + const newOption = document.createElement('li'); + newOption.className = 'option'; + newOption.innerHTML = ` + + `; + optionsList.appendChild(newOption); + + newOption.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); +}; + +const bindPollEvents = () => { + pollContainers = document.querySelectorAll('.poll-container'); + + pollContainers.forEach((poll) => { + poll.addEventListener('click', (event) => { + if (event.target.tagName === 'INPUT' && event.target.type === 'radio') { + const pollElement = event.target.closest('.poll-container'); + const pollId = pollElement.dataset.id; + const poll = pollsData.find(p => p.id === pollId); + + if (poll) { + const hasVoted = localStorage.getItem(`voted_${pollId}`); + if (hasVoted) { + alert('Ви вже голосували в цьому опитуванні'); + return; + } + + const optionIndex = Array.from( + pollElement.querySelectorAll('.option-row input') + ).indexOf(event.target); + + if (optionIndex !== -1) { + poll.options[optionIndex].votes++; + poll.totalVotes++; + localStorage.setItem('polls', JSON.stringify(pollsData)); + localStorage.setItem(`voted_${pollId}`, 'true'); + + const votesElement = pollElement.querySelector('.votes-quantity'); + if (votesElement) { + votesElement.textContent = `${poll.totalVotes} votes`; + } + } + } + return; + } - options.forEach((option, index) => { - radioHTML += ` -
    - - -
    - `; + if (event.target.tagName === 'LABEL') { + return; + } + + pollContainers.forEach((anotherPoll) => { + if (anotherPoll !== poll) { + anotherPoll.classList.toggle('disappear'); + anotherPoll.classList.add('slowly'); + } }); - poll.innerHTML = radioHTML; - poll.classList.remove('stats-view'); - poll.classList.add('radio-view'); - }; - - const convertToStatsView = (poll) => { - poll.innerHTML = poll.dataset.originalContent; - poll.classList.remove('radio-view'); - poll.classList.add('stats-view'); - }; - - const togglePollView = (poll) => { - if (poll.classList.contains('stats-view')) { - convertToRadioView(poll); - } else { - convertToStatsView(poll); - } - }; + poll.classList.toggle('big'); + + const pollUpper = document.querySelector('.create-poll-container'); + pollUpper.classList.toggle('disappear'); + + poll.classList.remove('slowly'); + + togglePollView(poll); + }); + }); +}; - const openPollCreator = document.getElementById('open-poll-creator'); - const pollCreator = document.querySelector('.poll-creator'); - const content = document.querySelector('.content-container'); - const closeBtn = document.querySelector('.close-btn'); - const createNewPoll = document.getElementById('create-new-poll'); - const pollContainers = document.querySelectorAll('.poll-container'); +const initEventListeners = () => { + openPollCreator.addEventListener('click', () => { + pollCreator.classList.toggle('appear'); + content.classList.toggle('disappear'); + + document.body.classList.toggle('creator-open'); + }); - document.addEventListener('DOMContentLoaded', () => { - storeOriginalPollContent(); - }); + closeBtn.addEventListener('click', () => { + pollCreator.classList.remove('appear'); + content.classList.remove('disappear'); + document.body.classList.remove('creator-open'); + }); - openPollCreator.addEventListener('click', () => { - pollCreator.classList.toggle('appear'); - content.classList.toggle('disappear'); - }); + createNewPoll.addEventListener('click', () => { + addNewPoll(); + pollCreator.classList.remove('appear'); + content.classList.remove('disappear'); + document.body.classList.remove('creator-open'); + }); - closeBtn.addEventListener('click', () => { + pollCreator.addEventListener('click', (event) => { + if (event.target === pollCreator) { pollCreator.classList.remove('appear'); content.classList.remove('disappear'); - }); + document.body.classList.remove('creator-open'); + } + }); - createNewPoll.addEventListener('click', () => { - pollCreator.classList.remove('appear'); - content.classList.remove('disappear'); - }); + document.getElementById('add-new-option').addEventListener('click', addNewOption); - pollCreator.addEventListener('click', (event) => { - if (event.target === pollCreator) { - pollCreator.classList.remove('appear'); - content.classList.remove('disappear'); - } - }); + const searchInput = document.querySelector('.category-container input'); + const categorySelect = document.querySelector('.category-container select'); + searchInput.addEventListener('input', filterPolls); + categorySelect.addEventListener('change', filterPolls); - pollContainers.forEach((poll) => { - poll.addEventListener('click', (event) => { - if (event.target.tagName === 'INPUT' || event.target.tagName === 'LABEL') { - return; - } - - pollContainers.forEach((anotherPoll) => { - if (anotherPoll !== poll) { - anotherPoll.classList.toggle('disappear'); - anotherPoll.classList.add('slowly'); - } - }); - - poll.classList.toggle('big'); - - const pollUpper = document.querySelector('.create-poll-container'); - pollUpper.classList.toggle('disappear'); - - poll.classList.remove('slowly'); - - togglePollView(poll); - }); - }); \ No newline at end of file + document.getElementById('open-report').addEventListener('click', () => { + window.location.href = 'report.html'; + }); +}; + +document.addEventListener('DOMContentLoaded', () => { + loadPolls(); + initEventListeners(); + storeOriginalPollContent(); +}); \ No newline at end of file diff --git a/src/report.js b/src/report.js new file mode 100644 index 0000000..1000e6e --- /dev/null +++ b/src/report.js @@ -0,0 +1,86 @@ +document.addEventListener('DOMContentLoaded', async () => { + let pollsData = JSON.parse(localStorage.getItem('polls')) || []; + + if (pollsData.length === 0) { + try { + const response = await fetch('data/polls.json'); + if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); + + pollsData = await response.json(); + localStorage.setItem('polls', JSON.stringify(pollsData)); + } catch (error) { + alert('Не вдалося завантажити дані для аналітики: ' + error.message); + return; + } + } + + const reportData = []; + + pollsData.forEach(poll => { + poll.options.forEach(option => { + const percent = poll.totalVotes > 0 + ? Math.round((option.votes / poll.totalVotes) * 100) + : 0; + + reportData.push({ + "ID опитування": poll.id, + "Питання": poll.question, + "Категорія": poll.category, + "Варіант": option.text, + "Кількість голосів": option.votes, + "Відсоток": percent, + "Загальна кількість голосів": poll.totalVotes + }); + }); + }); + + try { + const report = { + dataSource: { + data: reportData + }, + options: { + grid: { + type: "flat", + showTotals: "on", + showGrandTotals: "on" + }, + configuratorActive: true + }, + slice: { + rows: [ + { uniqueName: "Категорія" }, + { uniqueName: "Питання" }, + { uniqueName: "Варіант" } + ], + columns: [ + { uniqueName: "Measures" } + ], + measures: [ + { uniqueName: "Кількість голосів", aggregation: "sum" }, + { uniqueName: "Відсоток", aggregation: "average" } + ] + }, + formats: [ + { + name: "Кількість голосів", + decimalPlaces: 0 + }, + { + name: "Відсоток", + decimalPlaces: 1, + maxDecimalPlaces: 1 + } + ] + }; + + new WebDataRocks({ + container: "#wdr-component", + toolbar: true, + report: report + }); + + } catch (e) { + alert("Помилка ініціалізації звіту: " + e.message); + } +}); \ No newline at end of file diff --git a/style/style.css b/style/style.css index 92bd08c..a6ec8a2 100644 --- a/style/style.css +++ b/style/style.css @@ -89,14 +89,13 @@ body { width: 25%; } -.poll-list { +.poll-list-container { width: 100%; } -.poll-list ul { +.poll-list-container #poll-list { display: flex; flex-direction: column; - gap: 20px; } .poll-container { @@ -109,6 +108,7 @@ body { background-color: var(--main-color); cursor: pointer; transition: all 0.3s; + margin-bottom: 20px; } .poll-container:hover { @@ -225,17 +225,32 @@ body { flex-direction: column; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); position: fixed; - transform: translateY(200%); + bottom: 0; + transform: translateY(100%); transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1), opacity 0s 2s; z-index: 1000; opacity: 0; + + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0.95); + opacity: 0; + transition: all 0.3s ease; + z-index: 1000; + max-height: 90vh; + overflow-y: auto; + width: 90%; + max-width: 600px; } .poll-creator.appear { - display: flex; transform: translateY(0%); transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1); opacity: 1; + + transform: translate(-50%, -50%) scale(1); + opacity: 1; } .poll-creator .poll-creator-container { @@ -278,7 +293,7 @@ body { display: flex; } -.options-input-container li.option input { +.options-input-container li.option .option-input { flex: 1; } From a4a5a8a2874d1802366477f71ad741cbe8c3613c Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 23 Jun 2025 09:58:08 +0300 Subject: [PATCH 3/3] bonus --- index.html | 2 +- style/style.css | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 4b60a2d..379b101 100644 --- a/index.html +++ b/index.html @@ -33,7 +33,7 @@
- +
diff --git a/style/style.css b/style/style.css index a6ec8a2..dde7254 100644 --- a/style/style.css +++ b/style/style.css @@ -793,4 +793,18 @@ body { select { max-height: 16px; } -} \ No newline at end of file +} + +#open-report { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px 20px; + background-color: #4277d7; + color: white; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); + border-radius: var(--border-radius); + border: none; + outline: none; + margin-top: 20px; + } \ No newline at end of file