mirror of
https://github.com/imfing/hextra.git
synced 2025-09-14 07:07:17 -04:00
fix(navbar): menu positions (#804)
* fix: menu positions * refactor: factorize menu management and handle window resize * chore: the placement is better with +4 then +10 * chore: the placement is better with -10 than -15
This commit is contained in:

committed by
GitHub

parent
bbffff1f52
commit
82e25c0b0d
@@ -1,44 +1,18 @@
|
|||||||
(function () {
|
(function () {
|
||||||
const languageSwitchers = document.querySelectorAll('.hextra-language-switcher');
|
const languageSwitchers = document.querySelectorAll('.hextra-language-switcher');
|
||||||
|
|
||||||
languageSwitchers.forEach((switcher) => {
|
languageSwitchers.forEach((switcher) => {
|
||||||
switcher.addEventListener('click', (e) => {
|
switcher.addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
switcher.dataset.state = switcher.dataset.state === 'open' ? 'closed' : 'open';
|
switcher.dataset.state = switcher.dataset.state === 'open' ? 'closed' : 'open';
|
||||||
|
|
||||||
const optionsElement = switcher.nextElementSibling;
|
toggleMenu(switcher);
|
||||||
|
|
||||||
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)`;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener("resize", () => languageSwitchers.forEach(resizeMenu))
|
||||||
|
|
||||||
// Dismiss language switcher when clicking outside
|
// Dismiss language switcher when clicking outside
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
if (e.target.closest('.hextra-language-switcher') === null) {
|
if (e.target.closest('.hextra-language-switcher') === null) {
|
||||||
|
52
assets/js/switcher-menu.js
Normal file
52
assets/js/switcher-menu.js
Normal file
@@ -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)`;
|
||||||
|
}
|
@@ -36,41 +36,11 @@
|
|||||||
toggler.addEventListener("click", function (e) {
|
toggler.addEventListener("click", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const optionsElement = toggler.nextElementSibling;
|
toggleMenu(toggler);
|
||||||
|
|
||||||
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)`;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener("resize", () => themeToggleButtons.forEach(resizeMenu))
|
||||||
|
|
||||||
// Dismiss the menu when clicking outside
|
// Dismiss the menu when clicking outside
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
{{- $jsSwitcherMenu := resources.Get "js/switcher-menu.js" -}}
|
||||||
{{- $jsTheme := resources.Get "js/theme.js" | resources.ExecuteAsTemplate "theme.js" . -}}
|
{{- $jsTheme := resources.Get "js/theme.js" | resources.ExecuteAsTemplate "theme.js" . -}}
|
||||||
{{- $jsBanner := resources.Get "js/banner.js" | resources.ExecuteAsTemplate "banner.js" . -}}
|
{{- $jsBanner := resources.Get "js/banner.js" | resources.ExecuteAsTemplate "banner.js" . -}}
|
||||||
{{- $jsMenu := resources.Get "js/menu.js" -}}
|
{{- $jsMenu := resources.Get "js/menu.js" -}}
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
{{- $jsTocScroll := resources.Get "js/toc-scroll.js" -}}
|
{{- $jsTocScroll := resources.Get "js/toc-scroll.js" -}}
|
||||||
{{- $jsFavicon := resources.Get "js/favicon.js" | resources.ExecuteAsTemplate "favicon.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 -}}
|
{{- if hugo.IsProduction -}}
|
||||||
{{- $scripts = $scripts | minify | fingerprint -}}
|
{{- $scripts = $scripts | minify | fingerprint -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
Reference in New Issue
Block a user