diff --git a/Sprint-3/quote-generator/index.html b/Sprint-3/quote-generator/index.html index 30b434bcf..0bf7e3472 100644 --- a/Sprint-3/quote-generator/index.html +++ b/Sprint-3/quote-generator/index.html @@ -1,15 +1,33 @@ - + - Title here - + Quote Generator App + -

hello there

-

-

- +
+
+

Quote Generator

+
+
+

" "

+

-- --

+
+
+
+ +
+
+ + OFF +
+
+
+ diff --git a/Sprint-3/quote-generator/package.json b/Sprint-3/quote-generator/package.json index 0f6f98917..8a9bdb901 100644 --- a/Sprint-3/quote-generator/package.json +++ b/Sprint-3/quote-generator/package.json @@ -4,7 +4,7 @@ "license": "CC-BY-SA-4.0", "description": "You must update this package", "scripts": { - "test": "jest --config=../jest.config.js quote-generator" + "test": "jest --env=jsdom" }, "repository": { "type": "git", @@ -13,5 +13,11 @@ "bugs": { "url": "https://github.com/CodeYourFuture/CYF-Coursework-Template/issues" }, - "homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme" + "homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme", + "dependencies": { + "jsdom": "^20.0.3" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.9.1" + } } diff --git a/Sprint-3/quote-generator/quotes.js b/Sprint-3/quote-generator/quotes.js index 4a4d04b72..b184631da 100644 --- a/Sprint-3/quote-generator/quotes.js +++ b/Sprint-3/quote-generator/quotes.js @@ -15,11 +15,6 @@ // --------------- // pickFromArray(['a','b','c','d']) // maybe returns 'c' -// You don't need to change this function -function pickFromArray(choices) { - return choices[Math.floor(Math.random() * choices.length)]; -} - // A list of quotes you can use in your app. // DO NOT modify this array, otherwise the tests may break! const quotes = [ @@ -491,3 +486,75 @@ const quotes = [ ]; // call pickFromArray with the quotes array to check you get a random quote + +// Picks a random quote object from the quotes array +function pickFromArray(quotes) { + const randomIndex = Math.floor(Math.random() * quotes.length); + return quotes[randomIndex]; +} + +// Renders a quote object into the DOM +function renderQuote(quote) { + const quoteEl = document.getElementById("quote"); + const authorEl = document.getElementById("author"); + + if (!quoteEl || !authorEl || !quote) return; + + quoteEl.textContent = quote.quote; + authorEl.textContent = quote.author; +} + +// Sets up the application, event listeners, and initial state +function setupQuoteApp() { + const button = document.getElementById("new-quote"); + const autoplayCheckbox = document.getElementById("autoplay"); + const autoplayStatus = document.getElementById("autoplay-status"); + + if (!button || !autoplayCheckbox || !autoplayStatus) return; + + let autoplayInterval = null; + + // Show first quote on page load + renderQuote(pickFromArray(quotes)); + + // Handles generating and rendering a new quote + function handleNewQuote() { + renderQuote(pickFromArray(quotes)); + } + + // Button click generates a new quote + button.addEventListener("click", handleNewQuote); + + // Toggle autoplay feature + autoplayCheckbox.addEventListener("change", () => { + if (autoplayCheckbox.checked) { + // Start auto-changing quotes every 5 seconds + autoplayInterval = setInterval(handleNewQuote, 5000); + autoplayStatus.textContent = "ON"; + + // Apply ON styling via CSS class + autoplayStatus.classList.add("autoplay-on"); + autoplayStatus.classList.remove("autoplay-off"); + } else { + // Stop auto-changing quotes + clearInterval(autoplayInterval); + autoplayInterval = null; + + autoplayStatus.textContent = "OFF"; + + // Apply OFF styling via CSS class + autoplayStatus.classList.add("autoplay-off"); + autoplayStatus.classList.remove("autoplay-on"); + } + }); +} + +// Initialize app only when DOM is fully loaded (browser environment) +if (typeof window !== "undefined") { + window.addEventListener("DOMContentLoaded", setupQuoteApp); +} + +// Export function for Jest testing environment +if (typeof module !== "undefined") { + module.exports = pickFromArray; +} diff --git a/Sprint-3/quote-generator/quotes.test.js b/Sprint-3/quote-generator/quotes.test.js index f7b128bf7..d0631cb58 100644 --- a/Sprint-3/quote-generator/quotes.test.js +++ b/Sprint-3/quote-generator/quotes.test.js @@ -2,6 +2,9 @@ There are some Tests in this file that will help you work out if your code is working. */ +require("@testing-library/jest-dom"); +// @jest-environment jsdom +const pickFromArray = require("./quotes.js"); const path = require("path"); const { JSDOM } = require("jsdom"); diff --git a/Sprint-3/quote-generator/style.css b/Sprint-3/quote-generator/style.css index 63cedf2d2..a02b2cff7 100644 --- a/Sprint-3/quote-generator/style.css +++ b/Sprint-3/quote-generator/style.css @@ -1 +1,152 @@ -/** Write your CSS in here **/ +/* Reset */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; +} + +body { + min-height: 100vh; + background: #abd5e9; + display: flex; + justify-content: center; + align-items: center; + padding: 15px; +} + +.container { + background: rgb(206, 202, 202); + padding: 10px; + border-radius: 16px; + width: 100%; + max-width: 420px; + text-align: center; + border: 1px solid rgba(255, 255, 255, 0.3); + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2); + display: flex; + flex-direction: column; + min-height: 450px; +} + +.header { + flex: 0 0 25%; /* 25% of container height */ + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 15px; +} + +.header h1 { + font-size: 1.8rem; + color: #333; +} + +.quote-box { + flex: 1 0 50%; /* take remaining middle space */ + background: #f4f4f4; + padding: 10px; + border-radius: 12px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin: 10px 0; + + min-height: 100px; + transition: all 0.3s ease; + word-wrap: break-word; + text-align: center; +} + +.quote-box p { + margin: 0; + font-size: 1rem; + line-height: 1.4; +} + +.bottom-controls { + flex: 0 0 25%; + display: flex; + flex-direction: column; + justify-content: center; + gap: 10px; + margin-bottom: 0px; +} + +.button button { + width: 100%; + padding: 10px; + font-size: large; + border: none; + border-radius: 10px; + background: rgb(3, 73, 195); + color: #fff; + cursor: pointer; + transition: 0.3s ease; +} + +.button button:hover { + background: #4259c8; + transform: scale(1.03); + font-weight: bold; +} + +.autoplay-container { + display: flex; + justify-content: center; + align-items: center; + gap: 10px; +} + +.autoplay-container label { + display: flex; + align-items: center; + gap: 5px; + cursor: pointer; +} + +.autoplay-container input[type="checkbox"] { + width: 18px; + height: 18px; + cursor: pointer; +} + +.autoplay-on { + color: #4caf50; + font-weight: bold; +} + +.autoplay-off { + color: brown; + font-weight: bold; +} + +/* Responsive */ +@media (min-width: 600px) { + .container { + padding: 40px 35px; + } + .header h1 { + font-size: 2rem; + } + .quote-box p { + font-size: 1.1rem; + } +} + +@media (min-width: 992px) { + .container { + max-width: 500px; + } + .header h1 { + font-size: 2.2rem; + } + .quote-box p { + font-size: 1.2rem; + } + .button button { + width: auto; + padding: 12px 25px; + } +}