Skip to content

Commit fb834a7

Browse files
authored
Updated template to support searching in reviews page (#252)
* updated template to support searching in reviews page * don't update review count on searching
1 parent 37bbede commit fb834a7

File tree

3 files changed

+399
-24
lines changed

3 files changed

+399
-24
lines changed

public/reviews.html

Lines changed: 133 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,84 @@
115115
max-width: 100%;
116116
overflow: hidden;
117117
}
118+
119+
.header {
120+
text-align: center;
121+
max-width: 800px;
122+
margin: 8px auto;
123+
}
124+
125+
@keyframes fadeIn {
126+
from { opacity: 0; transform: translateY(5px); }
127+
to { opacity: 1; transform: translateY(0); }
128+
}
129+
130+
@keyframes fadeOut {
131+
from { opacity: 1; transform: translateY(0); }
132+
to { opacity: 0; transform: translateY(-5px); }
133+
}
134+
135+
/* Style for the search box */
136+
.search-box {
137+
width: 95%;
138+
max-width: 600px;
139+
padding: 15px;
140+
margin: 10px auto;
141+
display: block;
142+
border-radius: 8px;
143+
border: 1px solid #ccc;
144+
font-size: 16px;
145+
outline: none;
146+
margin-left: auto;
147+
margin-right: auto;
148+
transition: border-color 0.3s ease, box-shadow 0.3s ease;
149+
}
150+
151+
.search-box:focus {
152+
border-color: #007bff;
153+
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
154+
}
155+
156+
/* Style for the review count */
157+
.review-count {
158+
font-size: 18px;
159+
font-weight: bold;
160+
color: #333;
161+
padding: 8px;
162+
background: #f1f1f1;
163+
border-radius: 8px;
164+
display: inline-block;
165+
margin-left: 10px;
166+
}
167+
168+
/* Style for the action bar */
169+
.action-bar {
170+
width: 90%;
171+
max-width: 800px;
172+
text-align: center;
173+
display: flex;
174+
justify-content: center;
175+
gap: 2em;
176+
margin: 0 auto 1em auto;
177+
align-items: center;
178+
flex-wrap: wrap;
179+
}
180+
181+
118182
</style>
119183
</head>
120184
<body>
121185
<div class="container">
122-
<h1>App Privacy Policy Generator's 📖 Guest Book 🙇🏻‍♂️</h1>
123-
<h3>
124-
<a href="/" class="link">Back to Web App ↩️</a> |
125-
<a href="https://ko-fi.com/A443EQ6" target="_blank" class="link"
126-
>Buy Me a Coffee ☕️</a
127-
>
128-
</h3>
129-
<div class="review-columns">
186+
<div class="header">
187+
<h1>📖 App Privacy Policy Generator's Guest Book 🙇🏻‍♂️</h1>
188+
<div class="action-bar">
189+
<a href="/" class="link">↩️ Back to Web App</a>
190+
<a href="https://ko-fi.com/A443EQ6" target="_blank" class="link">☕️ Buy Me a Coffee</a>
191+
<span class="review-count">📊 Total Reviews: <span id="reviewCount">450</span></span>
192+
</div>
193+
<input type="text" id="searchInput" class="search-box" placeholder="Search reviews..." />
194+
</div>
195+
<div class="review-columns" id="reviewContainer">
130196
<a
131197
href="https://github.com/nisrulz/app-privacy-policy-generator/issues/65"
132198
target="_blank"
@@ -7680,5 +7746,64 @@ <h1>Amazing tool</h1></div>
76807746
</a>
76817747
</div>
76827748
</div>
7749+
7750+
<script>
7751+
document.addEventListener("DOMContentLoaded", function () {
7752+
const reviewCountElement = document.getElementById("reviewCount");
7753+
const searchInput = document.getElementById("searchInput");
7754+
7755+
function getReviewCards() {
7756+
return document.querySelectorAll(".review-card:not(.header-card)");
7757+
}
7758+
7759+
function updateReviewCount(count) {
7760+
reviewCountElement.textContent = typeof count === "number" ? count : getReviewCards().length;
7761+
}
7762+
7763+
function showCard(card, show) {
7764+
card.style.display = show ? "inline-block" : "none";
7765+
}
7766+
7767+
function filterReviews(query) {
7768+
const cards = getReviewCards();
7769+
query = query.trim().toLowerCase();
7770+
let visible = 0;
7771+
// Process cards in chunks to avoid blocking the UI
7772+
let index = 0;
7773+
const chunkSize = 100; // Adjust based on performance
7774+
function processChunk() {
7775+
const end = Math.min(index + chunkSize, cards.length);
7776+
for (; index < end; index++) {
7777+
const card = cards[index];
7778+
const match = card.innerText.toLowerCase().includes(query);
7779+
showCard(card, match);
7780+
if (match) visible++;
7781+
}
7782+
if (index < cards.length) {
7783+
requestAnimationFrame(processChunk);
7784+
}
7785+
}
7786+
processChunk();
7787+
}
7788+
7789+
function debounce(fn, delay) {
7790+
let timer;
7791+
return function (...args) {
7792+
clearTimeout(timer);
7793+
timer = setTimeout(() => fn.apply(this, args), delay);
7794+
};
7795+
}
7796+
7797+
function setupSearch() {
7798+
searchInput.addEventListener("input", debounce(function () {
7799+
filterReviews(searchInput.value);
7800+
}, 200));
7801+
}
7802+
7803+
// Initialize
7804+
updateReviewCount();
7805+
setupSearch();
7806+
});
7807+
</script>
76837808
</body>
76847809
</html>

