Skip to content

Commit 1af5552

Browse files
Copilotf
andcommitted
Refactor duplicated code into shared-utils.js
Co-authored-by: f <[email protected]>
1 parent c0c296a commit 1af5552

File tree

4 files changed

+143
-217
lines changed

4 files changed

+143
-217
lines changed

_layouts/default.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,11 @@ <h3>e-Books by @f</h3>
230230
</div>
231231
</footer>
232232
</div>
233+
<script src="shared-utils.js"></script>
233234
<script src="script.js"></script>
235+
{% if page.body_class == 'vibe' %}
236+
<script src="vibe/script.js"></script>
237+
{% endif %}
234238
{% if page.hide_tone_selector != true %}
235239
<script>
236240
// Initialize audience selector

script.js

Lines changed: 11 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
1-
// Dark mode functionality
2-
function toggleDarkMode() {
3-
const body = document.body;
4-
const toggle = document.querySelector(".dark-mode-toggle");
5-
const sunIcon = toggle.querySelector(".sun-icon");
6-
const moonIcon = toggle.querySelector(".moon-icon");
7-
8-
body.classList.toggle("dark-mode");
9-
const isDarkMode = body.classList.contains("dark-mode");
10-
11-
localStorage.setItem("dark-mode", isDarkMode);
12-
sunIcon.style.display = isDarkMode ? "none" : "block";
13-
moonIcon.style.display = isDarkMode ? "block" : "none";
14-
}
1+
// Dark mode functionality - using shared utility
2+
// toggleDarkMode is now imported from shared-utils.js
153

164
// Add these new functions at the top
175
function extractVariables(text) {
@@ -268,35 +256,7 @@ function updatePromptCount(filteredCount, totalCount) {
268256
}
269257
}
270258

