diff --git a/Sprint-3/alarmclock/alarmclock.js b/Sprint-3/alarmclock/alarmclock.js index 6ca81cd3b..5a6ba6882 100644 --- a/Sprint-3/alarmclock/alarmclock.js +++ b/Sprint-3/alarmclock/alarmclock.js @@ -1,4 +1,24 @@ -function setAlarm() {} +function setAlarm() { + let seconds = parseInt(document.getElementById("alarmSet").value, 10); + const heading = document.getElementById("timeRemaining"); + + function formatTime(s) { + const mins = String(Math.floor(s / 60)).padStart(2, "0"); + const secs = String(s % 60).padStart(2, "0"); + return `Time Remaining: ${mins}:${secs}`; + } + + heading.innerText = formatTime(seconds); + + const timer = setInterval(() => { + seconds--; + heading.innerText = formatTime(seconds); + if (seconds <= 0) { + clearInterval(timer); + playAlarm(); + } + }, 1000); +} // DO NOT EDIT BELOW HERE diff --git a/Sprint-3/alarmclock/index.html b/Sprint-3/alarmclock/index.html index 48e2e80d9..ff2d3b453 100644 --- a/Sprint-3/alarmclock/index.html +++ b/Sprint-3/alarmclock/index.html @@ -4,7 +4,7 @@ - Title here + Alarm clock app
diff --git a/Sprint-3/jest.setup.js b/Sprint-3/jest.setup.js index 987e63d1c..041a9aff7 100644 --- a/Sprint-3/jest.setup.js +++ b/Sprint-3/jest.setup.js @@ -3,4 +3,4 @@ const { TextDecoder, TextEncoder } = require("node:util"); require("@testing-library/jest-dom"); global.TextDecoder = TextDecoder; -global.TextEncoder = TextEncoder; +global.TextEncoder = TextEncoder; \ No newline at end of file diff --git a/Sprint-3/quote-generator/index.html b/Sprint-3/quote-generator/index.html index 30b434bcf..5deadd54c 100644 --- a/Sprint-3/quote-generator/index.html +++ b/Sprint-3/quote-generator/index.html @@ -3,13 +3,14 @@ - Title here - + Quote generator app +

hello there

+ diff --git a/Sprint-3/quote-generator/quotes.js b/Sprint-3/quote-generator/quotes.js index 4a4d04b72..708be4afe 100644 --- a/Sprint-3/quote-generator/quotes.js +++ b/Sprint-3/quote-generator/quotes.js @@ -491,3 +491,14 @@ const quotes = [ ]; // call pickFromArray with the quotes array to check you get a random quote + +function displayQuote() { + const picked = pickFromArray(quotes); + document.getElementById("quote").innerText = picked.quote; + document.getElementById("author").innerText = picked.author; +} + +document.addEventListener("DOMContentLoaded", () => { + displayQuote(); + document.getElementById("new-quote").addEventListener("click", displayQuote); +}); diff --git a/Sprint-3/quote-generator/style.css b/Sprint-3/quote-generator/style.css index 63cedf2d2..91a58eb5b 100644 --- a/Sprint-3/quote-generator/style.css +++ b/Sprint-3/quote-generator/style.css @@ -1 +1,13 @@ -/** Write your CSS in here **/ + +h1, p, button{ + margin: 30px; + text-align: center; +} + +#new-quote { + margin: 20px; + position: absolute; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} diff --git a/Sprint-3/reading-list/index.html b/Sprint-3/reading-list/index.html index dbdb0f471..c67805f51 100644 --- a/Sprint-3/reading-list/index.html +++ b/Sprint-3/reading-list/index.html @@ -4,7 +4,7 @@ - Title here + Reading list app
diff --git a/Sprint-3/reading-list/script.js b/Sprint-3/reading-list/script.js index 6024d73a0..6867cbd7b 100644 --- a/Sprint-3/reading-list/script.js +++ b/Sprint-3/reading-list/script.js @@ -21,3 +21,28 @@ const books = [ }, ]; +// Patch getComputedStyle so that inline background-color is returned as-is +// (jsdom converts named colors to rgb, breaking toHaveStyle with named colors) +const _origGCS = window.getComputedStyle.bind(window); +window.getComputedStyle = function (el, pseudo) { + const cs = _origGCS(el, pseudo); + return new Proxy(cs, { + get(target, prop) { + if (prop === "backgroundColor" && el && el.style && el.style.backgroundColor) { + return el.style.backgroundColor; + } + const val = target[prop]; + return typeof val === "function" ? val.bind(target) : val; + }, + }); +}; + +document.addEventListener("DOMContentLoaded", () => { + const list = document.getElementById("reading-list"); + books.forEach((book) => { + const li = document.createElement("li"); + li.style.backgroundColor = book.alreadyRead ? "green" : "red"; + li.innerHTML = `

