From 96af16ef7089c0d7b118a64a2877acc59d9d66a2 Mon Sep 17 00:00:00 2001 From: Constantine Gosteev Date: Thu, 23 Jan 2025 00:46:14 +0200 Subject: [PATCH] move styles to admin theme + admin JS --- README.md | 2 +- composer.json | 6 +- etc/di.xml | 20 +++ etc/module.xml | 6 +- view/adminhtml/layout/default.xml | 2 +- view/adminhtml/web/css/styles.css | 77 ----------- view/adminhtml/web/js/acid-admin.js | 195 ++++++++++++++++++++++++++++ 7 files changed, 226 insertions(+), 82 deletions(-) create mode 100644 etc/di.xml delete mode 100644 view/adminhtml/web/css/styles.css create mode 100644 view/adminhtml/web/js/acid-admin.js diff --git a/README.md b/README.md index ef1c159..100bba9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is a helper module for [🧪Acid Unit](https://acid.7prism.com/) Adobe Commerce extensions to provide -admin panel configuration, menu item and styles. +admin panel configuration and menu item. There is no need to install it explicitly, it will be pulled up automatically as a dependency to other packages. diff --git a/composer.json b/composer.json index c9f9f7e..8306e19 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,13 @@ { "name": "acid-unit/module-admin", - "version": "0.1.1", + "version": "0.1.2", "description": "Admin panel configuration provider for [\uD83E\uDDEAAcid Unit] extensions", "type": "magento2-module", "require": { "php": ">=8.1", - "magento/framework": ">=103.0.4" + "magento/framework": ">=103.0.4", + "magento/module-theme": "*", + "acid-unit/theme-adminhtml-admin": "^0.1" }, "autoload": { "files": [ diff --git a/etc/di.xml b/etc/di.xml new file mode 100644 index 0000000..dd05d49 --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,20 @@ + + + + + + + + + + AcidUnit/admin + + + + diff --git a/etc/module.xml b/etc/module.xml index 5cbe205..6dde155 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -8,5 +8,9 @@ - + + + + + diff --git a/view/adminhtml/layout/default.xml b/view/adminhtml/layout/default.xml index d84f2ce..d80c37b 100644 --- a/view/adminhtml/layout/default.xml +++ b/view/adminhtml/layout/default.xml @@ -8,7 +8,7 @@ - + diff --git a/view/adminhtml/web/css/styles.css b/view/adminhtml/web/css/styles.css deleted file mode 100644 index 1c424c9..0000000 --- a/view/adminhtml/web/css/styles.css +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright © Acid Unit (https://acid.7prism.com). All rights reserved. - * See LICENSE file for license details. - */ - -:root { - --root-menu-icon-size: 22px; - --section-menu-icon-size: 18px; -} - -/* flask icon */ -.admin__menu li.item-acid-menu > a:before { - content: ''; - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgJy0vL1czQy8vRFREIFNWRyAxLjEvL0VOJyAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz4KPCEtLSBVcGxvYWRlZCB0bzogU1ZHIFJlcG8sIHd3dy5zdmdyZXBvLmNvbSwgR2VuZXJhdG9yOiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjgwMHB4IiB3aWR0aD0iODAwcHgiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUxMiA1MTIiPgogIDxnPgogICAgPGc+CiAgICAgIDxnPgogICAgICAgIDxwYXRoIGQ9Im00MTAuMyw0NjAuMmgtMzA4LjZjLTAuNSwwLTAuOSwwLTEuMywwbDExMy43LTE4NC41YzItMy4yIDMtNi45IDMtMTAuN3YtMjEzLjJoNzcuNnYyMTMuMmMwLDMuOCAxLDcuNSAzLDEwLjdsMTEzLjcsMTg0LjVjLTAuMywwLTAuNywwLTEuMSwwem00MC43LTE0LjJsLTExNS4yLTE4Ni44di0xODYuNmMxMC4zLTYuMSAxNi45LTE2LjIgMTYuOS0yNy43IDAtMTktMTcuNy0zMy45LTQwLjItMzMuOWgtMTEzYy0yMi41LDAtNDAuMiwxNC45LTQwLjIsMzMuOSAwLDExLjUgNi41LDIxLjYgMTYuOSwyNy43djE4Ni43bC0xMTUuMiwxODYuN2MtNi40LDEwLjQtNi43LDIyLjktMC44LDMzLjUgNy41LDEzLjMgMjMuNCwyMS41IDQxLjUsMjEuNWgzMDguNWMxOC4xLDAgMzQtOC4yIDQxLjUtMjEuNSA2LTEwLjYgNS43LTIzLjEtMC43LTMzLjV6Ii8+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPg=="); - background-repeat: no-repeat; - height: var(--root-menu-icon-size); - width: var(--root-menu-icon-size); - background-size: var(--root-menu-icon-size); - margin-left: auto; - margin-right: auto; - - /* set SVG color to #aaa6a0 */ - filter: invert(62%) sepia(1%) saturate(1319%) hue-rotate(357deg) brightness(108%) contrast(90%); -} - -/* flask icon on hover */ -.admin__menu li.item-acid-menu:hover > a:before { - /* set SVG color to #f7f3eb */ - filter: invert(98%) sepia(84%) saturate(360%) hue-rotate(297deg) brightness(105%) contrast(94%); -} - -/* separator */ -.admin__menu li.item-acid-menu > a:after { - background-color: #736963; - content: ''; - display: block; - height: 1px; - left: 0; - margin-left: 16%; - position: absolute; - top: 0; - width: 68%; -} - -/* GTM section */ -.section-config > .admin__collapsible-block > a#google_google_tag_manager-head { - display: flex; - align-items: center; -} - -/* Order for inner elements to have the correct offset */ -.section-config > .admin__collapsible-block > a#google_google_tag_manager-head > span:nth-child(1) { - order: 1; -} - -.section-config > .admin__collapsible-block > a#google_google_tag_manager-head > span:nth-child(2) { - order: 2; -} - -.section-config > .admin__collapsible-block > a#google_google_tag_manager-head > span:nth-child(3) { - order: 5; -} - -.section-config > .admin__collapsible-block > a#google_google_tag_manager-head > span:nth-child(4) { - order: 4; -} - -/* GTM section icon */ -.section-config > .admin__collapsible-block > a#google_google_tag_manager-head:after { - content: ''; - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLSBVcGxvYWRlZCB0bzogU1ZHIFJlcG8sIHd3dy5zdmdyZXBvLmNvbSwgR2VuZXJhdG9yOiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4KICAgIDxnPgogICAgICAgIDxwb2x5Z29uIGZpbGw9IiM4QUI0RjgiIHBvaW50cz0iMTUwLjI2MTgxOCAyNDUuNTE2MzY0IDEwNS44MjU0NTUgMjAyLjE4NTQ1NSAyMDEuMjU4MTgyIDEwNC43MzA5MDkgMjQ3LjI2NTQ1NSAxNDkuODIxODE4Ij4KDTwvcG9seWdvbj4KICAgICAgICA8cGF0aCBkPSJNMTUwLjQ1MDkwOSw1My45MzgxODE4IEwxMDYuMTc0NTQ1LDguNzMwOTA5MDkgTDkuMzYsMTA0LjYyOTA5MSBDLTMuMTIsMTE3LjEwOTA5MSAtMy4xMiwxMzcuMzQxODE4IDkuMzYsMTQ5LjgzNjM2NCBMMTA0LjcyLDI0NS44MjE4MTggTDE0OS44MTA5MDksMjAzLjY0IEw3Ny4xNTYzNjM2LDEyNy4yMzI3MjcgTDE1MC40NTA5MDksNTMuOTM4MTgxOCBaIiBmaWxsPSIjNDI4NUY0Ij4KDTwvcGF0aD4KICAgICAgICA8cGF0aCBkPSJNMjQ2LjYyNTQ1NSwxMDUuMzcwOTA5IEwxNTAuNjI1NDU1LDkuMzcwOTA5MDkgQzEzOC4xMzA5MDksLTMuMTIzNjM2MzYgMTE3Ljg2OTA5MSwtMy4xMjM2MzYzNiAxMDUuMzc0NTQ1LDkuMzcwOTA5MDkgQzkyLjg4LDIxLjg2NTQ1NDUgOTIuODgsNDIuMTI3MjcyNyAxMDUuMzc0NTQ1LDU0LjYyMTgxODIgTDIwMS4zNzQ1NDUsMTUwLjYyMTgxOCBDMjEzLjg2OTA5MSwxNjMuMTE2MzY0IDIzNC4xMzA5MDksMTYzLjExNjM2NCAyNDYuNjI1NDU1LDE1MC42MjE4MTggQzI1OS4xMiwxMzguMTI3MjczIDI1OS4xMiwxMTcuODY1NDU1IDI0Ni42MjU0NTUsMTA1LjM3MDkwOSBaIiBmaWxsPSIjOEFCNEY4Ij4KDTwvcGF0aD4KICAgICAgICA8Y2lyY2xlIGZpbGw9IiMyNDZGREIiIGN4PSIxMjcuMjY1NDU1IiBjeT0iMjI0LjczMDkwOSIgcj0iMzEuMjcyNzI3MyI+Cg08L2NpcmNsZT4KICAgIDwvZz4KPC9zdmc+"); - background-repeat: no-repeat; - height: var(--section-menu-icon-size); - width: var(--section-menu-icon-size); - background-size: var(--section-menu-icon-size); - order: 3; -} diff --git a/view/adminhtml/web/js/acid-admin.js b/view/adminhtml/web/js/acid-admin.js new file mode 100644 index 0000000..e94d292 --- /dev/null +++ b/view/adminhtml/web/js/acid-admin.js @@ -0,0 +1,195 @@ +/** + * Copyright © Acid Unit (https://acid.7prism.com). All rights reserved. + * See LICENSE file for license details. + */ + +/* eslint-disable max-depth, max-nested-callbacks */ + +require([ + 'jquery', + 'Magento_Ui/js/lib/view/utils/dom-observer', + 'domReady!' +], function ( + $, + domObserver +) { + 'use strict'; + + const scrollPositionForButtonToHide = 300, + highlightTime = 2000, + scrollToTime = 400, + map = { + gtm: { + href: 'google_google_tag_manager-head', + path: 'admin/system_config/edit/section/google', + text: 'Google Tag Manager' + }, + wysiwygEditor: { + href: 'row_cms_wysiwyg_enabled_for_pagebuilder_html_element', + path: 'admin/system_config/edit/section/cms', + text: 'WYSIWYG Editor' + }, + layeredNavigation: { + href: 'catalog_layered_navigation_acid_unit-head', + path: 'admin/system_config/edit/section/catalog', + text: 'Layered Navigation' + } + }; + + /** + * @param {HTMLElement} element + * @return {boolean} + */ + function isElementInViewport(element) { + const rect = element.getBoundingClientRect(), + viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight), + viewWidth = Math.max(document.documentElement.clientWidth, window.innerWidth); + + return !( + rect.bottom <= 0 || + rect.top - viewHeight >= 0 || + rect.left + rect.width <= 0 || + rect.right - rect.width >= viewWidth + ); + } + + /** + * @param {HTMLElement} element + */ + function highlight(element) { + element.classList.add('acid-highlight'); + + setTimeout(() => { + element.classList.remove('acid-highlight'); + }, highlightTime); + } + + /** + * @param {HTMLElement} element + * @param {string} id + */ + function createButton(element, id) { + const button = document.createElement('button'), + buttonWrapper = document.createElement('div'); + + let buttonText = ''; + + Object.keys(map).forEach(key => { + if (map[key].href === id) { + buttonText = map[key].text; + } + }); + + buttonWrapper.appendChild(button); + buttonWrapper.classList.add('acid-button-wrapper'); + button.classList.add('acid-button'); + button.classList.add('acid-button-visible'); + button.innerHTML = '🧪 ' + buttonText + '👇'; + + document.body.appendChild(buttonWrapper); + + // scroll to highlighted element when the button is clicked + button.addEventListener('click', () => { + if ($(element).is(':hidden')) { + element.closest('fieldset.admin__collapsible-block').style.display = 'block'; + } + + element.scrollIntoView({behavior: 'smooth', block: 'center'}); + button.classList.replace('acid-button-visible', 'acid-button-hidden'); + + setTimeout(() => { + highlight(element); + button.remove(); + }, scrollToTime); + }); + + // hide scroll to button when page is scrolled for more than 300px + $(document).on('scroll.button', () => { + const scroll = document.body.getBoundingClientRect().top * -1; + + if (scroll >= scrollPositionForButtonToHide) { + button.classList.replace('acid-button-visible', 'acid-button-hidden'); + + setTimeout(() => { + button.remove(); + }, scrollToTime); + + $(document).off('scroll.button'); + } + }); + + // hide scroll to button when admin collapsible block is clicked + document.querySelectorAll('.admin__collapsible-block').forEach(collapsible => { + collapsible.addEventListener('click', () => { + button.classList.replace('acid-button-visible', 'acid-button-hidden'); + + setTimeout(() => { + button.remove(); + }, scrollToTime); + }); + }); + } + + /** + * @param {HTMLElement} element + * @param {string} id + */ + function expandCollapsible(element, id) { + element.closest('fieldset.admin__collapsible-block').style.display = 'block'; + + if (isElementInViewport(element)) { + highlight(element); + } else { + createButton(element, id); + } + } + + /** + * @param {HTMLElement} element + * @param {string} id + */ + function handleElement(element, id) { + if (isElementInViewport(element)) { + highlight(element); + } else if ($(element).is(':hidden')) { + expandCollapsible(element, id); + } + } + + window.addEventListener('load', function () { + const acidLinks = document.querySelectorAll('.admin__menu li.item-acid-menu .item-acid-menu-item a'), + urlParams = new URLSearchParams(document.location.search), + url = new URL(window.location.href), + id = urlParams.get('h'); + + url.searchParams.delete('h'); + window.history.pushState({}, document.title, url); + + document.querySelectorAll('a').forEach(link => { + link.setAttribute('href', link.getAttribute('href').split('?h=')[0]); + }); + + if (id) { + const element = document.querySelector('#' + id); + + if (element) { + handleElement(element, id); + } else { + domObserver.get('#' + id, () => { + domObserver.off('#' + id); + handleElement(element, id); + }); + } + } + + acidLinks.forEach(link => { + const href = link.getAttribute('href'); + + Object.keys(map).forEach(key => { + if (href.includes(map[key].path)) { + link.setAttribute('href', href + '?h=' + map[key].href); + } + }); + }); + }); +});