Skip to content
Open
42 changes: 31 additions & 11 deletions Sprint-3/quote-generator/index.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title here</title>
<script defer src="quotes.js"></script>
</head>
<body>

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Quote generator app</title>
<link rel="stylesheet" href="style.css" />
<script defer src="quotes.js"></script>
</head>

<body>
<main class="quote-app">
<h1>hello there</h1>
<p id="quote"></p>
<p id="author"></p>

<div class="quote-box">
<p id="quote"></p>
<p id="author"></p>
</div>

<button type="button" id="toggle-quote">Show more</button>
<button type="button" id="new-quote">New quote</button>
</body>
</html>

<div class="auto-play-controls">
<label class="auto-play-label">
<input type="checkbox" id="auto-play-toggle" />
Auto-generate quotes
</label>
<span id="auto-play-status">auto-play: OFF</span>
</div>

</main>
</body>

</html>
69 changes: 69 additions & 0 deletions Sprint-3/quote-generator/quotes.js
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,72 @@ const quotes = [
];

// call pickFromArray with the quotes array to check you get a random quote

function getElement(id) {
const element = document.getElementById(id);
if (!element) {
throw new Error(`Element with id "${id}" not found in the HTML`);
}
return element;
}

const quoteEl = getElement("quote");
const authorEl = getElement("author");
const newQuoteBtn = getElement("new-quote");
const autoPlayToggle = getElement("auto-play-toggle");
const autoPlayStatus = getElement("auto-play-status");
const toggleQuoteBtn = getElement("toggle-quote");

newQuoteBtn.addEventListener("click", showRandomQuote);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if quoteEl, authorEl, newQuoteBtn, autoPlayToggle, autoPlayStatus or their corresponding ids are not available, missing, not spelled correctly?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If newQuoteBtn is null, then JavaScript will try to run : "null.addEventListener(...)"
This causes a TypeError (Cannot read properties of null (reading 'addEventListener')), therefore it stops the script, so the whole quote generator will break.
I fixed it with adding helper function which checks if element exist and throws a mistake if not.


let autoPlayInterval = null;

let isQuoteExpanded = false;

function updateQuoteToggleVisibility() {
if (quoteEl.scrollHeight <= quoteEl.clientHeight) {
toggleQuoteBtn.classList.add("hidden");
} else {
toggleQuoteBtn.classList.remove("hidden");
}
}

toggleQuoteBtn.addEventListener("click", () => {
if (isQuoteExpanded) {
quoteEl.classList.add("quote-clamped");
toggleQuoteBtn.innerText = "Show more";
isQuoteExpanded = false;
} else {
quoteEl.classList.remove("quote-clamped");
toggleQuoteBtn.innerText = "Show less";
isQuoteExpanded = true;
}
});

autoPlayToggle.addEventListener("click", () => {
if (autoPlayToggle.checked) {
autoPlayStatus.innerText = "auto-play: ON";
if (!autoPlayInterval) {
autoPlayInterval = setInterval(showRandomQuote, 4000);
}
} else {
autoPlayStatus.innerText = "auto-play: OFF";
clearInterval(autoPlayInterval);
autoPlayInterval = null;
}
});

function showRandomQuote() {
const randomQuote = pickFromArray(quotes);

quoteEl.innerText = randomQuote.quote;
authorEl.innerText = randomQuote.author;

isQuoteExpanded = false;
quoteEl.classList.add("quote-clamped");
toggleQuoteBtn.innerText = "Show more";

updateQuoteToggleVisibility();
}

showRandomQuote();
95 changes: 95 additions & 0 deletions Sprint-3/quote-generator/style.css

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything works well, but there is an improvement to make. I noticed as I got new quotes, some quotes are quite long, so the height of the container keeps adjusting, and I have to move my cursor everytime that happens. So, what you can do is figure out how you can keep the height of the container, so the next button stays in its position. Maybe use ellipsis and a "show more" button if the quote is too long. Be creative.
When you have cards that displays a list of content, you have to keep the height uniform.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @JaypeeLan, thanks for pointing that out! I noticed the layout shifting with longer quotes too. I updated the card so it keeps a consistent height, which stops the button from moving around. For quotes that are really long, I added an ellipsis and a “Show more / Show less” toggle, truncated to 2 lines. This way the layout stays steady, but users can still read the full quote if they want to.

Original file line number Diff line number Diff line change
@@ -1 +1,96 @@
/** Write your CSS in here **/

body {
margin: 0;
padding: 0;
min-height: 100vh;

display: flex;
justify-content: center;
align-items: center;

background: linear-gradient(135deg, #e0f7ff, #c8f7dc);
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
sans-serif;
}

.quote-app {
background: #ffffff;
padding: 2rem 2.5rem;
border-radius: 12px;

box-shadow: 0 10px 25px rgba(0, 0, 0, 0.08);

max-width: 600px;
width: 90%;
text-align: center;
}

label {
display: inline-flex;
align-items: center;
gap: 0.5rem;
margin-top: 1rem;
}

.auto-play-controls {
display: flex;
justify-content: center;
gap: 1rem;
}

#auto-play-toggle {
width: 20px;
height: 20px;
cursor: pointer;
accent-color: #16a34a;
}

#auto-play-status {
margin-top: 0;
font-size: 0.9rem;
padding: 0.25rem 0.5rem;
border-radius: 999px;
display: inline-block;
}

.auto-play-label {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to use the DRY principle between the label and the .auto-play-label? since they both have label ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I updated the CSS so the shared label styles are all in the main label rule.
.auto-play-label now only overrides what’s different (the margin and slightly smaller gap), so it’s more DRY.

gap: 0.4rem;
margin: 0;
}

.quote-box {
min-height: 5rem;
margin-bottom: 1rem;
}

#quote {
margin-bottom: 0.5rem;
line-height: 1.4;
}

.quote-clamped {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}

#author {
font-style: italic;
color: #4b5563;
}

#toggle-quote {
margin-bottom: 0.75rem;
padding: 0.3rem 0.75rem;
border-radius: 999px;
border: 1px solid #cbd5f5;
background: #e5f0ff;
font-size: 0.85rem;
cursor: pointer;
}

#toggle-quote.hidden {
display: none;
}