Skip to content

Commit 545ef8c

Browse files
authored
Merge pull request #2 from pathanin-kht/Develop
feat: add favorite quotes & dark/light theme
2 parents 9dce023 + 3a294d2 commit 545ef8c

File tree

3 files changed

+303
-47
lines changed

3 files changed

+303
-47
lines changed

index.html

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,44 @@
88
<link rel="stylesheet" href="styles.css">
99
</head>
1010
<body>
11-
<div class="container">
12-
<h1>Daily Inspiration</h1>
13-
<div id="quote-box">
14-
<p id="quote-text"></p>
15-
<p id="quote-author"></p>
16-
<p id="quote-category"></p>
11+
<div class="app-container">
12+
<div class="container">
13+
<h1>Daily Inspiration</h1>
1714
<div class="button-container">
18-
<button id="new-quote">
19-
<i class="fas fa-sync-alt"></i>
20-
New Quote
21-
</button>
22-
<button class="action-btn" id="copy-quote">
23-
<i class="fas fa-copy"></i>
24-
Copy
15+
<button class="action-btn" id="toggle-theme">
16+
<i class="fas fa-moon"></i>
17+
Toggle Theme
2518
</button>
2619
</div>
20+
<div id="quote-box">
21+
<p id="quote-text"></p>
22+
<p id="quote-author"></p>
23+
<p id="quote-category"></p>
24+
<div class="button-container">
25+
<button id="new-quote">
26+
<i class="fas fa-sync-alt"></i>
27+
New Quote
28+
</button>
29+
<button class="action-btn" id="copy-quote">
30+
<i class="fas fa-copy"></i>
31+
Copy
32+
</button>
33+
<button class="action-btn" id="favorite-quote">
34+
<i class="fas fa-heart"></i>
35+
Favorite
36+
</button>
37+
</div>
38+
</div>
39+
</div>
40+
<div class="favorites-container container">
41+
<h2>Favorite Quotes</h2>
42+
<div id="favorites-list"></div>
2743
</div>
2844
</div>
45+
<button id="toggle-favorites">
46+
<i class="fas fa-heart"></i>
47+
<span class="favorite-count">0</span>
48+
</button>
2949
<div id="notification">Quote copied to clipboard!</div>
3050
<script src="script.js"></script>
3151
</body>

script.js

