diff --git a/index.html b/index.html index 09c6dc0..050713f 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,60 @@ - - - Simple HTML Page - - + + + Polling App + +
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..3a13cca --- /dev/null +++ b/script.js @@ -0,0 +1,119 @@ +clearCreateForm() +const STORAGE_KEY = 'pollsData'; +let polls = JSON.parse(localStorage.getItem(STORAGE_KEY)) || []; +let voteIndex = null; + +const pollsContainer = document.getElementById('polls'); +const modalCreate = document.getElementById('modal-create'); +const modalVote = document.getElementById('modal-vote'); + +function savePolls() { + localStorage.setItem(STORAGE_KEY, JSON.stringify(polls)); +} + +function open(elem) { elem.style.display = 'flex'; } +function close(elem) { elem.style.display = 'none'; } + +function renderPolls() { + const search = document.getElementById('search').value.toLowerCase(); + const categoryFilter = document.getElementById('category').value; + pollsContainer.innerHTML = ''; + + polls.forEach((p, i) => { + if (!p.question.toLowerCase().includes(search)) return; + if (categoryFilter !== 'all' && p.category !== categoryFilter) return; + + const card = document.createElement('div'); card.className = 'poll-card'; + const title = document.createElement('div'); title.className = 'poll-title'; title.textContent = p.question; + card.appendChild(title); + + const total = p.options.reduce((sum, o) => sum + o.count, 0) || 1; + p.options.forEach(o => { + const optEl = document.createElement('div'); optEl.className = 'option'; + const label = document.createElement('div'); label.textContent = o.text; + const barCont = document.createElement('div'); barCont.className = 'bar-container'; + const bar = document.createElement('div'); bar.className = 'bar'; + const pct = Math.round(o.count / total * 100); + bar.style.width = pct + '%'; + barCont.appendChild(bar); + const percent = document.createElement('div'); percent.className = 'option-percent'; percent.textContent = pct + '%'; + optEl.append(label, barCont, percent); + card.appendChild(optEl); + }); + + const footer = document.createElement('div'); footer.className = 'poll-footer'; + const count = document.createElement('div'); count.textContent = p.options.reduce((s, o) => s + o.count, 0) + ' votes'; + const btn = document.createElement('button'); btn.className = 'btn-vote'; btn.textContent = 'Vote'; + btn.onclick = () => openVote(i); + footer.append(count, btn); + card.appendChild(footer); + + pollsContainer.appendChild(card); + }); +} + +document.getElementById('open-create').onclick = () => open(modalCreate); +document.getElementById('close-create').onclick = () => { + close(modalCreate); + clearCreateForm(); +}; + +document.getElementById('add-option').onclick = () => { + const container = document.getElementById('option-fields'); + const idx = container.children.length + 1; + const div = document.createElement('div'); div.className = 'option-field'; + const inp = document.createElement('input'); inp.placeholder = 'Option ' + idx; + div.appendChild(inp); container.appendChild(div); +}; + +document.getElementById('submit-poll').onclick = () => { + const q = document.getElementById('poll-question').value.trim(); + const cat = document.getElementById('poll-category').value; + const optsEls = Array.from(document.querySelectorAll('#option-fields input')); + const opts = optsEls.map(i => i.value.trim()).filter(v => v); + if (!q || opts.length < 2) return; + polls.push({ question: q, options: opts.map(t => ({ text: t, count: 0 })), category: cat }); + savePolls(); + renderPolls(); + close(modalCreate); + clearCreateForm(); +}; + +function clearCreateForm() { + document.getElementById('poll-question').value = ''; + document.getElementById('poll-category').value = 'general'; + const container = document.getElementById('option-fields'); + container.innerHTML = + '
' + + '
'; +} + +function openVote(i) { + voteIndex = i; + const p = polls[i]; + document.getElementById('vote-title').textContent = p.question; + const form = document.getElementById('vote-form'); form.innerHTML = ''; + p.options.forEach((o, idx) => { + const label = document.createElement('label'); label.classList.add("radio-vote"); + const inp = document.createElement('input'); inp.type = 'radio'; inp.name = 'vote'; inp.value = idx; + label.appendChild(inp); + label.appendChild(document.createTextNode(' ' + o.text)); + form.appendChild(label); + }); + open(modalVote); +} + +document.getElementById('close-vote').onclick = () => close(modalVote); +document.getElementById('submit-vote').onclick = () => { + const sel = document.querySelector('#vote-form input[name=vote]:checked'); + if (!sel) return; + polls[voteIndex].options[+sel.value].count++; + savePolls(); + renderPolls(); + close(modalVote); +}; + +document.getElementById('search').oninput = renderPolls; +document.getElementById('category').onchange = renderPolls; + +renderPolls(); \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..9fbc7e1 --- /dev/null +++ b/style.css @@ -0,0 +1,209 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: Arial, sans-serif; + background: #a7b4d3; + padding: 20px; +} + +button { + cursor: pointer; +} + +.top-bar { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; + margin-bottom: 20px; +} + +.top-bar > * { + flex: 1; + min-width: 150px; +} + +.btn-primary { + background: #5059d5; + color: #fff; + border: none; + padding: 10px 20px; + border-radius: 6px; + font-size: 16px; +} +.btn-primary:hover, .btn-add-option:hover, .btn-submit:hover, .btn-vote:hover, .select:hover, .input:hover, #vote-form input[type="radio"]:hover{ + transform: scale(0.97); + transition: 0.2s ease; +} +.btn-primary:hover, .btn-add-option:hover, .btn-submit:hover, .btn-vote:hover{ + opacity: 0.3; +} + +.input, +.select { + padding: 10px; + width: 100%; + border: 1px solid #f0f0f4; + border-radius: 6px; +} + +.poll-list { + display: grid; + gap: 20px; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); +} + + +.poll-card { + background: #f0f0f4; + border-radius: 8px; + padding: 20px; + max-width: 320px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; +} + +.poll-title { + font-size: 18px; + margin-bottom: 15px; +} + +.option { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 10px; +} + +.bar-container { + background: #ccc; + flex: 1; + height: 8px; + border-radius: 4px; + overflow: hidden; +} + +.bar { + background: #5059d5; + height: 100%; + width: 0%; +} + +.option-percent { + width: 40px; + text-align: right; +} + +.poll-footer { + margin-top: auto; + display: flex; + justify-content: space-between; + align-items: center; +} + +.btn-vote { + background: #42b72a; + color: #fff; + border: none; + padding: 8px 16px; + border-radius: 6px; +} + +#vote-form { + display: flex; + flex-direction: column; + margin-bottom: 10px; +} + +#vote-form label { + display: flex; +} + +#vote-form input[type="radio"] { + margin: 0; + width: 20px; + margin-right: 8px; + accent-color: #5059d5; +} + +.modal-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.4); + display: none; + justify-content: center; + align-items: center; +} + +.modal { + background: #fff; + padding: 20px; + border-radius: 8px; + width: 90%; + max-width: 400px; + position: relative; +} + +.modal h2 { + margin-bottom: 15px; + font-size: 20px; +} + +.field { + margin-bottom: 10px; +} + +label { + display: block; + margin-bottom: 5px; +} + +input { + width: 100%; + padding: 8px; + border: 1px solid #f0f0f4; + border-radius: 4px; +} + +.options { + max-height: 200px; + overflow-y: auto; + margin-bottom: 10px; +} + +.option-field { + display: flex; + gap: 5px; + margin-bottom: 5px; +} + +.btn-add-option { + background: none; + border: none; + color: #5059d5; + font-size: 14px; +} + +.btn-submit { + background: #5059d5; + color: #fff; + border: none; + padding: 10px; + width: 100%; + border-radius: 6px; + font-size: 16px; +} + +.btn-close { + background: none; + border: none; + font-size: 18px; + position: absolute; + top: 10px; + right: 15px; +} \ No newline at end of file