From 2202767efdd4491e5874b42a161d529019a11a14 Mon Sep 17 00:00:00 2001 From: DenisKoriavets Date: Mon, 16 Jun 2025 10:28:03 +0300 Subject: [PATCH 1/2] Do hw4 --- index.html | 303 ++++++++++++++++++++++++++++- style/style.css | 501 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 801 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 09c6dc0..e81176c 100644 --- a/index.html +++ b/index.html @@ -3,11 +3,308 @@ - Simple HTML Page - - + Polling Website + +
+ + + + +
+ + + + + + + + + + \ No newline at end of file diff --git a/style/style.css b/style/style.css index e69de29..b1d5842 100644 --- a/style/style.css +++ b/style/style.css @@ -0,0 +1,501 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background-color: whitesmoke; + padding: clamp(10px, 4vw, 20px); + line-height: 1.6; +} + +.container { + margin: 0 auto; + max-width: 1400px; +} + +.create-poll-header { + margin-bottom: clamp(15px, 3vw, 20px); +} + +.create-poll-btn { + background: #4378d8; + border: none; + color: white; + padding: clamp(16px, 4vw, 20px) clamp(20px, 5vw, 24px); + border-radius: 8px; + cursor: pointer; + font-size: clamp(18px, 4.5vw, 30px); + font-weight: 500; + transition: all 0.3s ease; + width: 100%; + text-align: left; + box-shadow: 0 4px 12px rgba(0,0,0,0.25); + text-decoration: none; + display: block; + min-height: 44px; +} + +.create-poll-btn:hover { + background: #275cbe; + transform: translateY(-2px); +} + +.search-bar { + display: flex; + gap: clamp(10px, 3vw, 15px); + margin-bottom: clamp(20px, 5vw, 30px); +} + +.search-input, +.category-dropdown { + padding: clamp(12px, 3vw, 12px) clamp(16px, 4vw, 20px); + border: 2px solid #ddd; + background: white; + font-size: clamp(16px, 4vw, 20px); + outline: none; + border-radius: 8px; + transition: border-color 0.3s ease; + min-height: 44px; +} + +.search-input { + flex: 1; +} + +.search-input:focus, +.category-dropdown:focus { + border-color: #4378d8; + box-shadow: 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +.category-dropdown { + min-width: clamp(120px, 35vw, 150px); +} + +.poll-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(clamp(250px, 100%, 400px), 1fr)); + gap: clamp(15px, 4vw, 20px); +} + +@media (min-width: 1400px) { + .poll-grid { + grid-template-columns: repeat(3, 1fr); + } +} + +.poll-card { + background: white; + border-radius: 12px; + border: 2px solid #ddd; + padding: clamp(16px, 5vw, 24px); + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + transition: all 0.3s ease; + text-decoration: none; + color: black; + display: block; + min-height: 44px; +} + +.poll-card:hover, +.poll-card:focus { + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(0,0,0,0.15); + border-color: #4378d8; + outline: none; +} + +.poll-card:focus { + box-shadow: 0 4px 16px rgba(0,0,0,0.15), 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +.poll-title { + font-size: clamp(18px, 4.5vw, 25px); + font-weight: 600; + color: #333; + margin-bottom: clamp(14px, 4vw, 20px); +} + +.poll-option { + display: flex; + align-items: center; + margin-bottom: clamp(10px, 3vw, 12px); + padding: clamp(6px, 2vw, 8px); + border-radius: 8px; +} + +.option-label { + font-size: clamp(15px, 4vw, 20px); + font-weight: 500; + color: #333; + width: clamp(80px, 25vw, 120px); + flex-shrink: 0; + text-align: left; +} + +.progress-container { + flex: 1; + margin: 0 clamp(12px, 4vw, 20px); + background-color: #f0f0f0; + border-radius: 20px; + height: clamp(8px, 2vw, 8px); + position: relative; + overflow: hidden; +} + +.progress-bar { + height: 100%; + background: linear-gradient(90deg, #4378d8, #5c89e6); + border-radius: 20px; + transition: width 0.3s ease; +} + +.percentage { + font-size: clamp(15px, 4vw, 20px); + font-weight: 600; + color: #333; + min-width: clamp(40px, 10vw, 50px); + text-align: right; +} + +.vote-count { + text-align: right; + color: #666; + font-size: clamp(15px, 4vw, 18px); + margin-top: clamp(12px, 3vw, 15px); + font-weight: 500; +} + +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.6); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + padding: 10px; +} + +.modal:target { + opacity: 1; + visibility: visible; +} + +.modal-content { + background: white; + border-radius: 16px; + padding: clamp(20px, 6vw, 30px); + width: clamp(280px, 95vw, 600px); + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); + transform: scale(0.7); + transition: transform 0.3s ease; + box-sizing: border-box; +} + +.modal:target .modal-content { + transform: scale(1); +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: clamp(20px, 6vw, 30px); + padding-bottom: clamp(12px, 3vw, 15px); + border-bottom: 2px solid #f0f0f0; +} + +.modal-header h2 { + font-size: clamp(1.3rem, 5vw, 2rem); + color: #333; + margin: 0; +} + +.close-btn { + font-size: clamp(28px, 7vw, 30px); + color: #666; + text-decoration: none; + width: clamp(40px, 10vw, 40px); + height: clamp(40px, 10vw, 40px); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: all 0.3s ease; + min-height: 44px; + min-width: 44px; +} + +.close-btn:hover, +.close-btn:focus { + background: #f0f0f0; + color: #333; + outline: none; + box-shadow: 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +.poll-form .form-group { + margin-bottom: clamp(20px, 5vw, 25px); +} + +.poll-form label { + display: block; + font-size: clamp(16px, 4vw, 20px); + color: #333; + margin-bottom: clamp(8px, 2vw, 8px); + font-weight: 500; +} + +.poll-form input[type="text"], +.poll-form select { + width: 100%; + padding: clamp(14px, 4vw, 15px); + border: 2px solid #ddd; + border-radius: 8px; + font-size: clamp(16px, 4vw, 18px); + transition: all 0.3s ease; + background: white; + min-height: 44px; +} + +.poll-form input[type="text"]:focus, +.poll-form select:focus, +.option-input:focus { + outline: none; + border-color: #4378d8; + box-shadow: 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +.options-container { + display: flex; + flex-direction: column; + gap: 12px; +} + +.option-input { + padding: clamp(14px, 4vw, 15px); + border: 2px solid #e0e0e0; + border-radius: 8px; + font-size: clamp(16px, 4vw, 18px); + background-color: #fafafa; + transition: all 0.3s ease; + min-height: 44px; +} + +.add-option-btn { + background: none; + border: none; + color: #4378d8; + font-size: clamp(16px, 4vw, 18px); + font-weight: 500; + cursor: pointer; + padding: 12px 0; + text-decoration: none; + transition: all 0.3s ease; + margin-top: 10px; + min-height: 44px; +} + +.add-option-btn:hover, +.add-option-btn:focus { + color: #275cbe; + text-decoration: underline; + outline: none; + box-shadow: 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +.vote-modal .modal-content { + max-width: clamp(320px, 90vw, 500px); +} + +.question { + font-size: clamp(1.2rem, 5vw, 1.5rem); + text-align: center; + margin-bottom: clamp(25px, 6vw, 30px); + color: #333; + font-weight: 500; +} + +.vote-options { + display: flex; + flex-direction: column; + gap: clamp(12px, 3vw, 15px); + margin-bottom: clamp(25px, 6vw, 30px); +} + +.vote-option { + position: relative; +} + +.vote-option input[type="radio"] { + position: absolute; + opacity: 0; + cursor: pointer; +} + +.vote-option label { + display: flex; + align-items: center; + font-size: clamp(1rem, 4vw, 1.2rem); + cursor: pointer; + padding: clamp(14px, 4vw, 15px) clamp(18px, 5vw, 20px); + border-radius: 12px; + transition: all 0.3s ease; + border: 2px solid transparent; + background: #f8f9fa; + min-height: 44px; +} + +.vote-option label:hover { + border-color: #e9ecef; + background: white; +} + +.vote-option input[type="radio"]:checked + label { + border-color: #4378d8; + background: #f0f7ff; + color: #4378d8; +} + +.vote-option input[type="radio"]:focus + label { + box-shadow: 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +.radio-button { + width: clamp(20px, 5vw, 24px); + height: clamp(20px, 5vw, 24px); + border: 2px solid #ccc; + border-radius: 50%; + margin-right: clamp(12px, 3vw, 15px); + position: relative; + transition: all 0.3s ease; + min-width: 20px; + min-height: 20px; +} + +.vote-option input[type="radio"]:checked + label .radio-button { + border-color: #4378d8; + background-color: #4378d8; +} + +.vote-option input[type="radio"]:checked + label .radio-button::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: clamp(6px, 2vw, 8px); + height: clamp(6px, 2vw, 8px); + background-color: white; + border-radius: 50%; +} + +.modal-actions { + display: flex; + gap: clamp(12px, 3vw, 15px); + justify-content: flex-end; + margin-top: clamp(20px, 5vw, 20px); +} + +.cancel-btn, +.create-btn, +.vote-btn { + padding: clamp(12px, 4vw, 12px) clamp(18px, 5vw, 24px); + font-size: clamp(16px, 4vw, 18px); + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + border-radius: 8px; + min-height: 44px; +} + +.cancel-btn { + background: transparent; + color: #666; + border: 2px solid #ddd; + text-decoration: none; +} + +.cancel-btn:hover, +.cancel-btn:focus { + background: #f0f0f0; + border-color: #ccc; + outline: none; + box-shadow: 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +.create-btn, +.vote-btn { + background-color: #4378d8; + color: white; + border: none; +} + +.create-btn:hover, +.vote-btn:hover, +.create-btn:focus, +.vote-btn:focus { + background-color: #275cbe; + transform: translateY(-1px); + outline: none; + box-shadow: 0 0 0 3px rgba(67, 120, 216, 0.2); +} + +@media (max-width: 768px) { + .search-bar { + flex-direction: column; + } + + .category-dropdown { + min-width: 100%; + } +} + +@media (max-width: 600px) { + .modal-actions { + flex-direction: column; + } + + .cancel-btn, + .create-btn, + .vote-btn { + width: 100%; + text-align: center; + } +} + +@media (max-width: 300px) { + .option-label { + width: clamp(50px, 20vw, 80px); + font-size: clamp(13px, 4vw, 15px); + } + + .percentage { + min-width: clamp(30px, 8vw, 40px); + font-size: clamp(13px, 4vw, 15px); + } + + .progress-container { + margin: 0 clamp(8px, 3vw, 12px); + } + + .poll-card { + padding: clamp(12px, 4vw, 16px); + } + + .poll-title { + font-size: clamp(16px, 4vw, 18px); + } +} \ No newline at end of file From 578280e6698084fa4126f1d389fe326e1a95e6a9 Mon Sep 17 00:00:00 2001 From: DenisKoriavets Date: Mon, 23 Jun 2025 09:20:12 +0300 Subject: [PATCH 2/2] Do hw5 --- .idea/.gitignore | 8 + .idea/JS_Template.iml | 11 + .idea/easycode.ignore | 13 ++ .idea/jsLibraryMappings.xml | 6 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + data/polls.json | 98 +++++++++ index.html | 239 +------------------- report.html | 105 +++++++++ src/main.js | 310 ++++++++++++++++++++++++++ style/style.css | 426 ++++++++++++++++++++++++++++++++++++ 12 files changed, 1001 insertions(+), 235 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/JS_Template.iml create mode 100644 .idea/easycode.ignore create mode 100644 .idea/jsLibraryMappings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 data/polls.json create mode 100644 report.html diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/JS_Template.iml b/.idea/JS_Template.iml new file mode 100644 index 0000000..3ad4ebd --- /dev/null +++ b/.idea/JS_Template.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/easycode.ignore b/.idea/easycode.ignore new file mode 100644 index 0000000..04b63e2 --- /dev/null +++ b/.idea/easycode.ignore @@ -0,0 +1,13 @@ +.idea +.vscode +node_modules/ +dist/ +vendor/ +cache/ +.*/ +*.min.* +*.test.* +*.spec.* +*.bundle.* +*.bundle-min.* +*.log diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..3565144 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f03c948 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8811d7b --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/data/polls.json b/data/polls.json new file mode 100644 index 0000000..0547f85 --- /dev/null +++ b/data/polls.json @@ -0,0 +1,98 @@ +[ + { + "id": "poll_1", + "question": "What is your favorite programming language?", + "category": "technology", + "options": [ + { "text": "JavaScript", "votes": 67 }, + { "text": "Python", "votes": 52 }, + { "text": "Java", "votes": 23 }, + { "text": "C++", "votes": 8 } + ], + "totalVotes": 150 + }, + { + "id": "poll_2", + "question": "Which social media platform do you use the most?", + "category": "lifestyle", + "options": [ + { "text": "Facebook", "votes": 98 }, + { "text": "Instagram", "votes": 84 }, + { "text": "Twitter", "votes": 70 }, + { "text": "LinkedIn", "votes": 28 } + ], + "totalVotes": 280 + }, + { + "id": "poll_3", + "question": "What is your favorite color?", + "category": "lifestyle", + "options": [ + { "text": "Blue", "votes": 38 }, + { "text": "Green", "votes": 29 }, + { "text": "Red", "votes": 19 }, + { "text": "Yellow", "votes": 9 } + ], + "totalVotes": 95 + }, + { + "id": "poll_4", + "question": "Which business strategy is most important for startups?", + "category": "business", + "options": [ + { "text": "Product-Market Fit", "votes": 145 }, + { "text": "Marketing & Sales", "votes": 87 }, + { "text": "Team Building", "votes": 63 }, + { "text": "Funding", "votes": 41 } + ], + "totalVotes": 336 + }, + { + "id": "poll_5", + "question": "What's your preferred streaming service?", + "category": "entertainment", + "options": [ + { "text": "Netflix", "votes": 156 }, + { "text": "YouTube", "votes": 134 }, + { "text": "Disney+", "votes": 78 }, + { "text": "Amazon Prime", "votes": 92 } + ], + "totalVotes": 460 + }, + { + "id": "poll_6", + "question": "Which AI tool do you use most frequently?", + "category": "technology", + "options": [ + { "text": "ChatGPT", "votes": 189 }, + { "text": "Claude", "votes": 67 }, + { "text": "Gemini", "votes": 43 }, + { "text": "Copilot", "votes": 28 } + ], + "totalVotes": 327 + }, + { + "id": "poll_7", + "question": "What's your favorite movie genre?", + "category": "entertainment", + "options": [ + { "text": "Action", "votes": 112 }, + { "text": "Comedy", "votes": 98 }, + { "text": "Drama", "votes": 76 }, + { "text": "Sci-Fi", "votes": 54 } + ], + "totalVotes": 340 + }, + { + "id": "poll_8", + "question": "Which remote work tool is most essential?", + "category": "business", + "options": [ + { "text": "Zoom", "votes": 134 }, + { "text": "Slack", "votes": 89 }, + { "text": "Microsoft Teams", "votes": 76 }, + { "text": "Discord", "votes": 43 } + ], + "totalVotes": 342 + } +] \ No newline at end of file diff --git a/index.html b/index.html index e81176c..22cceda 100644 --- a/index.html +++ b/index.html @@ -7,8 +7,10 @@ +
@@ -24,104 +26,7 @@
@@ -168,143 +73,7 @@

Create Poll

- - - - + - \ No newline at end of file diff --git a/report.html b/report.html new file mode 100644 index 0000000..54b9e1e --- /dev/null +++ b/report.html @@ -0,0 +1,105 @@ + + + + + + Polls Report - WebDataRocks + + + + +
+
+

Polls Report

+ +
+ +
+

Detailed Poll Data

+
+
+
+ + + + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index e69de29..59a2472 100644 --- a/src/main.js +++ b/src/main.js @@ -0,0 +1,310 @@ +class PollApp { + constructor() { + this.polls = []; + this.filteredPolls = []; + this.currentCategory = ''; + this.userVotes = this.getUserVotes(); + this.init(); + } + + async init() { + await this.loadPolls(); + this.renderPolls(); + this.attachEventListeners(); + } + + async loadPolls() { + try { + const response = await fetch('/data/polls.json'); + const pollsData = await response.json(); + + const localPolls = this.getLocalPolls(); + this.polls = [...pollsData, ...localPolls]; + this.filteredPolls = [...this.polls]; + } catch (error) { + console.error('Error loading polls:', error); + this.polls = this.getLocalPolls(); + this.filteredPolls = [...this.polls]; + } + } + + getUserVotes() { + const votes = localStorage.getItem('pollVotes'); + return votes ? JSON.parse(votes) : {}; + } + + saveUserVotes() { + localStorage.setItem('pollVotes', JSON.stringify(this.userVotes)); + } + + getLocalPolls() { + const localPolls = localStorage.getItem('localPolls'); + return localPolls ? JSON.parse(localPolls) : []; + } + + saveLocalPolls() { + const localPolls = this.polls.filter(poll => poll.isLocal); + localStorage.setItem('localPolls', JSON.stringify(localPolls)); + } + + renderPolls() { + const pollGrid = document.querySelector('.poll-grid'); + pollGrid.innerHTML = ''; + + this.filteredPolls.forEach((poll, index) => { + const pollCard = this.createPollCard(poll, index); + pollGrid.appendChild(pollCard); + }); + + this.createVotingModals(); + } + + createPollCard(poll, index) { + const hasVoted = this.userVotes[poll.id]; + + const pollCard = document.createElement('a'); + pollCard.className = 'poll-card'; + pollCard.href = `#vote-modal-${index}`; + + const optionsHtml = poll.options.map(option => { + const percentage = poll.totalVotes > 0 ? Math.round((option.votes / poll.totalVotes) * 100) : 0; + return ` +
+ ${option.text} +
+
+
+ ${percentage}% +
+ `; + }).join(''); + + pollCard.innerHTML = ` +
${poll.question}
+ ${optionsHtml} +
${poll.totalVotes} votes ${hasVoted ? '(You voted)' : ''}
+ `; + + return pollCard; + } + + createVotingModals() { + const existingModals = document.querySelectorAll('[id^="vote-modal-"]'); + existingModals.forEach(modal => modal.remove()); + + this.filteredPolls.forEach((poll, index) => { + const modal = this.createVotingModal(poll, index); + document.body.appendChild(modal); + }); + } + + createVotingModal(poll, index) { + const hasVoted = this.userVotes[poll.id]; + + const modal = document.createElement('div'); + modal.id = `vote-modal-${index}`; + modal.className = 'modal'; + + const optionsHtml = poll.options.map((option, optionIndex) => ` +
+ + +
+ `).join(''); + + modal.innerHTML = ` + + `; + + return modal; + } + + attachEventListeners() { + const categoryDropdown = document.querySelector('.category-dropdown'); + categoryDropdown.addEventListener('change', (e) => { + this.currentCategory = e.target.value; + this.filterPolls(); + }); + + const searchInput = document.querySelector('.search-input'); + let searchTimeout; + searchInput.addEventListener('input', (e) => { + clearTimeout(searchTimeout); + searchTimeout = setTimeout(() => { + this.searchPolls(e.target.value); + }, 300); + }); + + const pollForm = document.querySelector('.poll-form'); + pollForm.addEventListener('submit', (e) => { + e.preventDefault(); + this.createNewPoll(new FormData(pollForm)); + }); + + const addOptionBtn = document.querySelector('.add-option-btn'); + addOptionBtn.addEventListener('click', () => { + this.addOptionInput(); + }); + + document.addEventListener('submit', (e) => { + if (e.target.classList.contains('vote-form')) { + e.preventDefault(); + this.handleVote(e.target); + } + }); + } + + filterPolls() { + if (this.currentCategory === '') { + this.filteredPolls = [...this.polls]; + } else { + this.filteredPolls = this.polls.filter(poll => poll.category === this.currentCategory); + } + this.renderPolls(); + } + + searchPolls(searchTerm) { + const term = searchTerm.toLowerCase().trim(); + if (term === '') { + this.filterPolls(); + return; + } + + let basePolls = this.currentCategory === '' ? + this.polls : + this.polls.filter(poll => poll.category === this.currentCategory); + + this.filteredPolls = basePolls.filter(poll => + poll.question.toLowerCase().includes(term) || + poll.options.some(option => option.text.toLowerCase().includes(term)) + ); + + this.renderPolls(); + } + + createNewPoll(formData) { + const question = formData.get('question').trim(); + const category = formData.get('category'); + + if (!question || !category) { + alert('Please fill in all required fields'); + return; + } + + const options = []; + for (let i = 1; i <= 10; i++) { + const optionText = formData.get(`option${i}`); + if (optionText && optionText.trim()) { + options.push({ text: optionText.trim(), votes: 0 }); + } + } + + if (options.length < 2) { + alert('Please provide at least 2 options'); + return; + } + + const newPoll = { + id: `local_poll_${Date.now()}`, + question: question, + category: category, + options: options, + totalVotes: 0, + isLocal: true + }; + + this.polls.push(newPoll); + this.saveLocalPolls(); + this.filterPolls(); + + document.querySelector('.poll-form').reset(); + document.querySelector('.options-container').innerHTML = ` + + + + + `; + + window.location.hash = '#'; + + alert('Poll created successfully!'); + } + + addOptionInput() { + const optionsContainer = document.querySelector('.options-container'); + const currentOptions = optionsContainer.querySelectorAll('.option-input').length; + + if (currentOptions >= 10) { + alert('Maximum 10 options allowed'); + return; + } + + const newInput = document.createElement('input'); + newInput.type = 'text'; + newInput.className = 'option-input'; + newInput.name = `option${currentOptions + 1}`; + newInput.placeholder = `Option ${currentOptions + 1}`; + + optionsContainer.appendChild(newInput); + } + + handleVote(form) { + const pollId = form.dataset.pollId; + const selectedOption = form.querySelector('input[type="radio"]:checked'); + + if (!selectedOption) { + alert('Please select an option'); + return; + } + + if (this.userVotes[pollId]) { + alert('You have already voted on this poll'); + return; + } + + const optionIndex = parseInt(selectedOption.value); + + const pollIndex = this.polls.findIndex(poll => poll.id === pollId); + if (pollIndex !== -1) { + this.polls[pollIndex].options[optionIndex].votes++; + this.polls[pollIndex].totalVotes++; + + this.userVotes[pollId] = optionIndex; + this.saveUserVotes(); + + if (this.polls[pollIndex].isLocal) { + this.saveLocalPolls(); + } + + this.filterPolls(); + + window.location.hash = '#'; + + alert('Thank you for voting!'); + } + } +} + +document.addEventListener('DOMContentLoaded', () => { + new PollApp(); +}); \ No newline at end of file diff --git a/style/style.css b/style/style.css index b1d5842..6ff545f 100644 --- a/style/style.css +++ b/style/style.css @@ -21,6 +21,7 @@ body { } .create-poll-btn { + margin-top: 10px; background: #4378d8; border: none; color: white; @@ -498,4 +499,429 @@ body { .poll-title { font-size: clamp(16px, 4vw, 18px); } +} + +.poll-footer { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: clamp(12px, 3vw, 15px); + padding-top: clamp(8px, 2vw, 10px); + border-top: 1px solid #f0f0f0; +} + +.vote-count { + color: #666; + font-size: clamp(15px, 4vw, 18px); + font-weight: 500; + margin: 0; +} + +.poll-category { + font-size: clamp(12px, 3vw, 14px); + color: #666; + font-weight: 500; + background: #f8f9fa; + padding: clamp(3px, 1vw, 4px) clamp(6px, 2vw, 8px); + border-radius: 4px; + text-transform: capitalize; + border: 1px solid #e9ecef; +} + +.poll-category { + font-size: clamp(12px, 3vw, 14px); + color: #666; + font-weight: 500; + background: #f8f9fa; + padding: clamp(3px, 1vw, 4px) clamp(6px, 2vw, 8px); + border-radius: 4px; + text-transform: capitalize; + border: 1px solid #e9ecef; +} + +/* Analytics Page Styles */ +.analytics-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30px; + flex-wrap: wrap; + gap: 15px; +} + +.analytics-title { + font-size: clamp(24px, 5vw, 32px); + color: #333; + margin: 0; + font-weight: 600; +} + +.nav-links { + display: flex; + gap: 15px; + flex-wrap: wrap; +} + +.nav-link { + background: #4378d8; + color: white; + text-decoration: none; + padding: 12px 20px; + border-radius: 8px; + font-weight: 500; + transition: all 0.3s ease; + font-size: clamp(14px, 3vw, 16px); + min-height: 44px; + display: flex; + align-items: center; +} + +.nav-link:hover { + background: #275cbe; + transform: translateY(-2px); +} + +.nav-link.secondary { + background: #6c757d; +} + +.nav-link.secondary:hover { + background: #545b62; +} + +.analytics-section { + margin-bottom: 40px; + background: white; + border-radius: 12px; + padding: 25px; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); +} + +.section-title { + font-size: clamp(18px, 4vw, 22px); + color: #333; + margin-bottom: 20px; + font-weight: 600; + border-bottom: 2px solid #f0f0f0; + padding-bottom: 10px; +} + +.pivot-container { + min-height: 500px; + border: 1px solid #ddd; + border-radius: 8px; + overflow: hidden; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 20px; + margin-bottom: 20px; +} + +.stat-card { + background: linear-gradient(135deg, #4378d8, #5c89e6); + color: white; + padding: 25px; + border-radius: 12px; + text-align: center; + box-shadow: 0 4px 12px rgba(67, 120, 216, 0.3); + transition: transform 0.3s ease; +} + +.stat-card:hover { + transform: translateY(-5px); +} + +.stat-number { + font-size: clamp(28px, 6vw, 36px); + font-weight: 700; + margin-bottom: 8px; +} + +.stat-label { + font-size: clamp(14px, 3vw, 16px); + opacity: 0.9; + font-weight: 500; +} + +.notification { + position: fixed; + top: 20px; + right: 20px; + z-index: 10000; + max-width: 400px; + padding: 0; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + animation: slideIn 0.3s ease; +} + +.notification.success { + background: #28a745; + color: white; +} + +.notification.error { + background: #dc3545; + color: white; +} + +.notification-content { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px 20px; +} + +.notification-close { + background: none; + border: none; + color: inherit; + font-size: 20px; + cursor: pointer; + margin-left: 10px; +} + +.voted-status { + color: #28a745; + font-weight: 500; + margin-top: 10px; + text-align: center; + font-size: 14px; +} + +.already-voted { + text-align: center; + color: #666; + font-size: 18px; + margin: 20px 0; + padding: 20px; + background: #f8f9fa; + border-radius: 8px; +} + +@keyframes slideIn { + from { transform: translateX(100%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } +} + +@media (max-width: 768px) { + .analytics-header { + flex-direction: column; + align-items: stretch; + } + + .nav-links { + justify-content: center; + } + + .stats-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 15px; + } +} + +.poll-category { + font-size: clamp(12px, 3vw, 14px); + color: #666; + font-weight: 500; + background: #f8f9fa; + padding: clamp(3px, 1vw, 4px) clamp(6px, 2vw, 8px); + border-radius: 4px; + text-transform: capitalize; + border: 1px solid #e9ecef; +} + +/* Analytics Page Styles */ +.analytics-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30px; + flex-wrap: wrap; + gap: 15px; +} + +.analytics-title { + font-size: clamp(24px, 5vw, 32px); + color: #333; + margin: 0; + font-weight: 600; +} + +.nav-links { + display: flex; + gap: 15px; + flex-wrap: wrap; +} + +.nav-link { + background: #4378d8; + color: white; + text-decoration: none; + padding: 12px 20px; + border-radius: 8px; + font-weight: 500; + transition: all 0.3s ease; + font-size: clamp(14px, 3vw, 16px); + min-height: 44px; + display: flex; + align-items: center; +} + +.nav-link:hover { + background: #275cbe; + transform: translateY(-2px); +} + +.nav-link.secondary { + background: #6c757d; +} + +.nav-link.secondary:hover { + background: #545b62; +} + +.analytics-section { + margin-bottom: 40px; + background: white; + border-radius: 12px; + padding: 25px; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); +} + +.section-title { + font-size: clamp(18px, 4vw, 22px); + color: #333; + margin-bottom: 20px; + font-weight: 600; + border-bottom: 2px solid #f0f0f0; + padding-bottom: 10px; +} + +.pivot-container { + min-height: 500px; + border: 1px solid #ddd; + border-radius: 8px; + overflow: hidden; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 20px; + margin-bottom: 20px; +} + +.stat-card { + background: linear-gradient(135deg, #4378d8, #5c89e6); + color: white; + padding: 25px; + border-radius: 12px; + text-align: center; + box-shadow: 0 4px 12px rgba(67, 120, 216, 0.3); + transition: transform 0.3s ease; +} + +.stat-card:hover { + transform: translateY(-5px); +} + +.stat-number { + font-size: clamp(28px, 6vw, 36px); + font-weight: 700; + margin-bottom: 8px; +} + +.stat-label { + font-size: clamp(14px, 3vw, 16px); + opacity: 0.9; + font-weight: 500; +} + +.notification { + position: fixed; + top: 20px; + right: 20px; + z-index: 10000; + max-width: 400px; + padding: 0; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + animation: slideIn 0.3s ease; +} + +.notification.success { + background: #28a745; + color: white; +} + +.notification.error { + background: #dc3545; + color: white; +} + +.notification-content { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px 20px; +} + +.notification-close { + background: none; + border: none; + color: inherit; + font-size: 20px; + cursor: pointer; + margin-left: 10px; +} + +.voted-status { + color: #28a745; + font-weight: 500; + margin-top: 10px; + text-align: center; + font-size: 14px; +} + +.already-voted { + text-align: center; + color: #666; + font-size: 18px; + margin: 20px 0; + padding: 20px; + background: #f8f9fa; + border-radius: 8px; +} + +@keyframes slideIn { + from { transform: translateX(100%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } +} + +@media (max-width: 768px) { + .analytics-header { + flex-direction: column; + align-items: stretch; + } + + .nav-links { + justify-content: center; + } + + .stats-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 15px; + } +} + +.stats-btn { + background: #28a745; +} + +.stats-btn:hover { + background: #218838; } \ No newline at end of file