split javascript file into multiple
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { getCookie, setCookie } from "../core/cookies.js";
|
||||
|
||||
const SUPPORTED_LANGUAGES = ["en", "de"];
|
||||
|
||||
// Language from cookie, else browser language, else "en".
|
||||
export function detectLanguage() {
|
||||
let lang = getCookie("lang");
|
||||
if (lang == null) {
|
||||
lang = navigator.language.split("-")[0];
|
||||
}
|
||||
if (!SUPPORTED_LANGUAGES.includes(lang)) {
|
||||
lang = "en";
|
||||
}
|
||||
|
||||
document.documentElement.lang = lang;
|
||||
return lang;
|
||||
}
|
||||
|
||||
export function setupLanguageDropdown(lang, buttonId, menuId, dropdownId) {
|
||||
const button = document.getElementById(buttonId);
|
||||
const menu = document.getElementById(menuId);
|
||||
const dropdown = document.getElementById(dropdownId);
|
||||
const items = menu.querySelectorAll(".lang-item");
|
||||
|
||||
button.textContent = lang;
|
||||
|
||||
button.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
items.forEach(item => {
|
||||
item.classList.toggle("hidden", item.dataset.lang == lang);
|
||||
});
|
||||
|
||||
menu.classList.toggle("hidden");
|
||||
dropdown.classList.toggle("show-border");
|
||||
});
|
||||
|
||||
items.forEach(item => {
|
||||
item.addEventListener("click", () => {
|
||||
const lang_selected = item.dataset.lang;
|
||||
|
||||
button.textContent = item.textContent;
|
||||
|
||||
menu.classList.add("hidden");
|
||||
dropdown.classList.remove("show-border");
|
||||
|
||||
items.forEach(el => el.classList.add("hidden"));
|
||||
|
||||
setCookie("lang", lang_selected, "3600");
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!e.target.closest(`#${dropdownId}`)) {
|
||||
menu.classList.add("hidden");
|
||||
dropdown.classList.remove("show-border");
|
||||
items.forEach(el => el.classList.add("hidden"));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { el } from "../core/dom.js";
|
||||
|
||||
const navbarMobile = () => document.getElementById("navbar-mobile");
|
||||
const openButton = () => document.getElementById("button-mobile");
|
||||
|
||||
// Mobile bar: open/close buttons and closing on outside click.
|
||||
export function setupMobileNavbar() {
|
||||
const navbar = navbarMobile();
|
||||
const button = openButton();
|
||||
const links = document.getElementById("navbar-mobile-links");
|
||||
|
||||
const toggle = () => {
|
||||
navbar.classList.toggle("inactive");
|
||||
button.classList.toggle("inactive");
|
||||
};
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!e.target.closest("#navbar-mobile") && !e.target.closest("#button-mobile") && !navbar.classList.contains("inactive")) {
|
||||
navbar.classList.add("inactive");
|
||||
button.classList.remove("inactive");
|
||||
}
|
||||
});
|
||||
|
||||
const closeButton = el("button", "button-mobile navbar", "");
|
||||
links.appendChild(closeButton);
|
||||
closeButton.addEventListener("click", toggle);
|
||||
|
||||
button.textContent = "";
|
||||
button.addEventListener("click", toggle);
|
||||
}
|
||||
|
||||
export function hideMobileNavbar() {
|
||||
navbarMobile().classList.add("inactive");
|
||||
}
|
||||
|
||||
// Desktop sidebar navigation and mobile bar links, filled together.
|
||||
export function createNavbar() {
|
||||
const desktop = document.getElementById("navbar");
|
||||
const mobile = document.getElementById("navbar-mobile-links");
|
||||
|
||||
return {
|
||||
addGroup(title) {
|
||||
desktop.appendChild(el("li", "navbar-group", title));
|
||||
},
|
||||
|
||||
addEntry(title, id, index) {
|
||||
addDesktopEntry(desktop, title, id, index);
|
||||
addMobileEntry(mobile, title, id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function addDesktopEntry(navbar, title, id, index) {
|
||||
const item = el("li", "navbar-item");
|
||||
navbar.appendChild(item);
|
||||
|
||||
const link = el("a", "nav-link");
|
||||
link.href = `#${id}`;
|
||||
link.dataset.target = id;
|
||||
item.appendChild(link);
|
||||
|
||||
link.appendChild(el("span", "idx", String(index).padStart(2, "0") + " "));
|
||||
link.appendChild(document.createTextNode(title));
|
||||
}
|
||||
|
||||
function addMobileEntry(navbar, title, id) {
|
||||
const item = el("li", "navbar-item-mobile");
|
||||
navbar.appendChild(item);
|
||||
|
||||
const link = el("a", "nav-link-mobile", title);
|
||||
link.href = `#${id}`;
|
||||
item.appendChild(link);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Scroll position restore across reloads (e.g. after switching language).
|
||||
|
||||
function saveScroll() {
|
||||
sessionStorage.setItem("scrollY", window.scrollY);
|
||||
}
|
||||
|
||||
export function setupScrollRestoration() {
|
||||
history.scrollRestoration = "manual";
|
||||
window.addEventListener("beforeunload", saveScroll);
|
||||
}
|
||||
|
||||
export function restoreScroll() {
|
||||
const scrollY = sessionStorage.getItem("scrollY");
|
||||
if (scrollY !== null) {
|
||||
|
||||
document.documentElement.style.scrollBehavior = "auto";
|
||||
|
||||
window.scrollTo(0, parseInt(scrollY));
|
||||
|
||||
document.documentElement.style.scrollBehavior = "smooth";
|
||||
}
|
||||
}
|
||||
|
||||
// Highlights the sidebar link of the section currently in view.
|
||||
export function setupScrollSpy() {
|
||||
const sections = document.querySelectorAll("[data-nav]");
|
||||
const navLinks = document.querySelectorAll(".nav-link");
|
||||
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
|
||||
navLinks.forEach(link => {
|
||||
link.classList.toggle(
|
||||
"active",
|
||||
link.dataset.target === entry.target.id
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0,
|
||||
rootMargin: "-10% 0px -80% 0px"
|
||||
});
|
||||
|
||||
sections.forEach(section => observer.observe(section));
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { getCookie, setCookie } from "../core/cookies.js";
|
||||
|
||||
const THEME_MAX_AGE = 60 * 60 * 24 * 7;
|
||||
|
||||
// Wires a dark-mode toggle and keeps the other toggles (sidebar / mobile bar) in sync.
|
||||
export function setupThemeToggle(toggleId, otherToggleIds) {
|
||||
const toggle = document.getElementById(toggleId);
|
||||
const otherToggles = otherToggleIds.map(id => document.getElementById(id));
|
||||
|
||||
toggle.addEventListener("change", () => {
|
||||
document.documentElement.classList.toggle("dark", toggle.checked);
|
||||
setCookie("theme", toggle.checked ? "dark" : "light", THEME_MAX_AGE);
|
||||
otherToggles.forEach(other => {
|
||||
other.checked = toggle.checked;
|
||||
});
|
||||
});
|
||||
|
||||
if (getCookie("theme") === "dark") {
|
||||
document.documentElement.classList.add("dark");
|
||||
toggle.checked = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user