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
-
-
-
+
+
+
+
+
+
+
+
+
+ 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;
+ }
+}