diff --git a/browser/css/jsdialogs.css b/browser/css/jsdialogs.css index 6e7446987a79..6ac848a8f631 100644 --- a/browser/css/jsdialogs.css +++ b/browser/css/jsdialogs.css @@ -161,10 +161,6 @@ div#autoFillPreviewTooltip .lokdialog.ui-dialog-content.ui-widget-content { vertical-align: middle; } -.jsdialog.vertical:not(.sidebar):not(.ui-separator) { - width: 100%; -} - th.jsdialog:not(:first-child) { padding-inline-end: 24px; } diff --git a/browser/css/toolbar.css b/browser/css/toolbar.css index 14551d0aa387..d1f1453f9468 100644 --- a/browser/css/toolbar.css +++ b/browser/css/toolbar.css @@ -60,6 +60,22 @@ margin: 0px; } +/* overflow menu */ +.menu-overflow-wrapper { + position: absolute; + height: var(--header-height); + top: var(--header-height); + display: flex; + background-color: var(--color-background-lighter); + border: 1px solid var(--color-toolbar-border); + align-items: center; + border-radius: 4px; + padding: 0 4px; + box-shadow: 0 2px 6px 2px rgba(60, 64, 67, .15); + opacity: 0; + pointer-events: none; +} + /* status bar / mobile bottom bar */ #toolbar-down .ui-badge { diff --git a/browser/images/dark/lc_menuoverflow.svg b/browser/images/dark/lc_menuoverflow.svg new file mode 100644 index 000000000000..1b5ba0a22f6e --- /dev/null +++ b/browser/images/dark/lc_menuoverflow.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + diff --git a/browser/images/lc_menuoverflow.svg b/browser/images/lc_menuoverflow.svg new file mode 100644 index 000000000000..d4b90d9e6d17 --- /dev/null +++ b/browser/images/lc_menuoverflow.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + diff --git a/browser/src/control/Control.TopToolbar.js b/browser/src/control/Control.TopToolbar.js index 5101b0e41bab..a499d3f001b8 100644 --- a/browser/src/control/Control.TopToolbar.js +++ b/browser/src/control/Control.TopToolbar.js @@ -190,6 +190,7 @@ class TopToolbar extends JSDialog.Toolbar { {type: 'customtoolitem', id: 'insertannotation', text: _UNO('.uno:InsertAnnotation', '', true), visible: false, lockUno: '.uno:InsertAnnotation'}, {type: 'customtoolitem', id: 'inserthyperlink', command: 'inserthyperlink', text: _UNO('.uno:HyperlinkDialog', '', true), lockUno: '.uno:HyperlinkDialog'}, {type: 'toolitem', id: 'insertsymbol', text: _UNO('.uno:InsertSymbol', '', true), command: '.uno:InsertSymbol'}, + {type: 'customtoolitem', id: 'menuoverflow', text: _('More'), desktop: true, mobile: false, visible: true}, {type: 'spacer', id: 'topspacer'}, {type: 'separator', orientation: 'vertical', id: 'breaksidebar', visible: false}, {type: 'toolitem', id: 'sidebar', text: _UNO('.uno:Sidebar', '', true), command: '.uno:SidebarDeck.PropertyDeck', visible: false}, @@ -228,14 +229,123 @@ class TopToolbar extends JSDialog.Toolbar { } } + createOverflowMenu() { + const topBarMenu = this.parentContainer.querySelector( + '.root-container .vertical', + ); + + const overflowMenu = L.DomUtil.create( + 'div', + 'menu-overflow-wrapper', + this.parentContainer, + ); + + const overflowMenuButton = + this.parentContainer.querySelector('#menuoverflow'); + + const showOverflowMenu = () => { + overflowMenu.style.opacity = 1; + overflowMenu.style.pointerEvents = 'revert'; + L.DomUtil.addClass(overflowMenuButton, 'selected'); + }; + + const hideOverflowMenu = () => { + overflowMenu.style.opacity = 0; + overflowMenu.style.pointerEvents = 'none'; + L.DomUtil.removeClass(overflowMenuButton, 'selected'); + }; + + overflowMenuButton.addEventListener('click', () => { + if ( + overflowMenu.style.opacity === '0' || + overflowMenu.style.opacity === '' + ) { + showOverflowMenu(); + } else { + hideOverflowMenu(); + } + }); + + const breakSidebar = this.parentContainer.querySelector('#breaksidebar'); + const foldButton = this.parentContainer.querySelector('#fold'); + + const getMenuWidth = () => { + const splitPosition = + foldButton.offsetLeft + + foldButton.offsetWidth * 2 - + breakSidebar.offsetLeft; + return window.innerWidth - splitPosition; + }; + + let overflowMenuDebounced = 0; + const originalTopbar = topBarMenu.querySelectorAll('.jsdialog'); + + const overflowMenuHandler = () => { + overflowMenuDebounced && clearTimeout(overflowMenuDebounced); + + hideOverflowMenu(); + + overflowMenuDebounced = setTimeout(() => { + topBarMenu.replaceChildren(...originalTopbar); + + const topBarButtons = topBarMenu.querySelectorAll('.jsdialog:not(.hidden)'); + const menuWidth = getMenuWidth(); + + const overflowMenuOffscreen = document.createElement('div'); + overflowMenuOffscreen.className = 'menu-overfow-vertical'; + + let section = []; + let overflow = false; + + const appendSection = () => { + for (const element of section) { + overflowMenuOffscreen.appendChild(element); + } + section.length = 0; + }; + + for (const button of topBarButtons) { + if (button.id === 'topspacer' || button.id === 'menuoverflow') { + break; + } + + if (button.offsetLeft > menuWidth || overflow) { + overflow = true; + appendSection(); + overflowMenuOffscreen.appendChild(button); + } else if (button.className.includes('vertical')) { + section = [button]; + } else { + section.push(button); + } + } + + overflowMenu.replaceChildren(overflowMenuOffscreen); + + if (overflowMenuOffscreen.children.length <= 0) { + overflowMenuButton.style.display = 'none'; + } else { + overflowMenuButton.style.display = 'revert'; + } + + overflowMenu.style.left = + overflowMenuButton.offsetLeft - + overflowMenu.clientWidth + + overflowMenuButton.offsetWidth + + 'px'; + }, 250); + }; + + window.addEventListener('resize', overflowMenuHandler); + } + create() { this.reset(); var items = this.getToolItems(); this.builder.build(this.parentContainer, items); - JSDialog.MakeScrollable(this.parentContainer, this.parentContainer.querySelector('div')); - JSDialog.RefreshScrollables(); + this.createOverflowMenu(); if (this.map.isRestrictedUser()) { for (var i = 0; i < items.length; i++) { @@ -260,7 +370,7 @@ class TopToolbar extends JSDialog.Toolbar { this.onDocLayerInit(); // if app opens direct in compact mode then we need to set the saveState first - this.map.saveState = new app.definitions.saveState(this.map); + this.map.saveState = new app.definitions.saveState(this.map); } onDocLayerInit() {