From 6fa5cc22c5c394fd79d8ea4ddd09e680fa84e114 Mon Sep 17 00:00:00 2001 From: Miwory Date: Sun, 17 Aug 2025 09:24:36 +0300 Subject: [PATCH] sadkawaai prediction gen 2 --- Predictions/sadkawaai/generation 2/index.html | 18 +++ Predictions/sadkawaai/generation 2/script.js | 138 ++++++++++++++++ Predictions/sadkawaai/generation 2/style.css | 148 ++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 Predictions/sadkawaai/generation 2/index.html create mode 100644 Predictions/sadkawaai/generation 2/script.js create mode 100644 Predictions/sadkawaai/generation 2/style.css diff --git a/Predictions/sadkawaai/generation 2/index.html b/Predictions/sadkawaai/generation 2/index.html new file mode 100644 index 0000000..4bff2ef --- /dev/null +++ b/Predictions/sadkawaai/generation 2/index.html @@ -0,0 +1,18 @@ +
+
+
+
+
+
+
+
+
+ +
diff --git a/Predictions/sadkawaai/generation 2/script.js b/Predictions/sadkawaai/generation 2/script.js new file mode 100644 index 0000000..c93a483 --- /dev/null +++ b/Predictions/sadkawaai/generation 2/script.js @@ -0,0 +1,138 @@ +let widgetNode = document.getElementById('widget'); +let predictionNode = document.getElementById('prediction'); +let titleNode = document.getElementById('title'); +let pointsNode = document.getElementById('points'); +let timeNode = document.getElementById('time'); +let outcomesNode = document.getElementById('outcomes'); +let templateNode = document.getElementById('outcome'); + +let willEndAt = new Date(); +let locksAt = null; +let endedAt = null; + +window.addEventListener('message', function (event) { + let message = event.detail; + widgetNode.classList.add('active'); + + switch (message.type) { + case 'prediction.end': + if (message.status == "canceled") { + predictionNode.classList.remove('active'); + predictionNode.classList.remove('ended'); + } else { + predictionNode.classList.remove('locked'); + predictionNode.classList.add('ended'); + endedAt = new Date(message.ended_at); + + let winnerNode = document.querySelector(`[outcomeId="${message.winning_outcome_id}"]`); + winnerNode.classList.add('winner'); + }; + break; + case 'prediction.lock': + predictionNode.classList.add('active'); + locksAt = new Date(); + endedAt = null; + break; + case 'prediction.begin': + case 'prediction.progress': + var totalPoints = message.outcomes.reduce((sum, outcome) => sum + (outcome.channel_points ?? 0), 0); + endedAt = null; + + if (message.id != predictionNode.getAttribute('predictionId')) { + outcomesNode.innerHTML = ''; + locksAt = new Date(message.ends_at); + + predictionNode.setAttribute('predictionId', message.id); + titleNode.innerText = message.title; + pointsNode.innerHTML = `Поинтов: ${totalPoints}`; + + predictionNode.classList.add('active'); + predictionNode.classList.remove('locked'); + predictionNode.classList.remove('ended'); + + message.outcomes.forEach(outcome => { + let root = templateNode.content.cloneNode(true); + let outcomeNode = root.querySelector('.outcome'); + let title = root.querySelector('.title'); + let points = root.querySelector('.points'); + + let outcomePoints = outcome.channel_points ?? 0; + let percent = (outcomePoints / (totalPoints || 1) * 100).toFixed(2); + + outcomeNode.setAttribute('outcomeId', outcome.id); + outcomeNode.style.setProperty('--progress', `${percent}%`); + + title.innerText = outcome.title; + points.innerText = `${percent}%`; + + outcomesNode.appendChild(root); + }); + } else { + pointsNode.innerHTML = `Поинтов: ${totalPoints}`; + message.outcomes.forEach(outcome => { + let outcomeNode = document.querySelector(`[outcomeId="${outcome.id}"]`); + let title = outcomeNode.querySelector('.title'); + let points = outcomeNode.querySelector('.points'); + + let outcomePoints = outcome.channel_points ?? 0; + let percent = (outcomePoints / (totalPoints || 1) * 100).toFixed(2); + + outcomeNode.style.setProperty('--progress', `${percent}%`); + + title.innerText = outcome.title; + points.innerText = `${percent}%`; + }); + }; + + locksAt = new Date(message.locks_at); + + break; + + default: break; + }; +}); + +function convertSecondsToMMSS(seconds) { + seconds = Math.round(seconds); + if (seconds <= 0) { + seconds = 0; + }; + const minutes = Math.floor((seconds % 3600) / 60); + const secs = seconds % 60; + const formattedMinutes = String(minutes).padStart(2, '0'); + const formattedSeconds = String(secs).padStart(2, '0'); + return `${formattedMinutes}м:${formattedSeconds}с`; +}; + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +}; + +async function updateTimer() { + let now = new Date().getTime(); + let left = (locksAt - now) / 1000; + + timeNode.innerHTML = `Осталось: ${convertSecondsToMMSS(left)}`; + + if (!endedAt && left <= 0) { + timeNode.innerHTML = `Ожидание результата`; + predictionNode.classList.add('locked'); + }; + + left = (now - endedAt) / 1000; + + if (endedAt) { + timeNode.innerHTML = `Закончилось`; + predictionNode.classList.remove('locked'); + + if (left > 5) { + predictionNode.classList.remove('active'); + predictionNode.classList.remove('ended'); + }; + }; + + await delay(100); + updateTimer(); +}; + +updateTimer(); diff --git a/Predictions/sadkawaai/generation 2/style.css b/Predictions/sadkawaai/generation 2/style.css new file mode 100644 index 0000000..9d1eadc --- /dev/null +++ b/Predictions/sadkawaai/generation 2/style.css @@ -0,0 +1,148 @@ +@font-face { + font-family: 'SF Pro Rounded'; + src: url('https://raw.githubusercontent.com/chris-short/apple-san-francisco-pro-fonts/refs/heads/main/SF-Pro-Rounded-Black.otf') format('opentype'); + font-weight: normal; + font-style: normal; + display: swap; +} + +#widget { + display: flex; + align-items: center; + justify-content: center; + visibility: hidden; +} + +#widget.active { + visibility: visible; +} + +#prediction { + position: relative; + color: #513E80; + margin-top: 70px; + margin-left: 50px; + padding: 20px 30px; + width: 900px; + border-radius: 50px; + font-family: 'SF Pro Rounded'; + font-weight: bolder; + letter-spacing: .1rem; + background-color: transparent; + transition: opacity 500ms ease-out; + font-size: 40px; + opacity: 0; + filter: drop-shadow(0 0 5px rgba(0, 0, 0, .55)) drop-shadow(0 0 8px rgba(0, 0, 0, .3)); +} + +#prediction::before { + position: absolute; + content: ''; + inset: 0; + border-radius: inherit; + background: linear-gradient(to right, #FEEDFE, #D3CBFE); + z-index: -1; +} + +#prediction::after { + position: absolute; + content: ''; + top: 0; + left: 0; + width: 75px; + transform: translate(-50%, -50%); + z-index: -3; + aspect-ratio: 89 / 92; + background-repeat: no-repeat; + background-size: cover; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='89' height='92' fill='none'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-width='4' d='M86.145 56.418S70.838 70.01 57.692 75.508c-11.473 4.8-28.311 11.993-28.311 11.993'/%3E%3Cpath fill='%23fff' d='M77.68 4.918s4.478 26.592 1.276 43.935c-3.202 17.344-15.394 21.552-25.381 35.393 0 0-6.983-7.52-9.358-13.515-3.254-8.214-4.643-11.614-2.382-20.143 4.98-18.783 35.845-45.67 35.845-45.67Z'/%3E%3Cpath fill='%23fff' d='M.58 68.138s17.822-4.301 32.316-4.866c5.471-.213 9.071 2.652 13.662 6.374 3.901 3.163 8.494 8.678 8.494 8.678s-9.933 8.055-16.627 8.617c-5.5.461-8.797-.924-13.766-3.202C14.48 79.073.58 68.139.58 68.139Z'/%3E%3C/svg%3E"); +} + +#prediction.active, +#prediction.ended +{ + opacity: 1; +} + +#prediction.locked { + opacity: 0!important; +} + +#prediction .info { + display: flex; + justify-content: space-evenly; + align-items: center; + font-size: 25px; + padding-block: 15px; +} + +#prediction #title { + word-wrap: break-word; + word-break: break-all; + text-align: center; + padding-inline: 50px; +} + +#prediction .info #points, #prediction .info #time { + text-align: center; + max-width: fit-content; +} + +#prediction #outcomes { + display: flex; + flex-direction: column; + padding-block: 15px; + padding-bottom: 25px; + font-size: 24px; + gap: 25px; +} + +#prediction #outcomes .outcome { + transition: filter 300ms ease-out; +} + +#prediction.ended #outcomes .outcome { + filter: brightness(50%); +} + +#prediction.ended #outcomes .outcome.winner { + filter: brightness(125%); +} + +#prediction #outcomes .outcome .title { + font-size: 25px; +} + +#prediction #outcomes .outcome .progressbar { + position: relative; + width: calc(100% - 130px); + height: 18px; + border-radius: 25px; +} + +#prediction #outcomes .outcome .progressbar::before { + position: absolute; + content: ''; + inset: 0; + border-radius: inherit; + background-color: #513E80; + opacity: 0.3; +} + +#prediction #outcomes .outcome .progressbar::after { + position: absolute; + content: ''; + inset: 0; + width: 100%; + max-width: var(--progress); + transition: max-width 1.5s ease-in-out; + border-radius: inherit; + background-color: #513E80; +} + +#prediction #outcomes .outcome .progressbar .points { + position: absolute; + top: 0; + right: -130px; + transform: translateY(-20%); +}