diff --git a/modules/erp/direktverkauf/ui/index.php b/modules/erp/direktverkauf/ui/index.php index e5804a5..f20f50f 100644 --- a/modules/erp/direktverkauf/ui/index.php +++ b/modules/erp/direktverkauf/ui/index.php @@ -275,6 +275,7 @@ +

OTC-Verkauf

diff --git a/modules/shared/auth/ui/home.php b/modules/shared/auth/ui/home.php index 8157a4d..ea37a3b 100644 --- a/modules/shared/auth/ui/home.php +++ b/modules/shared/auth/ui/home.php @@ -193,6 +193,7 @@ function render_auth_home_page(array $user, array $otcProducts = []): void echo '
'; echo ''; echo ''; + echo ''; echo ''; diff --git a/modules/shared/auth/ui/login.php b/modules/shared/auth/ui/login.php index 409a4b4..95bd89e 100644 --- a/modules/shared/auth/ui/login.php +++ b/modules/shared/auth/ui/login.php @@ -25,6 +25,7 @@ function render_auth_login_page(array $state): void echo ''; echo ''; echo ''; + echo ''; echo '
'; echo '
'; diff --git a/public/scripts/help-icon-overlays.js b/public/scripts/help-icon-overlays.js new file mode 100644 index 0000000..3787cc3 --- /dev/null +++ b/public/scripts/help-icon-overlays.js @@ -0,0 +1,186 @@ +(function initHelpIconOverlayModule() { + const CLOSE_HANDLERS = { + '.sg-pulldown-demo': (root) => { + root.querySelectorAll('.sg-pulldown-demo').forEach((demo) => { + const trigger = demo.querySelector('.sg-pulldown-demo__trigger'); + demo.dataset.open = 'false'; + if (trigger) { + trigger.setAttribute('aria-expanded', 'false'); + } + }); + }, + '.sg-sandwich-menu-wrap': (root) => { + root.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => { + const button = wrap.querySelector('.sg-sandwich-button'); + wrap.dataset.open = 'false'; + if (button) { + button.setAttribute('aria-expanded', 'false'); + } + }); + }, + }; + + const getViewportWidth = () => { + if (window.visualViewport && typeof window.visualViewport.width === 'number') { + return window.visualViewport.width; + } + return window.innerWidth; + }; + + const getViewportHeight = () => { + if (window.visualViewport && typeof window.visualViewport.height === 'number') { + return window.visualViewport.height; + } + return window.innerHeight; + }; + + const getSafeInsetPx = () => { + const rootStyles = getComputedStyle(document.documentElement); + const spacingSmallRaw = rootStyles.getPropertyValue('--spacing-small').trim(); + const rootFontSize = parseFloat(rootStyles.fontSize) || 16; + const spacingSmallValue = parseFloat(spacingSmallRaw); + if (Number.isNaN(spacingSmallValue)) { + return 0; + } + if (spacingSmallRaw.endsWith('rem')) { + return spacingSmallValue * rootFontSize; + } + return spacingSmallValue; + }; + + const closeAllHelpIcons = (root) => { + root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => { + const button = wrap.querySelector('.sg-help-icon'); + const panel = wrap.querySelector('.sg-help-icon-panel'); + wrap.dataset.open = 'false'; + if (panel) { + panel.style.removeProperty('transform'); + panel.style.removeProperty('max-height'); + panel.style.removeProperty('overflow-y'); + } + if (button) { + button.setAttribute('aria-expanded', 'false'); + } + }); + }; + + const positionHelpPanel = (wrap, panel) => { + wrap.dataset.align = 'left'; + wrap.dataset.vertical = 'bottom'; + panel.style.removeProperty('transform'); + panel.style.removeProperty('max-height'); + panel.style.removeProperty('overflow-y'); + + const viewportWidth = getViewportWidth(); + const panelRect = panel.getBoundingClientRect(); + if (panelRect.right > viewportWidth) { + wrap.dataset.align = 'right'; + } + const alignedPanelRect = panel.getBoundingClientRect(); + if (alignedPanelRect.left < 0) { + wrap.dataset.align = 'left'; + } + + const clampedRect = panel.getBoundingClientRect(); + const safeInset = getSafeInsetPx(); + let shiftX = 0; + if (clampedRect.right > (viewportWidth - safeInset)) { + shiftX -= clampedRect.right - (viewportWidth - safeInset); + } + if ((clampedRect.left + shiftX) < safeInset) { + shiftX += safeInset - (clampedRect.left + shiftX); + } + if (shiftX !== 0) { + panel.style.transform = `translateX(${shiftX}px)`; + } + + const viewportHeight = getViewportHeight(); + const verticalSafeInset = getSafeInsetPx(); + const bottomRect = panel.getBoundingClientRect(); + if (bottomRect.bottom > (viewportHeight - verticalSafeInset)) { + wrap.dataset.vertical = 'top'; + const topRect = panel.getBoundingClientRect(); + if (topRect.top < verticalSafeInset) { + const wrapRect = wrap.getBoundingClientRect(); + const spaceAbove = Math.max(0, wrapRect.top - verticalSafeInset); + const spaceBelow = Math.max(0, viewportHeight - verticalSafeInset - wrapRect.bottom); + const useTop = spaceAbove >= spaceBelow; + wrap.dataset.vertical = useTop ? 'top' : 'bottom'; + const availableHeight = Math.max(96, Math.floor((useTop ? spaceAbove : spaceBelow) - verticalSafeInset)); + panel.style.maxHeight = `${availableHeight}px`; + panel.style.overflowY = 'auto'; + } + } + }; + + window.sgInitHelpIconOverlays = (options = {}) => { + const root = options.root || document; + const closeOnOpenSelectors = options.closeOnOpenSelectors || []; + const outsideClickIgnoreSelectors = options.outsideClickIgnoreSelectors || []; + + root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => { + if (wrap.dataset.helpIconInit === 'true') { + return; + } + wrap.dataset.helpIconInit = 'true'; + + const button = wrap.querySelector('.sg-help-icon'); + const panel = wrap.querySelector('.sg-help-icon-panel'); + if (!button || !panel) { + return; + } + + button.addEventListener('click', (event) => { + event.stopPropagation(); + const nextState = wrap.dataset.open !== 'true'; + + closeAllHelpIcons(root); + closeOnOpenSelectors.forEach((selector) => { + const handler = CLOSE_HANDLERS[selector]; + if (handler) { + handler(root); + } + }); + + if (!nextState) { + return; + } + + wrap.dataset.open = 'true'; + button.setAttribute('aria-expanded', 'true'); + positionHelpPanel(wrap, panel); + window.requestAnimationFrame(() => { + if (wrap.dataset.open === 'true') { + positionHelpPanel(wrap, panel); + } + }); + }); + }); + + const refreshOpenPanels = () => { + root.querySelectorAll('.sg-help-icon-wrap[data-open="true"]').forEach((wrap) => { + const panel = wrap.querySelector('.sg-help-icon-panel'); + if (panel) { + positionHelpPanel(wrap, panel); + } + }); + }; + + if (!window.sgHelpIconOverlayResizeBound) { + window.addEventListener('resize', refreshOpenPanels); + if (window.visualViewport && typeof window.visualViewport.addEventListener === 'function') { + window.visualViewport.addEventListener('resize', refreshOpenPanels); + } + window.sgHelpIconOverlayResizeBound = true; + } + + document.addEventListener('click', (event) => { + const isInsideIgnoredZone = ['.sg-help-icon-wrap', ...outsideClickIgnoreSelectors] + .some((selector) => event.target.closest(selector)); + if (isInsideIgnoredZone) { + return; + } + closeAllHelpIcons(root); + }); + }; +})();