diff --git a/dsu/index.html b/dsu/index.html index c9d3584..38b2b93 100644 --- a/dsu/index.html +++ b/dsu/index.html @@ -1,429 +1,19 @@ -` - + + + DSU Speaker Selector - - - - - -

DSURandomUserSelector

-

Welcome!

-
- - -
- Meeting Time: -
0:00
-
- - - - - - + + + +

DSURandomUserSelector

+

Welcome!

+
+ +
+ Meeting Time: +
0:00
+
+ + diff --git a/dsu/script.js b/dsu/script.js new file mode 100644 index 0000000..2521ad7 --- /dev/null +++ b/dsu/script.js @@ -0,0 +1,177 @@ +const images = [ + "./images/Jed.png", + "./images/Carlos.png", + "./images/Shahbaz.png", + "./images/Sheridan.png", + "./images/Gayane.png", + "./images/Sanjay.png", + "./images/DJ.png" +]; +const userName = document.getElementById("userName"); +const imageGrid = document.getElementById("imageGrid"); +const selectButton = document.getElementById("selectButton"); +const timerDisplay = document.getElementById("timerDisplay"); + +let timerRunning = false; +const userTimers = []; +let availableImages = [...images]; + +function init() { + images.forEach(() => { + const div = document.createElement("div"); + div.classList.add("imageContainer", "empty"); + imageGrid.appendChild(div); + }); +} + +function startMainTimer() { + timerDisplay.parentElement.classList.add("running"); + const startTimestamp = Date.now(); + const updateMainTimer = () => { + const elapsed = Math.floor((Date.now() - startTimestamp) / 1000); + const mins = Math.floor(elapsed / 60); + const secs = elapsed % 60; + timerDisplay.textContent = `${mins}:${secs.toString().padStart(2, "0")}`; + }; + updateMainTimer(); + const mainTimerId = setInterval(updateMainTimer, 1000); + timerDisplay.dataset.timerId = mainTimerId; + timerRunning = true; +} + +function displaySpeaker(imagePath) { + const name = imagePath.split("/").pop().split(".")[0]; + userName.textContent = name; + if (!timerRunning) startMainTimer(); + selectButton.textContent = "Next Speaker"; + + const container = document.querySelector("div.imageContainer.empty"); + container.id = name; + container.classList.remove("empty"); + container.classList.add("selected", "filled"); + + const img = document.createElement("img"); + img.src = imagePath; + img.alt = name; + img.classList.add("imageItem"); + + const timerDiv = document.createElement("div"); + timerDiv.classList.add("timer"); + timerDiv.textContent = "0:00"; + + container.appendChild(img); + container.appendChild(timerDiv); + + // Resume timer on click + container.addEventListener("click", () => { + removeSelected(); + container.classList.add("selected"); + const prevTime = userTimers.find(u => u.user === name)?.time || 0; + const resumeStart = Date.now() - prevTime * 1000; + const updateResume = () => { + const elapsed = Math.floor((Date.now() - resumeStart) / 1000); + const mins = Math.floor(elapsed / 60); + const secs = elapsed % 60; + timerDiv.textContent = `${mins}:${secs.toString().padStart(2, "0")}`; + }; + updateResume(); + const resumeId = setInterval(updateResume, 1000); + container.dataset.timerId = resumeId; + if (selectButton.textContent === "End Meeting") { + selectButton.classList.remove("reset"); + selectButton.textContent = "Done!"; + } + }); + + // Remove used image from list + availableImages = availableImages.filter(p => p !== imagePath); + + // Start new speaker timer + const start = Date.now(); + const updateTimer = () => { + const elapsed = Math.floor((Date.now() - start) / 1000); + const mins = Math.floor(elapsed / 60); + const secs = elapsed % 60; + timerDiv.textContent = `${mins}:${secs.toString().padStart(2, "0")}`; + }; + updateTimer(); + const timerId = setInterval(updateTimer, 1000); + container.dataset.timerId = timerId; + + if (availableImages.length === 0) { + selectButton.classList.add("reset"); + selectButton.textContent = "Done!"; + } +} + +function removeSelected() { + const sel = imageGrid.querySelector("div.selected"); + if (!sel) return; + sel.classList.remove("selected"); + clearInterval(parseInt(sel.dataset.timerId)); + const name = sel.id; + const time = toSeconds(sel.querySelector(".timer").textContent); + const idx = userTimers.findIndex(u => u.user === name); + if (idx !== -1) userTimers[idx].time = time; + else userTimers.push({ user: name, time }); +} + +function toSeconds(str) { + const [m, s] = str.split(":").map(Number); + return m * 60 + s; +} + +function selectRandomImage() { + removeSelected(); + const idx = Math.floor(Math.random() * availableImages.length); + displaySpeaker(availableImages[idx]); +} + +function endSpeakers() { + userName.textContent = "Done!"; + selectButton.textContent = "End Meeting"; + imageGrid.classList.add("done"); + removeSelected(); +} + +function endMeeting() { + userName.textContent = "Done!"; + selectButton.textContent = "Reset Meeting"; + selectButton.classList.add("reset"); + imageGrid.classList.add("finished"); + removeSelected(); + timerDisplay.parentElement.classList.remove("running"); + if (timerDisplay.dataset.timerId) clearInterval(parseInt(timerDisplay.dataset.timerId)); + timerDisplay.dataset.timerId = null; + timerRunning = false; +} + +function resetMeeting() { + imageGrid.classList.remove("finished"); + availableImages = [...images]; + clearTimers(); + document.querySelectorAll(".imageContainer").forEach(div => { + div.classList.remove("selected", "filled"); + div.classList.add("empty"); + div.innerHTML = ""; + }); + selectButton.textContent = "Start Meeting"; + selectButton.classList.remove("reset"); +} + +function clearTimers() { + timerDisplay.parentElement.classList.remove("running"); + timerDisplay.textContent = "0:00"; + document.querySelectorAll(".imageContainer").forEach(div => { + if (div.dataset.timerId) clearInterval(parseInt(div.dataset.timerId)); + }); +} + +selectButton.addEventListener("click", () => { + if (availableImages.length > 0) selectRandomImage(); + else if (selectButton.textContent === "Done!") endSpeakers(); + else if (selectButton.textContent === "End Meeting") endMeeting(); + else if (selectButton.textContent === "Reset Meeting") resetMeeting(); +}); + +init(); \ No newline at end of file diff --git a/dsu/style.css b/dsu/style.css new file mode 100644 index 0000000..fc76936 --- /dev/null +++ b/dsu/style.css @@ -0,0 +1,144 @@ +html { + background-color: #333; +} +body { + font-family: sans-serif; + text-align: center; + background: #333; + background: linear-gradient(180deg, #333, transparent, #333); + color: #fff; +} +h1 { + font-weight: 300; + font-size: 28px; +} +h1 span { + font-weight: 400; + color: #aaaaaacc; +} +#userName { + font-size: 44px; + color: #fff; + font-weight: 400; + margin: 0; +} +#imageGrid { + display: flex; + justify-content: center; + gap: 10px; + margin: 50px auto; + border: solid 1px #666; + padding: 20px; + max-width: 1200px; +} +#imageGrid div.imageContainer { + width: 160px; + height: 220px; + border: solid 1px #757575; + background: linear-gradient(45deg, #000, transparent); +} +#imageGrid > div { + opacity: 0.33; + transition: all 0.3s ease; +} +#imageGrid.done > div { + opacity: 1; +} +#imageGrid.finished > div { + opacity: 0.75; +} +#imageGrid div.selected { + opacity: 1; + border: solid 1px #999; + box-shadow: 0 0 16px #000; + transform: scale(1.25); + font-weight: 300; + position: absolute; + z-index: 2; + border-radius: 20px; +} +#imageGrid div.selected img { + border-radius: 20px 20px 0 0; +} +#imageGrid .selected { + animation: spinHorizontal 0.8s ease-in-out; +} +@keyframes spinHorizontal { + from { + transform: rotateX(270deg) scale(0.05); + } + to { + transform: rotateX(0) scale(1.25); + } +} +.imageItem { + width: 160px; + height: 180px; + object-fit: cover; + cursor: pointer; +} +.timer { + font-size: 28px; + font-family: monospace; + background: #000; + color: #999; + margin-top: -5px; + padding: 4px; + border-radius: 0 0 20px 20px; +} +#selectButton { + padding: 10px 20px; + font-size: 16px; + background-color: #4CAF50; + color: #fff; + border: none; + cursor: pointer; + border-radius: 5px; +} +#selectButton.reset { + background-color: #2d6a2f; +} +#mainTimer { + display: none; + color: #666; + margin-top: 50px; + font-weight: 300; +} +#mainTimer.running { + display: block; +} +#mainTimer.finished, +#mainTimer.finished > #timerDisplay { + color: #ddd; +} +#timerDisplay { + color: #404040; + font-size: 100px; + font-weight: 600; + text-shadow: 1px 1px 0 #666; +} +.imageContainer.empty { + font-size: 200px; + color: #ffffff22; +} +.imageContainer.empty:first-child:after { + content: 'J'; +} +.imageContainer.empty:nth-child(2):after { + content: 'A'; +} +.imageContainer.empty:nth-child(3):after { + content: 'V'; +} +.imageContainer.empty:nth-child(4):after { + content: 'E'; +} +.imageContainer.empty:nth-child(5):after { + content: 'L'; +} +.imageContainer.empty:nth-child(6):after { + content: 'I'; +} +.imageContainer.empty:nth-child(7):after { + content: 'N'; +}