diff --git a/src/bundle/Resources/encore/ibexa.js.config.js b/src/bundle/Resources/encore/ibexa.js.config.js index c7c09b3e1f..0539b9fe80 100644 --- a/src/bundle/Resources/encore/ibexa.js.config.js +++ b/src/bundle/Resources/encore/ibexa.js.config.js @@ -40,6 +40,7 @@ const layout = [ path.resolve(__dirname, '../public/js/scripts/admin.picker.js'), path.resolve(__dirname, '../public/js/scripts/admin.notifications.modal.js'), path.resolve(__dirname, '../public/js/scripts/sidebar/side.panel.js'), + path.resolve(__dirname, '../public/js/scripts/quick.action.manager.js'), path.resolve(__dirname, '../public/js/scripts/admin.location.add.translation.js'), path.resolve(__dirname, '../public/js/scripts/admin.form.autosubmit.js'), path.resolve(__dirname, '../public/js/scripts/admin.anchor.navigation'), diff --git a/src/bundle/Resources/public/js/scripts/admin.back.to.top.js b/src/bundle/Resources/public/js/scripts/admin.back.to.top.js index 6aec1a432d..763bef1484 100644 --- a/src/bundle/Resources/public/js/scripts/admin.back.to.top.js +++ b/src/bundle/Resources/public/js/scripts/admin.back.to.top.js @@ -1,5 +1,6 @@ -(function (global, doc) { +(function (global, doc, ibexa) { const backToTopBtn = doc.querySelector('.ibexa-back-to-top__btn'); + const backToTop = doc.querySelector('.ibexa-back-to-top'); const backToTopAnchor = doc.querySelector('.ibexa-back-to-top-anchor'); const backToTopScrollContainer = doc.querySelector('.ibexa-back-to-top-scroll-container'); @@ -7,12 +8,28 @@ return; } + const checkIsVisible = () => { + if (!backToTop) { + return false; + } + + return backToTopBtn.classList.contains('ibexa-back-to-top__btn--visible'); + }; const backToTopBtnTitle = backToTopBtn.querySelector('.ibexa-back-to-top__title'); let currentBackToTopAnchorHeight = backToTopAnchor.offsetHeight; const setBackToTopBtnTextVisibility = (container) => { const isTitleVisible = Math.abs(container.scrollHeight - container.scrollTop - container.clientHeight) <= 2; + const shouldBeVisible = container.scrollTop !== 0; + + if (backToTopBtn.classList.contains('ibexa-back-to-top__btn--visible') && !shouldBeVisible) { + backToTopBtn.classList.remove('ibexa-back-to-top__btn--visible'); + } + + if (!backToTopBtn.classList.contains('ibexa-back-to-top__btn--visible') && shouldBeVisible) { + backToTopBtn.classList.add('ibexa-back-to-top__btn--visible'); + ibexa.quickAction.recalculateButtonsLayout(); + } - backToTopBtn.classList.toggle('ibexa-back-to-top__btn--visible', container.scrollTop !== 0); backToTopBtn.classList.toggle('ibexa-btn--no-text', !isTitleVisible); backToTopBtnTitle.classList.toggle('ibexa-back-to-top__title--visible', isTitleVisible); }; @@ -37,6 +54,14 @@ setBackToTopBtnTextVisibility(backToTopScrollContainer); }); + const config = { + id: 'back-to-top', + zIndex: 10, + container: backToTop, + priority: 100, + checkVisibility: checkIsVisible, + }; + ibexa.quickAction.registerButton(config); resizeObserver.observe(backToTopAnchor); -})(window, window.document); +})(window, window.document, window.ibexa); diff --git a/src/bundle/Resources/public/js/scripts/core/backdrop.js b/src/bundle/Resources/public/js/scripts/core/backdrop.js index 2982ad4277..3daefd3e3e 100644 --- a/src/bundle/Resources/public/js/scripts/core/backdrop.js +++ b/src/bundle/Resources/public/js/scripts/core/backdrop.js @@ -28,6 +28,7 @@ if (this.backdrop) { this.backdrop.remove(); this.backdrop = null; + this.extraClasses = []; } } diff --git a/src/bundle/Resources/public/js/scripts/quick.action.manager.js b/src/bundle/Resources/public/js/scripts/quick.action.manager.js new file mode 100644 index 0000000000..a75fe01bb9 --- /dev/null +++ b/src/bundle/Resources/public/js/scripts/quick.action.manager.js @@ -0,0 +1,50 @@ +(function (global) { + const ACTION_BTN_VERTICAL_SPACING = 4.3; + let actionButtonConfigs = []; + + const registerButton = (config) => { + if (!config || !config.container || actionButtonConfigs.some((btn) => btn.id === config.id)) { + return; + } + + actionButtonConfigs = [...actionButtonConfigs, config].sort((a, b) => a.priority - b.priority); + recalculateButtonsLayout(); + }; + const unregisterButton = (id) => { + actionButtonConfigs = actionButtonConfigs.filter((btn) => btn.id !== id); + recalculateButtonsLayout(); + }; + const recalculateButtonsLayout = () => { + const buttonsToRender = actionButtonConfigs.filter((btn) => { + if (typeof btn.checkVisibility === 'function') { + const isVisible = btn.checkVisibility(); + + return isVisible; + } + + return false; + }); + + buttonsToRender.forEach((buttonConfig, index) => { + const { container } = buttonConfig; + + if (!container.style.transition) { + container.style.transition = 'all 0.3s ease-in-out'; + } + + container.style.position = 'fixed'; + container.style.right = '2rem'; + container.style.zIndex = buttonConfig.zIndex || 1040; + + const bottomPosition = `${index * ACTION_BTN_VERTICAL_SPACING + 2}rem`; + + container.style.bottom = bottomPosition; + }); + }; + + global.ibexa.quickAction = { + registerButton, + unregisterButton, + recalculateButtonsLayout, + }; +})(window); diff --git a/src/bundle/Resources/public/js/scripts/sidebar/side.panel.js b/src/bundle/Resources/public/js/scripts/sidebar/side.panel.js index 08123d75b4..48fa8891db 100644 --- a/src/bundle/Resources/public/js/scripts/sidebar/side.panel.js +++ b/src/bundle/Resources/public/js/scripts/sidebar/side.panel.js @@ -4,22 +4,42 @@ '.ibexa-side-panel .ibexa-btn--close, .ibexa-side-panel .ibexa-side-panel__btn--cancel', ); const sidePanelTriggers = [...doc.querySelectorAll('.ibexa-side-panel-trigger')]; - const backdrop = new ibexa.core.Backdrop(); - const removeBackdrop = () => { - backdrop.hide(); + const panelBackdrops = new Map(); + const defaultBackdrop = new ibexa.core.Backdrop(); + const removeBackdrop = (sidePanel) => { + const backdrop = panelBackdrops.get(sidePanel) || defaultBackdrop; + + backdrop.remove(); doc.body.classList.remove('ibexa-scroll-disabled'); + + if (panelBackdrops.has(sidePanel)) { + panelBackdrops.delete(sidePanel); + } }; - const showBackdrop = () => { - backdrop.show(); + const showBackdrop = (sidePanel) => { + if (sidePanel.dataset.backdropClasses) { + const extraClasses = sidePanel.dataset.backdropClasses.split(' ').filter(Boolean); + const newBackdrop = new ibexa.core.Backdrop({ extraClasses }); + + newBackdrop.show(); + panelBackdrops.set(sidePanel, newBackdrop); + } else { + defaultBackdrop.show(); + panelBackdrops.set(sidePanel, defaultBackdrop); + } + doc.body.classList.add('ibexa-scroll-disabled'); }; const toggleSidePanelVisibility = (sidePanel) => { const shouldBeVisible = sidePanel.classList.contains(CLASS_HIDDEN); const handleClickOutside = (event) => { - if (event.target.classList.contains('ibexa-backdrop')) { + const currentBackdrop = panelBackdrops.get(sidePanel); + + if (event.target.classList.contains('ibexa-backdrop') && event.target === currentBackdrop.get()) { + event.stopPropagation(); sidePanel.classList.add(CLASS_HIDDEN); - doc.body.removeEventListener('click', handleClickOutside, false); - removeBackdrop(); + doc.body.removeEventListener('click', handleClickOutside, { capture: true }); + removeBackdrop(sidePanel); if (sidePanel.dataset?.closeReload === 'true') { global.location.reload(); @@ -30,11 +50,11 @@ sidePanel.classList.toggle(CLASS_HIDDEN, !shouldBeVisible); if (shouldBeVisible) { - doc.body.addEventListener('click', handleClickOutside, false); - showBackdrop(); + doc.body.addEventListener('click', handleClickOutside, { capture: true }); + showBackdrop(sidePanel); } else { - doc.body.removeEventListener('click', handleClickOutside, false); - removeBackdrop(); + doc.body.removeEventListener('click', handleClickOutside, { capture: true }); + removeBackdrop(sidePanel); } }; diff --git a/src/bundle/Resources/public/scss/_back-to-top.scss b/src/bundle/Resources/public/scss/_back-to-top.scss index 764785efef..7a0ef57c8b 100644 --- a/src/bundle/Resources/public/scss/_back-to-top.scss +++ b/src/bundle/Resources/public/scss/_back-to-top.scss @@ -1,8 +1,4 @@ .ibexa-back-to-top { - position: fixed; - bottom: calculateRem(16px); - right: calculateRem(32px); - .btn.ibexa-back-to-top__btn { height: calculateRem(62px); min-width: calculateRem(62px); diff --git a/src/bundle/Resources/public/scss/_tabs.scss b/src/bundle/Resources/public/scss/_tabs.scss index 3476684911..361e5a8fe4 100644 --- a/src/bundle/Resources/public/scss/_tabs.scss +++ b/src/bundle/Resources/public/scss/_tabs.scss @@ -30,6 +30,13 @@ } } + &--no-corner { + .ibexa-tabs__link { + font-weight: 600; + background-color: $ibexa-color-light-400; + } + } + &--hidden { display: none; } diff --git a/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs.html.twig index 6bb38abbb1..2c9ea158ad 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs.html.twig @@ -16,6 +16,7 @@ active_tab, hide_toggler: hide_toggler|default(false), include_tab_more: include_tab_more|default(false), + tab_corner_disabled: tab_corner_disabled|default(false), } %} {% block tabs_list_after %} {{ tabs_list_after_content }} diff --git a/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_header.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_header.html.twig index a323d19957..ff0131ff06 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_header.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_header.html.twig @@ -17,6 +17,7 @@ label: tab.label, active: tab == active_tab, has_error: tab.has_error|default(false), + tab_corner_disabled: tab_corner_disabled|default(false), } %} {% endfor %} {% endblock %} diff --git a/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_tab.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_tab.html.twig index 3d1b9bc742..42d9045721 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_tab.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/tab/tabs_tab.html.twig @@ -10,5 +10,7 @@ label: tab.label, } %} {% endblock %} - {% include '@ibexadesign/ui/component/tab/tab_corner.html.twig' %} + {% if not tab_corner_disabled|default(false) %} + {% include '@ibexadesign/ui/component/tab/tab_corner.html.twig' %} + {% endif %} diff --git a/src/bundle/Resources/views/themes/admin/ui/layout.html.twig b/src/bundle/Resources/views/themes/admin/ui/layout.html.twig index e3ca18743f..38bd4c4d45 100644 --- a/src/bundle/Resources/views/themes/admin/ui/layout.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/layout.html.twig @@ -217,21 +217,23 @@ })|e('html_attr') }}">
- {% if not is_back_to_top_disabled|default(false) %} - {% block back_to_top %} -