diff options
| author | Arne Rief <riearn@proton.me> | 2025-12-22 14:02:07 +0100 |
|---|---|---|
| committer | Arne Rief <riearn@proton.me> | 2025-12-22 14:02:07 +0100 |
| commit | 038054b8206a9c25e84adeb0f0f355abd22d6143 (patch) | |
| tree | 47700e52b88e0db08f0ca113de22f4c0d05cc405 | |
| parent | 32c1a5dd203435e8bef324306d1516e28ce14615 (diff) | |
CSS & JS splitting, small fix section badge
| -rw-r--r-- | assets/css/footer.css | 31 | ||||
| -rw-r--r-- | assets/css/header.css | 41 | ||||
| -rw-r--r-- | assets/css/list-navigation.css | 18 | ||||
| -rw-r--r-- | assets/css/main.css | 348 | ||||
| -rw-r--r-- | assets/css/navmenu.css | 26 | ||||
| -rw-r--r-- | assets/css/page.css | 19 | ||||
| -rw-r--r-- | assets/css/post-card.css | 71 | ||||
| -rw-r--r-- | assets/css/post.css | 88 | ||||
| -rw-r--r-- | assets/css/search.css | 51 | ||||
| -rw-r--r-- | assets/js/main.js | 151 | ||||
| -rw-r--r-- | assets/js/search.js | 118 | ||||
| -rw-r--r-- | assets/js/theme.js | 32 | ||||
| -rw-r--r-- | layouts/_default/all-posts.html | 2 | ||||
| -rw-r--r-- | layouts/_default/search.html | 2 | ||||
| -rw-r--r-- | layouts/index.json | 2 | ||||
| -rw-r--r-- | layouts/partials/head/css.html | 28 | ||||
| -rw-r--r-- | layouts/partials/list/post-card.html | 17 | ||||
| -rw-r--r-- | layouts/partials/list/recent-posts.html | 2 | ||||
| -rw-r--r-- | layouts/tags/term.html | 2 |
19 files changed, 533 insertions, 516 deletions
diff --git a/assets/css/footer.css b/assets/css/footer.css new file mode 100644 index 0000000..88d705c --- /dev/null +++ b/assets/css/footer.css @@ -0,0 +1,31 @@ +/* FOOTER */ +.site__footer { + display: flex; + align-items: center; + justify-content: space-around; + margin-top: var(--gap-medium); + + @media (max-width: 768px) { + flex-direction: column; + gap: var(--gap-default); + } +} + +.follow-me-list { + display: flex; + align-items: center; + justify-content: center; + gap: var(--gap-medium); + + @media (max-width: 768px) { + flex-wrap: wrap; + } +} + +/* Footer Icons */ +.follow-me-item img { + object-fit: contain; + height: 2rem; + width: 2rem; +} + diff --git a/assets/css/header.css b/assets/css/header.css new file mode 100644 index 0000000..8cb9e9d --- /dev/null +++ b/assets/css/header.css @@ -0,0 +1,41 @@ +/* HEADER */ +.site__header { + display: flex; + align-items: center; + justify-content: space-around; + margin-bottom: var(--gap-medium); +} + +.site-selections, +.site-selections * { + display: flex; + align-items: center; + justify-content: center; + gap: var(--gap-medium); +} + +.site-title { + color: inherit !important; + font-size: var(--font-size-h1); + font-weight: bold; + text-decoration: none; +} + +/* Flag Icon */ +.language-select__language-item img { + height: 2rem; +} + +.theme-toggle { + background-color: var(--text-color); + border: none; + border-radius: var(--border-radius-max); + color: var(--bg-main); + cursor: pointer; + padding: 0.2rem; +} + +.theme-toggle svg { + display: none; +} + diff --git a/assets/css/list-navigation.css b/assets/css/list-navigation.css new file mode 100644 index 0000000..2f8495c --- /dev/null +++ b/assets/css/list-navigation.css @@ -0,0 +1,18 @@ +/* List navigation */ +.pagination { + display: flex; + align-items: center; + justify-content: space-between; +} + +.recent-posts__view-all-link, +.tag-page__view-all-link { + display: block; + margin: 0 auto; + width: max-content; +} + +.tags-index__list > li { + margin-bottom: var(--gap-small); +} + diff --git a/assets/css/main.css b/assets/css/main.css index a17c9b3..c693221 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -25,7 +25,7 @@ --text-color: #1e1e1e; } -/* BASICS */ +/* BASE SETTINGS */ *, *::before, *::after { @@ -51,7 +51,7 @@ html { &[data-theme="dark"] { --bg-main: #0a234a; --bg-special: #1e4a73; - --glow: rgba(79, 195, 247, 0.24); + --glow: rgba(79, 195, 247, 0.24); --link-color: #4fc3f7; --link-hover: #039be5; --shadow-default: 0 2px 6px rgba(224, 224, 224, 0.15); @@ -220,347 +220,3 @@ p > code { width: fit-content; } -/* HEADER */ -.site__header { - display: flex; - align-items: center; - justify-content: space-around; - margin-bottom: var(--gap-medium); -} - -.site-selections, -.site-selections * { - display: flex; - align-items: center; - justify-content: center; - gap: var(--gap-medium); -} - -.site-title { - color: inherit !important; - font-size: var(--font-size-h1); - font-weight: bold; - text-decoration: none; -} - -/* Flag Icon */ -.language-select__language-item img { - height: 2rem; -} - -.theme-toggle { - background-color: var(--text-color); - border: none; - border-radius: var(--border-radius-max); - color: var(--bg-main); - cursor: pointer; - padding: 0.2rem; -} - -.theme-toggle svg { - display: none; -} - -/* SITE NAVMENU */ -.header__navigation { - background-color: var(--bg-special); - border-radius: var(--border-radius-default); - padding: var(--margin-padding-Y-small); -} - -.header__navigation-list { - display: flex; - align-items: center; - justify-content: space-evenly; - - @media (max-width: 768px) { - /* Grid items stretch to at least 100px or take up full width */ - display: grid; - grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); - justify-items: center; - gap: var(--gap-medium) var(--gap-small); - } -} - -.header__navigation-link--active { - color: var(--text-color); - text-decoration: none; -} - -/* FOOTER */ -.site__footer { - display: flex; - align-items: center; - justify-content: space-around; - margin-top: var(--gap-medium); - - @media (max-width: 768px) { - flex-direction: column; - gap: var(--gap-default); - } -} - -.follow-me-list { - display: flex; - align-items: center; - justify-content: center; - gap: var(--gap-medium); - - @media (max-width: 768px) { - flex-wrap: wrap; - } -} - -/* Footer Icons */ -.follow-me-item img { - object-fit: contain; - height: 2rem; - width: 2rem; -} - -/* POST CARD */ -.post-card { - border: 3px solid var(--bg-special); - border-radius: var(--border-radius-default); - margin: 0 auto 1.5rem; - padding: 0 var(--gap-default); - width: 90%; - - & .post-card__title { - font-size: var(--font-size-default); - margin-top: var(--gap-default); - } - - & .post-card__meta { - display: flex; - align-items: center; - gap: var(--gap-small); - } - - & .post-card__meta, - .post-card__summary { - font-size: var(--font-size-small); - } - - & .post-card__meta-info { - margin-bottom: 0; - } - - @media (max-width: 768px) { - padding: 0 var(--gap-small); - } -} - -.post-card__header { - display: flex; - flex-direction: column; - align-items: start; - justify-content: center; - gap: 0.5rem; - margin: var(--margin-padding-Y-small); -} - -.post-card__tags-list { - display: flex; - align-items: center; - justify-content: start; - gap: var(--gap-default); - margin: var(--margin-padding-Y-default) !important; - - @media (max-width: 768px) { - flex-direction: column; - align-items: start; - } -} - -.post-card__tags-item { - background-color: var(--bg-special); - border-radius: var(--border-radius-max); - color: var(--text-color); - font-size: var(--font-size-small); - padding: 0.1rem 0.4rem; -} - -.post-card__section-badge { - background-color: var(--link-color); - border-radius: var(--border-radius-max); - color: var(--bg-main); - font-size: var(--font-size-small); - padding: 0.1rem 0.4rem; -} - -/* PAGES Content */ -.page-not-found { - text-align: center; -} - -/* Homepage */ -.homepage__header { - text-align: center; -} - -.homepage__header-image { - border: 4px solid var(--bg-special); - border-radius: var(--border-radius-max); - display: block; - margin: 1rem auto; - max-width: 150px; - max-height: 150px; -} - -/* Article */ -.post { - position: relative; /* Needed for post__scroll-top */ -} - -.post__content ol > li, -.post__content ul > li { - margin-bottom: var(--gap-small); -} - -.post__header { - margin-bottom: var(--gap-large); -} - -.post__navigation > hr { - height: 2px; - margin-bottom: var(--gap-large); -} - -.post__navigation-list { - display: flex; - align-items: center; - justify-content: space-between; - margin: 0 1rem !important; - - @media (max-width: 768px) { - flex-direction: column; - gap: var(--gap-default); - margin: 0 !important; - } -} - -.post__scroll-top { - background-color: var(--bg-special); - border-radius: var(--border-radius-max); - box-shadow: var(--shadow-default); - cursor: pointer; - display: inline-flex; - align-items: center; - justify-content: center; - height: 2.5rem; - width: 2.5rem; - position: absolute; - bottom: 6rem; - right: 0; - z-index: 1000; - - & svg { - height: 2rem; - width: 2rem; - padding-bottom: 0.2rem; - } - - /* Arrow up */ - & svg > path { - stroke: var(--text-color); - - &:hover { - stroke: var(--bg-main); - } - } - - &:hover { - background-color: var(--link-hover); - } -} - -.post__tags { - margin: var(--margin-padding-Y-big); -} - -.post__tags-heading { - font-weight: bold; -} - -.post__tags-list { - display: flex; - gap: var(--gap-default); - - @media (max-width: 768px) { - flex-direction: column; - } -} - -.post__tags-link { - font-weight: normal; -} - -/* List navigation */ -.pagination { - display: flex; - align-items: center; - justify-content: space-between; -} - -.recent-posts__view-all-link, -.tag-page__view-all-link { - display: block; - margin: 0 auto; - width: max-content; -} - -.tags-index__list > li { - margin-bottom: var(--gap-small); -} - -/* Search */ -.search-form__input { - font-size: var(--font-size-default); - border: 1px solid var(--bg-special); - border-radius: var(--border-radius-minimal); - margin-right: var(--gap-small); - padding: 0.2rem; - height: var(--font-size-h1); - width: 50%; - - &:focus { - border-color: var(--link-color); - box-shadow: var(--glow); - outline: none; - } - - @media (max-width: 768px) { - width: 90%; - } -} - -.search-form__reset { - background-color: var(--bg-special); - border: none; - border-radius: var(--border-radius-max); - box-shadow: var(--shadow-default); - color: var(--text-color); - font-size: var(--font-size-default); - font-weight: bold; - padding: 0.1rem 0.5rem 0.3rem 0.5rem; - - &:hover { - background-color: var(--link-hover); - color: var(--bg-main); - cursor: pointer; - } -} - -.search-input { - width: 30vw; - - @media (max-width: 768px) { - width: 100vw; - } -} - -.search-results__count { - font-weight: bold; - margin: var(--margin-padding-Y-default); -} diff --git a/assets/css/navmenu.css b/assets/css/navmenu.css new file mode 100644 index 0000000..d092e6c --- /dev/null +++ b/assets/css/navmenu.css @@ -0,0 +1,26 @@ +/* SITE NAVMENU */ +.header__navigation { + background-color: var(--bg-special); + border-radius: var(--border-radius-default); + padding: var(--margin-padding-Y-small); +} + +.header__navigation-list { + display: flex; + align-items: center; + justify-content: space-evenly; + + @media (max-width: 768px) { + /* Grid items stretch to at least 100px or take up full width */ + display: grid; + grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); + justify-items: center; + gap: var(--gap-medium) var(--gap-small); + } +} + +.header__navigation-link--active { + color: var(--text-color); + text-decoration: none; +} + diff --git a/assets/css/page.css b/assets/css/page.css new file mode 100644 index 0000000..daec989 --- /dev/null +++ b/assets/css/page.css @@ -0,0 +1,19 @@ +/* PAGES Content */ +.page-not-found { + text-align: center; +} + +/* Homepage */ +.homepage__header { + text-align: center; +} + +.homepage__header-image { + border: 4px solid var(--bg-special); + border-radius: var(--border-radius-max); + display: block; + margin: 1rem auto; + max-width: 150px; + max-height: 150px; +} + diff --git a/assets/css/post-card.css b/assets/css/post-card.css new file mode 100644 index 0000000..c8afb42 --- /dev/null +++ b/assets/css/post-card.css @@ -0,0 +1,71 @@ +/* POST CARD */ +.post-card { + border: 3px solid var(--bg-special); + border-radius: var(--border-radius-default); + margin: 0 auto 1.5rem; + padding: 0 var(--gap-default); + width: 90%; + + & .post-card__title { + font-size: var(--font-size-default); + margin-top: var(--gap-default); + } + + & .post-card__meta { + display: flex; + align-items: center; + gap: var(--gap-small); + } + + & .post-card__meta, + .post-card__summary { + font-size: var(--font-size-small); + } + + & .post-card__meta-info { + margin-bottom: 0; + } + + @media (max-width: 768px) { + padding: 0 var(--gap-small); + } +} + +.post-card__header { + display: flex; + flex-direction: column; + align-items: start; + justify-content: center; + gap: 0.5rem; + margin: var(--margin-padding-Y-small); +} + +.post-card__tags-list { + display: flex; + align-items: center; + justify-content: start; + gap: var(--gap-default); + margin: var(--margin-padding-Y-default) !important; + + @media (max-width: 768px) { + flex-direction: column; + align-items: start; + } +} + +.post-card__tags-item { + background-color: var(--bg-special); + border-radius: var(--border-radius-max); + color: var(--text-color); + font-size: var(--font-size-small); + padding: 0.1rem 0.4rem; +} + +.post-card__section-badge { + border-radius: var(--border-radius-max); + color: var(--link-color); + font-size: var(--font-size-small); + font-weight: bold; + padding: 0.1rem 0.4rem; +} + diff --git a/assets/css/post.css b/assets/css/post.css new file mode 100644 index 0000000..2c7fcd5 --- /dev/null +++ b/assets/css/post.css @@ -0,0 +1,88 @@ +/* Post/Article */ +.post { + position: relative; /* Needed for post__scroll-top */ +} + +.post__content ol > li, +.post__content ul > li { + margin-bottom: var(--gap-small); +} + +.post__header { + margin-bottom: var(--gap-large); +} + +.post__navigation > hr { + height: 2px; + margin-bottom: var(--gap-large); +} + +.post__navigation-list { + display: flex; + align-items: center; + justify-content: space-between; + margin: 0 1rem !important; + + @media (max-width: 768px) { + flex-direction: column; + gap: var(--gap-default); + margin: 0 !important; + } +} + +.post__scroll-top { + background-color: var(--bg-special); + border-radius: var(--border-radius-max); + box-shadow: var(--shadow-default); + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + height: 2.5rem; + width: 2.5rem; + position: absolute; + bottom: 6rem; + right: 0; + z-index: 1000; + + & svg { + height: 2rem; + width: 2rem; + padding-bottom: 0.2rem; + } + + /* Arrow up */ + & svg > path { + stroke: var(--text-color); + } + + &:hover { + background-color: var(--link-hover); + + & svg > path { + stroke: var(--bg-main); + } + } +} + +.post__tags { + margin: var(--margin-padding-Y-big); +} + +.post__tags-heading { + font-weight: bold; +} + +.post__tags-list { + display: flex; + gap: var(--gap-default); + + @media (max-width: 768px) { + flex-direction: column; + } +} + +.post__tags-link { + font-weight: normal; +} + diff --git a/assets/css/search.css b/assets/css/search.css new file mode 100644 index 0000000..7b6feab --- /dev/null +++ b/assets/css/search.css @@ -0,0 +1,51 @@ +/* Search */ +.search-form__input { + font-size: var(--font-size-default); + border: 2px solid var(--bg-special); + border-radius: var(--border-radius-minimal); + margin-right: var(--gap-small); + padding: 0.2rem; + height: var(--font-size-h1); + width: 50%; + + &:focus { + border-color: var(--link-color); + box-shadow: var(--glow); + outline: none; + } + + @media (max-width: 768px) { + width: 90%; + } +} + +.search-form__reset { + background-color: var(--bg-special); + border: none; + border-radius: var(--border-radius-max); + box-shadow: var(--shadow-default); + color: var(--text-color); + font-size: var(--font-size-default); + font-weight: bold; + padding: 0.1rem 0.5rem 0.3rem 0.5rem; + + &:hover { + background-color: var(--link-hover); + color: var(--bg-main); + cursor: pointer; + } +} + +.search-input { + width: 30vw; + + @media (max-width: 768px) { + width: 100vw; + } +} + +.search-results__count { + font-weight: bold; + margin: var(--margin-padding-Y-default); +} + 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(); })(); diff --git a/assets/js/search.js b/assets/js/search.js new file mode 100644 index 0000000..f10695a --- /dev/null +++ b/assets/js/search.js @@ -0,0 +1,118 @@ +/* Search Entire Site for Content */ +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 matches with 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) => { + clearTimeout(searchTimeout); + // Debounce search + 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(); +} + +export default initSearch; + diff --git a/assets/js/theme.js b/assets/js/theme.js new file mode 100644 index 0000000..36896c9 --- /dev/null +++ b/assets/js/theme.js @@ -0,0 +1,32 @@ +/* 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); + }); +} + +export default initThemeToggle; + diff --git a/layouts/_default/all-posts.html b/layouts/_default/all-posts.html index dcfe74e..4a94ab6 100644 --- a/layouts/_default/all-posts.html +++ b/layouts/_default/all-posts.html @@ -22,7 +22,7 @@ <ul class="all-posts__list" role="list"> {{- range $allPosts.ByDate.Reverse }} <li class="all-posts__list-item"> - {{ partial "list/post-card.html" (dict "post" . "show_category" true) }} + {{ partial "list/post-card.html" (dict "post" . "show_section" true) }} </li> {{- end }} </ul> diff --git a/layouts/_default/search.html b/layouts/_default/search.html index b501c8b..6004f2e 100644 --- a/layouts/_default/search.html +++ b/layouts/_default/search.html @@ -61,7 +61,7 @@ "Params" (dict "tags" (slice "TEMPLATE_TAG")) -}} <li class="search-results__list-item"> - {{- partial "list/post-card.html" (dict "post" $mockPost "show_category" true) }} + {{- partial "list/post-card.html" (dict "post" $mockPost "show_section" true) }} </li> </template> diff --git a/layouts/index.json b/layouts/index.json index 00a7048..e50a721 100644 --- a/layouts/index.json +++ b/layouts/index.json @@ -5,7 +5,7 @@ "title" .Title "summary" (.Summary | plainify | htmlUnescape) "url" .RelPermalink - "section" (lang.translate (.Section | singularize) | default (.Section | singularize | title)) + "section" (lang.Translate (.Section | singularize) | default (.Section | singularize | title)) "date" (.Date.Format "2006-01-02T15:04:05Z07:00") "tags" .Params.tags -}} diff --git a/layouts/partials/head/css.html b/layouts/partials/head/css.html index c3c6e33..d4e894e 100644 --- a/layouts/partials/head/css.html +++ b/layouts/partials/head/css.html @@ -1,9 +1,21 @@ -{{- with resources.Get "css/main.css" }} - {{- if hugo.IsDevelopment }} - <link rel="stylesheet" href="{{ .RelPermalink }}"> - {{- else }} - {{- with . | minify | fingerprint }} - <link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"> - {{- end }} - {{- end }} +{{- with resources.Get "css/main.css" -}} + {{- $allStylesheets := slice + . + (resources.Get "css/header.css") + (resources.Get "css/navmenu.css") + (resources.Get "css/footer.css") + (resources.Get "css/post-card.css") + (resources.Get "css/page.css") + (resources.Get "css/post.css") + (resources.Get "css/list-navigation.css") + (resources.Get "css/search.css") + -}} + {{- $cssBundle := $allStylesheets | resources.Concat "css/bundle.css" -}} + + {{- if hugo.IsDevelopment -}} + <link rel="stylesheet" href="{{ $cssBundle.RelPermalink }}"> + {{- else -}} + {{- $css := $cssBundle | minify | fingerprint -}} + <link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous"> + {{- end -}} {{- end -}} diff --git a/layouts/partials/list/post-card.html b/layouts/partials/list/post-card.html index b35c724..6444701 100644 --- a/layouts/partials/list/post-card.html +++ b/layouts/partials/list/post-card.html @@ -1,14 +1,14 @@ {{- /* -Card with a summary of and link to a post. Accepts a dict with the following optional parameters: +Card with a summary of and link to a post. Accepts a dict with the following parameters: -@context {Page} post: The post to display (default: .). -@context {bool} show_category: Whether to display a badge with the name of the category/section the post was published under (default: true). +@context {Page} post: The post to display. +@context {bool} show_section: Whether to display a badge with the name of the section the post was published under (default: false). -@example: {{ partial "list/post-card.html" (dict "post" . "show_category" true) }} +@example: {{ partial "list/post-card.html" (dict "post" . "show_section" true) }} */ -}} -{{- $post := .post }} -{{- $showCategory := .show_category | default false }} +{{- $post := .post -}} +{{- $showSection := .show_section | default false -}} <article class="post-card"> <header class="post-card__header"> <h3 class="post-card__title"> @@ -31,10 +31,9 @@ Card with a summary of and link to a post. Accepts a dict with the following opt </span> </p> --> - {{- if $showCategory }} - {{- $section := $post.Section }} + {{- if $showSection }} <span class="post-card__section-badge"> - {{ lang.Translate ($section | singularize) | default ($section | singularize | title) }} + {{ lang.Translate ($post.Section | singularize) | default ($post.Section | singularize | title) }} </span> {{- end }} </div> diff --git a/layouts/partials/list/recent-posts.html b/layouts/partials/list/recent-posts.html index f42af13..464e9f7 100644 --- a/layouts/partials/list/recent-posts.html +++ b/layouts/partials/list/recent-posts.html @@ -24,7 +24,7 @@ List of specified number of the most recent and published posts. Accepts a dict <ul class="recent-posts__list" role="list"> {{- range $recentPosts }} <li class="recent-posts__list-item"> - {{- partial "list/post-card.html" (dict "post" . "show_category" true) }} + {{- partial "list/post-card.html" (dict "post" . "show_section" true) }} </li> {{- end }} </ul> diff --git a/layouts/tags/term.html b/layouts/tags/term.html index 8a259c2..f4dfd73 100644 --- a/layouts/tags/term.html +++ b/layouts/tags/term.html @@ -20,7 +20,7 @@ <ul class="tag-page__posts-list"> {{- range . }} <li class="tag-page__post"> - {{- partial "list/post-card.html" (dict "post" . "show_category" true) }} + {{- partial "list/post-card.html" (dict "post" . "show_section" true) }} </li> {{- end }} </ul> |