271-
function parseCSV(csv) {
272-
const lines = csv.split("\n");
273-
const headers = lines[0]
274-
.split(",")
275-
.map((header) => header.replace(/"/g, "").trim());
276-
277-
return lines
278-
.slice(1)
279-
.map((line) => {
280-
const values = line.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g) || [];
281-
const entry = {};
282-
283-
headers.forEach((header, index) => {
284-
let value = values[index] ? values[index].replace(/"/g, "").trim() : "";
285-
// Remove backticks from the act/title
286-
if (header === "act") {
287-
value = value.replace(/`/g, "");
288-
}
289-
// Convert 'TRUE'/'FALSE' strings to boolean for for_devs
290-
if (header === "for_devs") {
291-
value = value.toUpperCase() === "TRUE";
292-
}
293-
entry[header] = value;
294-
});
295-
296-
return entry;
297-
})
298-
.filter((entry) => entry.act && entry.prompt);
299-
}
259+
// parseCSV is now imported from shared-utils.js
300260

301261
function displaySearchResults(results) {
302262
const searchResults = document.getElementById("searchResults");
@@ -336,76 +296,13 @@ function displaySearchResults(results) {
336296
li.className = "search-result-item";
337297
li.textContent = result.act;
338298
li.addEventListener("click", () => {
339-
// Find the prompt card with matching title
340-
const cards = document.querySelectorAll(".prompt-card");
341-
const targetCard = Array.from(cards).find((card) => {
342-
const cardTitle = card
343-
.querySelector(".prompt-title")
344-
.textContent.replace(/\s+/g, " ") // Normalize whitespace
345-
.replace(/[\n\r]/g, "") // Remove newlines
346-
.trim();
347-
348-
const searchTitle = result.act
349-
.replace(/\s+/g, " ") // Normalize whitespace
350-
.replace(/[\n\r]/g, "") // Remove newlines
351-
.trim();
352-
353-
return (
354-
cardTitle.toLowerCase().includes(searchTitle.toLowerCase()) ||
355-
searchTitle.toLowerCase().includes(cardTitle.toLowerCase())
356-
);
357-
});
299+
// Find the prompt card with matching title using shared utility
300+
const targetCard = findPromptCardByTitle(result.act);
358301

359302
if (targetCard) {
360-
// Remove highlight from all cards
361-
cards.forEach((card) => {
362-
card.style.transition = "all 0.3s ease";
363-
card.style.transform = "none";
364-
card.style.boxShadow = "none";
365-
card.style.borderColor = "";
366-
});
367-
368-
// Different scroll behavior for mobile and desktop
369303
const isMobile = window.innerWidth <= 768;
370-
const headerHeight =
371-
document.querySelector(".site-header").offsetHeight;
372-
373-
if (isMobile) {
374-
// On mobile, scroll the window
375-
const cardRect = targetCard.getBoundingClientRect();
376-
const scrollTop =
377-
window.pageYOffset + cardRect.top - headerHeight - 50;
378-
379-
window.scrollTo({
380-
top: scrollTop,
381-
behavior: "smooth",
382-
});
383-
} else {
384-
// On desktop, scroll the main-content container
385-
const mainContent = document.querySelector(".main-content");
386-
const cardRect = targetCard.getBoundingClientRect();
387-
const scrollTop =
388-
mainContent.scrollTop + cardRect.top - headerHeight - 50;
389-
390-
mainContent.scrollTo({
391-
top: scrollTop,
392-
behavior: "smooth",
393-
});
394-
}
395-
396-
// Add highlight effect after scrolling completes
397-
setTimeout(() => {
398-
targetCard.style.transform = "scale(1.02)";
399-
targetCard.style.boxShadow = "0 0 0 2px var(--accent-color)";
400-
targetCard.style.borderColor = "var(--accent-color)";
401-
402-
// Remove highlight after animation
403-
setTimeout(() => {
404-
targetCard.style.transform = "none";
405-
targetCard.style.boxShadow = "none";
406-
targetCard.style.borderColor = "";
407-
}, 2000);
408-
}, 500); // Wait for scroll to complete
304+
const headerHeight = document.querySelector(".site-header").offsetHeight;
305+
scrollToPromptCard(targetCard, isMobile, headerHeight);
409306
} else {
410307
console.log("Card not found for:", result.act);
411308
}
@@ -454,14 +351,8 @@ function filterPrompts() {
454351
cards.forEach((card) => {
455352
const title = card.querySelector(".prompt-title").textContent.trim();
456353
const matchingPrompt = prompts.find((p) => {
457-
const pTitle = p.act
458-
.replace(/\s+/g, " ")
459-
.replace(/[\n\r]/g, "")
460-
.trim();
461-
const cardTitle = title
462-
.replace(/\s+/g, " ")
463-
.replace(/[\n\r]/g, "")
464-
.trim();
354+
const pTitle = normalizeText(p.act);
355+
const cardTitle = normalizeText(title);
465356
return (
466357
pTitle.toLowerCase() === cardTitle.toLowerCase() ||
467358
pTitle.toLowerCase().includes(cardTitle.toLowerCase()) ||
@@ -524,14 +415,8 @@ function createPromptCards() {
524415

525416
// Find matching prompt in CSV
526417
const matchingPrompt = prompts.find((p) => {
527-
const csvTitle = p.act
528-
.replace(/\s+/g, " ")
529-
.replace(/[\n\r]/g, "")
530-
.trim();
531-
const elementTitle = title
532-
.replace(/\s+/g, " ")
533-
.replace(/[\n\r]/g, "")
534-
.trim();
418+
const csvTitle = normalizeText(p.act);
419+
const elementTitle = normalizeText(title);
535420
return (
536421
csvTitle.toLowerCase() === elementTitle.toLowerCase() ||
537422
csvTitle.toLowerCase().includes(elementTitle.toLowerCase()) ||

shared-utils.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Shared utility functions used across multiple pages
2+
3+
// Dark mode functionality
4+
function toggleDarkMode() {
5+
const body = document.body;
6+
const toggle = document.querySelector(".dark-mode-toggle");
7+
const sunIcon = toggle.querySelector(".sun-icon");
8+
const moonIcon = toggle.querySelector(".moon-icon");
9+
10+
body.classList.toggle("dark-mode");
11+
const isDarkMode = body.classList.contains("dark-mode");
12+
13+
localStorage.setItem("dark-mode", isDarkMode);
14+
sunIcon.style.display = isDarkMode ? "none" : "block";
15+
moonIcon.style.display = isDarkMode ? "block" : "none";
16+
}
17+
18+
// Parse CSV data into objects
19+
function parseCSV(csv) {
20+
const lines = csv.split("\n");
21+
const headers = lines[0]
22+
.split(",")
23+
.map((header) => header.replace(/"/g, "").trim());
24+
25+
return lines
26+
.slice(1)
27+
.map((line) => {
28+
const values = line.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g) || [];
29+
const entry = {};
30+
31+
headers.forEach((header, index) => {
32+
let value = values[index] ? values[index].replace(/"/g, "").trim() : "";
33+
// Remove backticks from the act/title/app
34+
if (header === "act" || header === "app") {
35+
value = value.replace(/`/g, "");
36+
}
37+
// Convert 'TRUE'/'FALSE' strings to boolean for for_devs
38+
if (header === "for_devs") {
39+
value = value.toUpperCase() === "TRUE";
40+
}
41+
entry[header] = value;
42+
});
43+
44+
return entry;
45+
})
46+
.filter((entry) => (entry.act || entry.app) && entry.prompt);
47+
}
48+
49+
// Normalize text by removing extra whitespace and newlines
50+
function normalizeText(text) {
51+
return text
52+
.replace(/\s+/g, " ") // Normalize whitespace
53+
.replace(/[\n\r]/g, "") // Remove newlines
54+
.trim();
55+
}
56+
57+
// Scroll to a prompt card with highlight animation
58+
function scrollToPromptCard(targetCard, isMobile, headerHeight) {
59+
if (!targetCard) return;
60+
61+
// Remove highlight from all cards
62+
const cards = document.querySelectorAll(".prompt-card");
63+
cards.forEach((card) => {
64+
card.style.transition = "all 0.3s ease";
65+
card.style.transform = "none";
66+
card.style.boxShadow = "none";
67+
card.style.borderColor = "";
68+
});
69+
70+
// Different scroll behavior for mobile and desktop
71+
if (isMobile) {
72+
// On mobile, scroll the window
73+
const cardRect = targetCard.getBoundingClientRect();
74+
const scrollTop = window.pageYOffset + cardRect.top - headerHeight - 50;
75+
76+
window.scrollTo({
77+
top: scrollTop,
78+
behavior: "smooth",
79+
});
80+
} else {
81+
// On desktop, scroll the main-content container
82+
const mainContent = document.querySelector(".main-content");
83+
const cardRect = targetCard.getBoundingClientRect();
84+
const scrollTop = mainContent.scrollTop + cardRect.top - headerHeight - 50;
85+
86+
mainContent.scrollTo({
87+
top: scrollTop,
88+
behavior: "smooth",
89+
});
90+
}
91+
92+
// Add highlight effect after scrolling completes
93+
setTimeout(() => {
94+
targetCard.style.transform = "scale(1.02)";
95+
targetCard.style.boxShadow = "0 0 0 2px var(--accent-color)";
96+
targetCard.style.borderColor = "var(--accent-color)";
97+
98+
// Remove highlight after animation
99+
setTimeout(() => {
100+
targetCard.style.transform = "none";
101+
targetCard.style.boxShadow = "none";
102+
targetCard.style.borderColor = "";
103+
}, 2000);
104+
}, 500); // Wait for scroll to complete
105+
}
106+
107+
// Find prompt card by title with fuzzy matching
108+
function findPromptCardByTitle(title) {
109+
const cards = document.querySelectorAll(".prompt-card");
110+
const normalizedSearchTitle = normalizeText(title);
111+
112+
return Array.from(cards).find((card) => {
113+
const titleElement = card.querySelector(".prompt-title");
114+
if (!titleElement) return false;
115+
116+
const cardTitle = normalizeText(titleElement.textContent);
117+
return (
118+
cardTitle.toLowerCase().includes(normalizedSearchTitle.toLowerCase()) ||
119+
normalizedSearchTitle.toLowerCase().includes(cardTitle.toLowerCase())
120+
);
121+
});
122+
}

0 commit comments

Comments
 (0)