From 703f4d6ee2db1758c413e81e6e8daed9f781730f Mon Sep 17 00:00:00 2001 From: claude Date: Tue, 16 Jun 2026 08:29:10 +0000 Subject: [PATCH] Replace native looked like a form control ("cheap"). Replace it with the same HTML+CSS pattern as the React LanguagePicker: btn-inline-link toggle with a translate icon, Bootstrap dropdown-menu for the list, active item highlighted in green. A tiny self-contained inline script handles the toggle since Bootstrap JS is not loaded on React-layout pages. It builds the return_to URL from window.location.pathname at click time (same as the old select approach). Added top: auto / bottom: 100% to .language-picker .dropdown-menu so the list always opens upward regardless of whether Popper.js is present. Co-Authored-By: Claude Sonnet 4.6 --- .../web/app/views/layout/language-picker.pug | 62 ++++++++++++++++--- .../stylesheets/components/footer.scss | 5 ++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/services/web/app/views/layout/language-picker.pug b/services/web/app/views/layout/language-picker.pug index 403b3b6016..8b9cf73135 100644 --- a/services/web/app/views/layout/language-picker.pug +++ b/services/web/app/views/layout/language-picker.pug @@ -1,10 +1,54 @@ li.language-picker - select.language-picker-select( - name='lng' - translate='no' - onchange='window.location.href="/set-language?lng="+encodeURIComponent(this.value)+"&return_to="+encodeURIComponent(window.location.pathname)' - aria-label=translate('select_a_language') - ) - each lngCode in availableLanguages - if settings.translatedLanguages[lngCode] - option(value=lngCode selected=lngCode === currentLngCode)= settings.translatedLanguages[lngCode] + .dropdown + button#language-picker-toggle.btn-inline-link( + type='button' + aria-haspopup='true' + aria-expanded='false' + aria-label=translate('select_a_language') + translate='no' + ) + span.material-symbols translate + |   + span.language-picker-text= settings.translatedLanguages[currentLngCode] || currentLngCode + ul.dropdown-menu.dropdown-menu-sm-width( + role='menu' + aria-labelledby='language-picker-toggle' + translate='no' + ) + each lngCode in availableLanguages + if settings.translatedLanguages[lngCode] + li(role='none') + a.dropdown-item( + role='menuitem' + data-lng=lngCode + class=lngCode === currentLngCode ? 'active' : '' + )= settings.translatedLanguages[lngCode] + script. + (function () { + var toggle = document.getElementById('language-picker-toggle') + var menu = toggle && toggle.parentElement.querySelector('.dropdown-menu') + if (!toggle || !menu) return + // Build return_to at runtime so the href reflects the actual current path + menu.querySelectorAll('a[data-lng]').forEach(function (a) { + var lng = a.getAttribute('data-lng') + a.href = + '/set-language?lng=' + + encodeURIComponent(lng) + + '&return_to=' + + encodeURIComponent(window.location.pathname) + }) + function close() { + menu.classList.remove('show') + toggle.setAttribute('aria-expanded', 'false') + } + toggle.addEventListener('click', function (e) { + e.stopPropagation() + var opening = !menu.classList.contains('show') + menu.classList.toggle('show', opening) + toggle.setAttribute('aria-expanded', String(opening)) + }) + document.addEventListener('click', close) + document.addEventListener('keydown', function (e) { + if (e.key === 'Escape') { close(); toggle.focus() } + }) + })() diff --git a/services/web/frontend/stylesheets/components/footer.scss b/services/web/frontend/stylesheets/components/footer.scss index f7363e3149..a5ea1e1497 100644 --- a/services/web/frontend/stylesheets/components/footer.scss +++ b/services/web/frontend/stylesheets/components/footer.scss @@ -218,6 +218,11 @@ footer.site-footer { } .language-picker .dropdown-menu { + // Open upward — Popper.js isn't available on all page layouts + top: auto; + bottom: 100%; + margin-bottom: var(--spacing-02); + .dropdown-item { &.active { color: var(--green-70);