Lines changed: 107 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,104 @@
1-
document.addEventListener('DOMContentLoaded', () => {
2-
async function fetchQuotes() {
3-
try {
4-
const response = await fetch('quotes.json');
5-
return await response.json();
6-
} catch (error) {
7-
console.error('Error loading quotes:', error);
8-
return [];
9-
}
10-
}
1+
document.addEventListener('DOMContentLoaded', async () => {
2+
let quotes = [];
3+
let currentQuote = null;
4+
const favorites = JSON.parse(localStorage.getItem('favoriteQuotes') || '[]');
115

126
const quoteText = document.getElementById('quote-text');
137
const quoteAuthor = document.getElementById('quote-author');
148
const quoteCategory = document.getElementById('quote-category');
159
const notification = document.getElementById('notification');
10+
const favoritesList = document.getElementById('favorites-list');
1611

17-
function showNotification(message) {
12+
function showNotification(message, isError = false) {
1813
notification.textContent = message;
14+
notification.className = isError ? 'error-message' : '';
1915
notification.style.display = 'block';
2016
setTimeout(() => {
2117
notification.style.display = 'none';
2218
}, 2000);
2319
}
2420

21+
async function fetchQuotes() {
22+
try {
23+
const response = await fetch('quotes.json');
24+
if (!response.ok) {
25+
throw new Error('Failed to load quotes');
26+
}
27+
quotes = await response.json();
28+
} catch (error) {
29+
console.error('Error loading quotes:', error);
30+
showNotification('Error loading quotes. Please try again later.', true);
31+
quotes = [];
32+
}
33+
}
34+
2535
async function loadQuote() {
26-
const quotes = await fetchQuotes();
27-
if (quotes && quotes.length > 0) {
28-
const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
29-
quoteText.textContent = `"${randomQuote.Quote}"`;
30-
quoteAuthor.textContent = `- ${randomQuote.Author}`;
31-
quoteCategory.textContent = `Category: ${randomQuote.Category}`;
36+
if (quotes.length === 0) {
37+
await fetchQuotes();
38+
}
39+
40+
if (quotes.length > 0) {
41+
currentQuote = quotes[Math.floor(Math.random() * quotes.length)];
42+
quoteText.textContent = `"${currentQuote.Quote}"`;
43+
quoteAuthor.textContent = `- ${currentQuote.Author}`;
44+
quoteCategory.textContent = `Category: ${currentQuote.Category}`;
3245
}
3346
}
3447

35-
loadQuote();
48+
function updateFavoritesList() {
49+
favoritesList.innerHTML = '';
50+
favorites.forEach((quote, index) => {
51+
const quoteElement = document.createElement('div');
52+
quoteElement.className = 'favorite-quote';
53+
quoteElement.innerHTML = `
54+
<p class="favorite-quote-text">"${quote.Quote}"</p>
55+
<p class="favorite-quote-author">- ${quote.Author}</p>
56+
<button class="remove-favorite" data-index="${index}">
57+
<i class="fas fa-times"></i>
58+
</button>
59+
`;
60+
favoritesList.appendChild(quoteElement);
61+
});
62+
63+
const favoriteCount = document.querySelector('.favorite-count');
64+
favoriteCount.textContent = favorites.length;
65+
66+
document.querySelectorAll('.remove-favorite').forEach(button => {
67+
button.addEventListener('click', (e) => {
68+
const index = parseInt(e.currentTarget.dataset.index);
69+
favorites.splice(index, 1);
70+
localStorage.setItem('favoriteQuotes', JSON.stringify(favorites));
71+
updateFavoritesList();
72+
showNotification('Quote removed from favorites!');
73+
});
74+
});
75+
}
76+
77+
const toggleTheme = document.getElementById('toggle-theme');
78+
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
79+
80+
if (prefersDarkScheme.matches) {
81+
document.body.classList.add('dark-mode');
82+
}
83+
84+
toggleTheme.addEventListener('click', () => {
85+
document.body.classList.toggle('dark-mode');
86+
});
87+
88+
const toggleFavoritesBtn = document.getElementById('toggle-favorites');
89+
const favoritesContainer = document.querySelector('.favorites-container');
90+
91+
toggleFavoritesBtn.addEventListener('click', () => {
92+
const isVisible = favoritesContainer.classList.contains('visible');
93+
favoritesContainer.classList.toggle('visible');
94+
toggleFavoritesBtn.classList.toggle('active');
95+
96+
const icon = toggleFavoritesBtn.querySelector('i');
97+
icon.className = isVisible ? 'fas fa-heart' : 'fas fa-times';
98+
});
99+
100+
await loadQuote();
101+
updateFavoritesList();
36102

37103
document.getElementById('new-quote').addEventListener('click', loadQuote);
38104

@@ -42,5 +108,27 @@ document.addEventListener('DOMContentLoaded', () => {
42108
showNotification('Quote copied to clipboard!');
43109
});
44110
});
45-
});
46111

112+
document.getElementById('favorite-quote').addEventListener('click', () => {
113+
if (!currentQuote) return;
114+
115+
const quoteExists = favorites.some(q => q.Quote === currentQuote.Quote);
116+
117+
if (quoteExists) {
118+
showNotification('Quote already in favorites!', true);
119+
return;
120+
}
121+
122+
favorites.push(currentQuote);
123+
localStorage.setItem('favoriteQuotes', JSON.stringify(favorites));
124+
updateFavoritesList();
125+
showNotification('Quote added to favorites!');
126+
127+
if (favorites.length === 1) {
128+
favoritesContainer.classList.add('visible');
129+
toggleFavoritesBtn.classList.add('active');
130+
const icon = toggleFavoritesBtn.querySelector('i');
131+
icon.className = 'fas fa-times';
132+
}
133+
});
134+
});

0 commit comments

Comments
 (0)