summaryrefslogtreecommitdiff
path: root/assets/js/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/main.js')
-rw-r--r--assets/js/main.js151
1 files changed, 3 insertions, 148 deletions
diff --git a/assets/js/main.js b/assets/js/main.js
index d849b4e..957c9b5 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,152 +1,7 @@
-(function () {
- "use strict";
-
- // TOGGLE DARK/LIGHT MODE
- function initThemeToggle() {
- const rootHtml = document.documentElement;
- const toggleThemeBtn = document.getElementById("theme-toggle");
-
- // If no saved theme, determine user preference, otherwise default to light
- const savedTheme = localStorage.getItem("theme");
- const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
- const initialTheme = savedTheme ?? (prefersDark ? "dark" : "light");
-
- function setTheme(theme) {
- const isDarkMode = theme === "dark";
- // toggleThemeBtn dataset comes with translated labels for site's language
- const label = isDarkMode ? toggleThemeBtn.dataset.labelLight : toggleThemeBtn.dataset.labelDark;
-
- rootHtml.setAttribute("data-theme", theme);
- toggleThemeBtn.setAttribute("aria-label", label); // display handled by CSS
- }
-
- // Apply initial theme
- setTheme(initialTheme);
-
- // Change theme on click and save user's choice
- toggleThemeBtn.addEventListener("click", () => {
- const newTheme = rootHtml.getAttribute("data-theme") === "dark" ? "light" : "dark";
- setTheme(newTheme);
- localStorage.setItem("theme", newTheme);
- });
- }
-
- // SEARCH
- function initSearch() {
- const input = document.getElementById("search-input");
- const resetBtn = document.getElementById("search-reset");
- const resultsCount = document.querySelector(".search-results__count");
- const resultsList = document.querySelector(".search-results__list");
- const template = document.getElementById("search-result-template");
-
- // Only initialize search on the search page
- if (!input || !template) return;
-
- let allPosts = [];
- let searchTimeout;
-
- // Get JSON file with data of all posts
- fetch(input.dataset.indexUrl ?? "/index.json")
- .then((res) => res.json())
- .then((data) => allPosts = data)
- .catch((err) => console.error("Search index.json failed to load", err));
-
- function clearResults() {
- resultsCount.hidden = true;
- resultsList.innerHTML = "";
- resultsList.hidden = true;
- }
-
- function renderSearchResults(matches) {
- clearResults();
-
- // Display how many results found for query
- resultsCount.hidden = false;
- resultsCount.querySelector("#search-results-number").textContent = String(matches.length ?? 0);
-
- // No posts matching query found
- if (!matches.length) return;
-
- // Hydrate post-card list item(s) from the template with JSON data
- matches.forEach((post) => {
- const li = template.content.firstElementChild.cloneNode(true);
-
- const link = li.querySelector(".post-card__link");
- link.href = post.url;
- link.innerHTML = post.title;
-
- const section = li.querySelector(".post-card__section-badge");
- if (section) section.textContent = post.section;
-
- const date = li.querySelector(".post-card__publish-date");
- date.textContent = new Date(post.date).toLocaleDateString();
- date.setAttribute("datetime", post.date);
-
- const summary = li.querySelector(".post-card__summary");
- if (summary) summary.textContent = post.summary;
-
- const tagsList = li.querySelector(".post-card__tags-list");
- if (tagsList) {
- tagsList.innerHTML = "";
- if (post.tags && post.tags.length) {
- post.tags.slice(0, 3).forEach((tag) => {
- const liTag = document.createElement("li");
- liTag.className = "post-card__tags-item";
- liTag.textContent = `#${tag}`;
- tagsList.appendChild(liTag);
- });
-
- if (post.tags.length > 3) {
- const more = document.createElement("li");
- more.className = "post-card__tags-item post-card__tags-more";
- more.textContent = `+${post.tags.length - 3}`;
- tagsList.appendChild(more);
- }
- }
- }
-
- resultsList.appendChild(li);
- resultsList.hidden = false;
- });
- }
-
- // Filter all posts for ones matching the user's search query
- function searchPosts(query) {
- const normalizedQuery = query.trim().toLowerCase();
-
- // Only search if user entered at least 3 chars
- if (normalizedQuery.length < 3) {
- clearResults();
- return;
- }
-
- const matches = allPosts.filter((post) => (
- post.title.toLowerCase().includes(normalizedQuery) ||
- (post.summary && post.summary.toLowerCase().includes(normalizedQuery))
- ));
-
- // At least 1 post matching query found
- renderSearchResults(matches);
- }
-
- input.addEventListener("input", (event) => {
- // Debounce search
- clearTimeout(searchTimeout);
- searchTimeout = setTimeout(() => {
- searchPosts(event.target.value);
- }, 300);
- });
-
- resetBtn.addEventListener("click", () => {
- input.value = "";
- input.focus();
- clearResults();
- });
-
- // Focus input on page load - it's what the user is here for
- input.focus();
- }
+import initThemeToggle from "./theme.js";
+import initSearch from "./search.js";
+(function () {
initThemeToggle();
initSearch();
})();