diff --git a/assets/js/lang.js b/assets/js/lang.js index aa76611..b3fa7f0 100644 --- a/assets/js/lang.js +++ b/assets/js/lang.js @@ -1,44 +1,18 @@ (function () { const languageSwitchers = document.querySelectorAll('.hextra-language-switcher'); + languageSwitchers.forEach((switcher) => { switcher.addEventListener('click', (e) => { e.preventDefault(); switcher.dataset.state = switcher.dataset.state === 'open' ? 'closed' : 'open'; - const optionsElement = switcher.nextElementSibling; - - optionsElement.classList.toggle('hx:hidden'); - - // Calculate the position of a language options element. - const switcherRect = switcher.getBoundingClientRect(); - - // Must be called before optionsElement.clientWidth. - optionsElement.style.minWidth = `${Math.max(switcherRect.width, 50)}px`; - - const isOnTop = switcher.dataset.location === 'top'; - const isRTL = document.body.dir === 'rtl' - - // Stuck on the left side of the switcher. - let translateX = switcherRect.left; - - if (isOnTop && !isRTL || !isOnTop && isRTL) { - // Stuck on the right side of the switcher. - translateX = switcherRect.right - optionsElement.clientWidth; - } - - // Stuck on the top of the switcher. - let translateY = switcherRect.top - window.innerHeight - 15; - - if (isOnTop) { - // Stuck on the bottom of the switcher. - translateY = switcherRect.top - window.innerHeight + 180; - } - - optionsElement.style.transform = `translate3d(${translateX}px, ${translateY}px, 0)`; + toggleMenu(switcher); }); }); + window.addEventListener("resize", () => languageSwitchers.forEach(resizeMenu)) + // Dismiss language switcher when clicking outside document.addEventListener('click', (e) => { if (e.target.closest('.hextra-language-switcher') === null) { diff --git a/assets/js/switcher-menu.js b/assets/js/switcher-menu.js new file mode 100644 index 0000000..49074bd --- /dev/null +++ b/assets/js/switcher-menu.js @@ -0,0 +1,52 @@ +function computeMenuTranslation(switcher, optionsElement) { + // Calculate the position of a language options element. + const switcherRect = switcher.getBoundingClientRect(); + + // Must be called before optionsElement.clientWidth. + optionsElement.style.minWidth = `${Math.max(switcherRect.width, 50)}px`; + + const isOnTop = switcher.dataset.location === 'top'; + const isOnBottom = switcher.dataset.location === 'bottom'; + const isOnBottomRight = switcher.dataset.location === 'bottom-right'; + const isRTL = document.body.dir === 'rtl' + + // Stuck on the left side of the switcher. + let x = switcherRect.left; + + if (isOnTop && !isRTL || isOnBottom && isRTL || isOnBottomRight && !isRTL) { + // Stuck on the right side of the switcher. + x = switcherRect.right - optionsElement.clientWidth; + } + + // Stuck on the top of the switcher. + let y = switcherRect.top - window.innerHeight - 10; + + if (isOnTop) { + // Stuck on the bottom of the switcher. + y = switcherRect.top - window.innerHeight + optionsElement.clientHeight + switcher.clientHeight + 4; + } + + return { x: x, y: y }; +} + +function toggleMenu(switcher) { + const optionsElement = switcher.nextElementSibling; + + optionsElement.classList.toggle('hx:hidden'); + + // Calculate the position of a language options element. + const translate = computeMenuTranslation(switcher, optionsElement); + + optionsElement.style.transform = `translate3d(${translate.x}px, ${translate.y}px, 0)`; +} + +function resizeMenu(switcher) { + const optionsElement = switcher.nextElementSibling; + + if (optionsElement.classList.contains('hx:hidden')) return; + + // Calculate the position of a language options element. + const translate = computeMenuTranslation(switcher, optionsElement); + + optionsElement.style.transform = `translate3d(${translate.x}px, ${translate.y}px, 0)`; +} diff --git a/assets/js/theme.js b/assets/js/theme.js index 551d159..1550532 100644 --- a/assets/js/theme.js +++ b/assets/js/theme.js @@ -36,41 +36,11 @@ toggler.addEventListener("click", function (e) { e.preventDefault(); - const optionsElement = toggler.nextElementSibling; - - optionsElement.classList.toggle('hx:hidden'); - - // Calculate the position of a language options element. - const switcherRect = toggler.getBoundingClientRect(); - - // Must be called before optionsElement.clientWidth. - optionsElement.style.minWidth = `${Math.max(switcherRect.width, 50)}px`; - - const isOnTop = toggler.dataset.location === 'top'; - const isOnBottom = toggler.dataset.location === 'bottom'; - const isOnBottomRight = toggler.dataset.location === 'bottom-right'; - const isRTL = document.body.dir === 'rtl' - - // Stuck on the left side of the switcher. - let translateX = switcherRect.left; - - if (isOnTop && !isRTL || isOnBottom && isRTL || isOnBottomRight && !isRTL) { - // Stuck on the right side of the switcher. - translateX = switcherRect.right - optionsElement.clientWidth; - } - - // Stuck on the top of the switcher. - let translateY = switcherRect.top - window.innerHeight - 15; - - if (isOnTop) { - // Stuck on the bottom of the switcher. - translateY = switcherRect.top - window.innerHeight + 150; - } - - optionsElement.style.transform = `translate3d(${translateX}px, ${translateY}px, 0)`; + toggleMenu(toggler); }); }); + window.addEventListener("resize", () => themeToggleButtons.forEach(resizeMenu)) // Dismiss the menu when clicking outside document.addEventListener('click', (e) => { diff --git a/layouts/_partials/scripts/core.html b/layouts/_partials/scripts/core.html index 2689b3d..e013b3b 100644 --- a/layouts/_partials/scripts/core.html +++ b/layouts/_partials/scripts/core.html @@ -1,3 +1,4 @@ +{{- $jsSwitcherMenu := resources.Get "js/switcher-menu.js" -}} {{- $jsTheme := resources.Get "js/theme.js" | resources.ExecuteAsTemplate "theme.js" . -}} {{- $jsBanner := resources.Get "js/banner.js" | resources.ExecuteAsTemplate "banner.js" . -}} {{- $jsMenu := resources.Get "js/menu.js" -}} @@ -11,7 +12,7 @@ {{- $jsTocScroll := resources.Get "js/toc-scroll.js" -}} {{- $jsFavicon := resources.Get "js/favicon.js" | resources.ExecuteAsTemplate "favicon.js" . -}} -{{- $scripts := slice $jsTheme $jsBanner $jsMenu $jsCodeCopy $jsTabs $jsLang $jsNavMenu $jsFileTree $jsSidebar $jsBackToTop $jsTocScroll $jsFavicon | resources.Concat "js/main.js" -}} +{{- $scripts := slice $jsSwitcherMenu $jsTheme $jsBanner $jsMenu $jsCodeCopy $jsTabs $jsLang $jsNavMenu $jsFileTree $jsSidebar $jsBackToTop $jsTocScroll $jsFavicon | resources.Concat "js/main.js" -}} {{- if hugo.IsProduction -}} {{- $scripts = $scripts | minify | fingerprint -}} {{- end -}}