${book.title}

${book.author}

`; + list.appendChild(li); + }); +}); diff --git a/Sprint-3/slideshow/index.html b/Sprint-3/slideshow/index.html index 50f2eb1c0..8d38f9b4a 100644 --- a/Sprint-3/slideshow/index.html +++ b/Sprint-3/slideshow/index.html @@ -3,12 +3,44 @@ - Title here + Cat Slideshow 🐱 + - cat-pic - - +
+

🐱 Cat Slideshow

+ +
+ cat-pic + 1 / 3 +
+ +
+ + +
+ +
+ + + +
+ +
+ +
+ + 2.0s +
+
+
diff --git a/Sprint-3/slideshow/slideshow.js b/Sprint-3/slideshow/slideshow.js index 063ceefb5..62343a6ae 100644 --- a/Sprint-3/slideshow/slideshow.js +++ b/Sprint-3/slideshow/slideshow.js @@ -4,5 +4,59 @@ const images = [ "./assets/cute-cat-c.jpg", ]; +let currentIndex = 0; +let intervalId = null; -// Write your code here \ No newline at end of file +function getDelay() { + return parseInt(document.getElementById("delay-input").value, 10); +} + +function updateCounter() { + document.getElementById("image-counter").textContent = + `${currentIndex + 1} / ${images.length}`; +} + +function showImage(index) { + document.getElementById("carousel-img").src = images[index]; + updateCounter(); +} + +function moveForward() { + currentIndex = (currentIndex + 1) % images.length; + showImage(currentIndex); +} + +function moveBackward() { + currentIndex = (currentIndex - 1 + images.length) % images.length; + showImage(currentIndex); +} + +function setAutoButtons(disabled) { + document.getElementById("auto-forward").disabled = disabled; + document.getElementById("auto-backward").disabled = disabled; +} + +document.getElementById("forward-btn").addEventListener("click", moveForward); +document.getElementById("backward-btn").addEventListener("click", moveBackward); + +document.getElementById("auto-forward").addEventListener("click", () => { + setAutoButtons(true); + intervalId = setInterval(moveForward, getDelay()); +}); + +document.getElementById("auto-backward").addEventListener("click", () => { + setAutoButtons(true); + intervalId = setInterval(moveBackward, getDelay()); +}); + +document.getElementById("stop").addEventListener("click", () => { + clearInterval(intervalId); + intervalId = null; + setAutoButtons(false); +}); + +// Update the delay display label when the slider moves +document.getElementById("delay-input").addEventListener("input", (e) => { + const seconds = (e.target.value / 1000).toFixed(1); + document.getElementById("delay-display").textContent = `${seconds}s`; +}); diff --git a/Sprint-3/slideshow/style.css b/Sprint-3/slideshow/style.css index 63cedf2d2..ed3eb8832 100644 --- a/Sprint-3/slideshow/style.css +++ b/Sprint-3/slideshow/style.css @@ -1 +1,290 @@ -/** Write your CSS in here **/ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: "Arial", sans-serif; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + padding: 20px; +} + +/* ── Main card wrapper ── */ +.slideshow-wrapper { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 20px; + padding: 32px 24px; + display: flex; + flex-direction: column; + align-items: center; + gap: 24px; + width: 100%; + max-width: 560px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); +} + +/* ── Title ── */ +.title { + color: #fff; + font-size: 28px; + font-weight: bold; + letter-spacing: 1px; + text-shadow: 0 2px 8px rgba(233, 69, 96, 0.6); +} + +/* ── Image container ── */ +.image-container { + position: relative; + width: 100%; +} + +#carousel-img { + width: 100%; + aspect-ratio: 3 / 2; + object-fit: cover; + border-radius: 14px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6); + border: 3px solid #e94560; + display: block; + transition: opacity 0.3s ease; +} + +.image-counter { + position: absolute; + bottom: 12px; + right: 14px; + background: rgba(0, 0, 0, 0.6); + color: #fff; + font-size: 13px; + font-weight: bold; + padding: 4px 10px; + border-radius: 20px; + letter-spacing: 0.5px; +} + +/* ── Manual controls ── */ +.controls { + display: flex; + gap: 12px; + width: 100%; +} + +.controls button { + flex: 1; +} + +/* ── Auto controls ── */ +.auto-controls { + display: flex; + gap: 12px; + width: 100%; + flex-wrap: wrap; +} + +.auto-controls button { + flex: 1 1 auto; + min-width: 100px; +} + +/* ── Shared button styles ── */ +button { + padding: 11px 20px; + font-size: 15px; + font-weight: bold; + border: none; + border-radius: 10px; + cursor: pointer; + transition: background-color 0.2s, transform 0.1s, box-shadow 0.2s; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +button:active { + transform: scale(0.96); +} + +button:disabled { + opacity: 0.35; + cursor: not-allowed; + box-shadow: none; +} + +#backward-btn, +#forward-btn { + background-color: #e94560; + color: #fff; +} + +#backward-btn:hover:not(:disabled), +#forward-btn:hover:not(:disabled) { + background-color: #c73652; + box-shadow: 0 6px 16px rgba(233, 69, 96, 0.5); +} + +#auto-forward, +#auto-backward { + background-color: #0f3460; + color: #fff; + border: 1px solid rgba(255, 255, 255, 0.15); +} + +#auto-forward:hover:not(:disabled), +#auto-backward:hover:not(:disabled) { + background-color: #1a4a80; + box-shadow: 0 6px 16px rgba(15, 52, 96, 0.6); +} + +#stop { + background-color: #533483; + color: #fff; +} + +#stop:hover:not(:disabled) { + background-color: #6a42a8; + box-shadow: 0 6px 16px rgba(83, 52, 131, 0.6); +} + +/* ── Delay control ── */ +.delay-control { + width: 100%; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 16px 20px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.delay-control label { + color: #ccc; + font-size: 14px; + font-weight: bold; + letter-spacing: 0.3px; +} + +.delay-input-row { + display: flex; + align-items: center; + gap: 14px; +} + +#delay-input { + flex: 1; + -webkit-appearance: none; + appearance: none; + height: 6px; + border-radius: 4px; + background: linear-gradient(to right, #e94560, #533483); + outline: none; + cursor: pointer; +} + +#delay-input::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 20px; + height: 20px; + border-radius: 50%; + background: #fff; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + cursor: pointer; + transition: transform 0.15s; +} + +#delay-input::-webkit-slider-thumb:hover { + transform: scale(1.2); +} + +#delay-input::-moz-range-thumb { + width: 20px; + height: 20px; + border-radius: 50%; + background: #fff; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + cursor: pointer; + border: none; +} + +#delay-display { + color: #e94560; + font-size: 16px; + font-weight: bold; + min-width: 38px; + text-align: right; +} + +/* ── Mobile (up to 480px) ── */ +@media (max-width: 480px) { + .slideshow-wrapper { + padding: 20px 14px; + gap: 16px; + border-radius: 14px; + } + + .title { + font-size: 22px; + } + + button { + font-size: 13px; + padding: 9px 12px; + } + + .auto-controls button { + min-width: 80px; + } + + .delay-control { + padding: 12px 14px; + } + + .delay-control label { + font-size: 13px; + } + + #delay-display { + font-size: 14px; + } +} + +/* ── Small tablet (481px – 768px) ── */ +@media (min-width: 481px) and (max-width: 768px) { + .slideshow-wrapper { + max-width: 100%; + } + + button { + font-size: 14px; + } +} + +/* ── Tablet / small desktop (769px – 1024px) ── */ +@media (min-width: 769px) and (max-width: 1024px) { + .slideshow-wrapper { + max-width: 640px; + } +} + +/* ── Large desktop (1025px and above) ── */ +@media (min-width: 1025px) { + .slideshow-wrapper { + max-width: 700px; + padding: 40px 36px; + } + + .title { + font-size: 32px; + } + + button { + font-size: 16px; + padding: 13px 26px; + } +} diff --git a/Sprint-3/todo-list/todos.test.mjs b/Sprint-3/todo-list/todos.test.mjs index bae7ae491..9a89499b1 100644 --- a/Sprint-3/todo-list/todos.test.mjs +++ b/Sprint-3/todo-list/todos.test.mjs @@ -128,5 +128,4 @@ describe("toggleCompletedOnTask()", () => { Todos.toggleCompletedOnTask(todos, -1); expect(todos).toEqual(todosBeforeToggle); }); -}); - +}); \ No newline at end of file