tools/reviews-page-generator/reviews.html

Lines changed: 133 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,84 @@
115115
max-width: 100%;
116116
overflow: hidden;
117117
}
118+
119+
.header {
120+
text-align: center;
121+
max-width: 800px;
122+
margin: 8px auto;
123+
}
124+
125+
@keyframes fadeIn {
126+
from { opacity: 0; transform: translateY(5px); }
127+
to { opacity: 1; transform: translateY(0); }
128+
}
129+
130+
@keyframes fadeOut {
131+
from { opacity: 1; transform: translateY(0); }
132+
to { opacity: 0; transform: translateY(-5px); }
133+
}
134+
135+
/* Style for the search box */
136+
.search-box {
137+
width: 95%;
138+
max-width: 600px;
139+
padding: 15px;
140+
margin: 10px auto;
141+
display: block;
142+
border-radius: 8px;
143+
border: 1px solid #ccc;
144+
font-size: 16px;
145+
outline: none;
146+
margin-left: auto;
147+
margin-right: auto;
148+
transition: border-color 0.3s ease, box-shadow 0.3s ease;
149+
}
150+
151+
.search-box:focus {
152+
border-color: #007bff;
153+
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
154+
}
155+
156+
/* Style for the review count */
157+
.review-count {
158+
font-size: 18px;
159+
font-weight: bold;
160+
color: #333;
161+
padding: 8px;
162+
background: #f1f1f1;
163+
border-radius: 8px;
164+
display: inline-block;
165+
margin-left: 10px;
166+
}
167+
168+
/* Style for the action bar */
169+
.action-bar {
170+
width: 90%;
171+
max-width: 800px;
172+
text-align: center;
173+
display: flex;
174+
justify-content: center;
175+
gap: 2em;
176+
margin: 0 auto 1em auto;
177+
align-items: center;
178+
flex-wrap: wrap;
179+
}
180+
181+
118182
</style>
119183
</head>
120184
<body>
121185
<div class="container">
122-
<h1>App Privacy Policy Generator's 📖 Guest Book 🙇🏻‍♂️</h1>
123-
<h3>
124-
<a href="/" class="link">Back to Web App ↩️</a> |
125-
<a href="https://ko-fi.com/A443EQ6" target="_blank" class="link"
126-
>Buy Me a Coffee ☕️</a
127-
>
128-
</h3>
129-
<div class="review-columns">
186+
<div class="header">
187+
<h1>📖 App Privacy Policy Generator's Guest Book 🙇🏻‍♂️</h1>
188+
<div class="action-bar">
189+
<a href="/" class="link">↩️ Back to Web App</a>
190+
<a href="https://ko-fi.com/A443EQ6" target="_blank" class="link">☕️ Buy Me a Coffee</a>
191+
<span class="review-count">📊 Total Reviews: <span id="reviewCount">450</span></span>
192+
</div>
193+
<input type="text" id="searchInput" class="search-box" placeholder="Search reviews..." />
194+
</div>
195+
<div class="review-columns" id="reviewContainer">
130196
<a
131197
href="https://github.com/nisrulz/app-privacy-policy-generator/issues/65"
132198
target="_blank"
@@ -7680,5 +7746,64 @@ <h1>Amazing tool</h1></div>
76807746
</a>
76817747
</div>
76827748
</div>
7749+
7750+
<script>
7751+
document.addEventListener("DOMContentLoaded", function () {
7752+
const reviewCountElement = document.getElementById("reviewCount");
7753+
const searchInput = document.getElementById("searchInput");
7754+
7755+
function getReviewCards() {
7756+
return document.querySelectorAll(".review-card:not(.header-card)");
7757+
}
7758+
7759+
function updateReviewCount(count) {
7760+
reviewCountElement.textContent = typeof count === "number" ? count : getReviewCards().length;
7761+
}
7762+
7763+
function showCard(card, show) {
7764+
card.style.display = show ? "inline-block" : "none";
7765+
}
7766+
7767+
function filterReviews(query) {
7768+
const cards = getReviewCards();
7769+
query = query.trim().toLowerCase();
7770+
let visible = 0;
7771+
// Process cards in chunks to avoid blocking the UI
7772+
let index = 0;
7773+
const chunkSize = 100; // Adjust based on performance
7774+
function processChunk() {
7775+
const end = Math.min(index + chunkSize, cards.length);
7776+
for (; index < end; index++) {
7777+
const card = cards[index];
7778+
const match = card.innerText.toLowerCase().includes(query);
7779+
showCard(card, match);
7780+
if (match) visible++;
7781+
}
7782+
if (index < cards.length) {
7783+
requestAnimationFrame(processChunk);
7784+
}
7785+
}
7786+
processChunk();
7787+
}
7788+
7789+
function debounce(fn, delay) {
7790+
let timer;
7791+
return function (...args) {
7792+
clearTimeout(timer);
7793+
timer = setTimeout(() => fn.apply(this, args), delay);
7794+
};
7795+
}
7796+
7797+
function setupSearch() {
7798+
searchInput.addEventListener("input", debounce(function () {
7799+
filterReviews(searchInput.value);
7800+
}, 200));
7801+
}
7802+
7803+
// Initialize
7804+
updateReviewCount();
7805+
setupSearch();
7806+
});
7807+
</script>
76837808
</body>
76847809
</html>

0 commit comments

Comments
 (0)