From 881d6c1c4a5caefbe59b2cb7fedd537cd137050a Mon Sep 17 00:00:00 2001 From: "Philipps, Marc" <Marc.Philipps@adesso.de> Date: Wed, 26 Feb 2025 07:22:13 +0100 Subject: [PATCH 01/10] feat(frontend_editing): display icon_default from Paragraphs in overlay with improved styling Adjusted rendering logic so that when adding Paragraph entities via the frontend editing overlay, the icon_default from the Paragraphs module is displayed if available. Added CSS classes to enhance the visual appearance of the icon, ensuring a consistent and appealing user interface. --- css/frontend_editing.css | 171 +++++----- src/Controller/FrontendEditingController.php | 308 +++++++++++++------ 2 files changed, 308 insertions(+), 171 deletions(-) diff --git a/css/frontend_editing.css b/css/frontend_editing.css index 4bd208a..bf4b9d1 100644 --- a/css/frontend_editing.css +++ b/css/frontend_editing.css @@ -5,29 +5,29 @@ body.path-frontend-editing { } .editing-container { - height: 100%; position: fixed; + z-index: 1000; top: 0; right: 0; - z-index: 1000; - background-color: white; - box-shadow: -0.2rem 0 1rem rgb(116 116 116 / 40%); + overflow: auto; width: 30%; min-width: 300px; + height: 100%; transition: width 0.5s; - overflow: auto; + background-color: white; + box-shadow: -0.2rem 0 1rem rgb(116, 116, 116, 0.4); } .editing-container--wide { width: 80%; } .editing-container--loading { - animation-duration: 1.8s; - animation-fill-mode: forwards; - animation-iteration-count: infinite; animation-name: placeholder-shimmer; + animation-duration: 1.8s; animation-timing-function: linear; + animation-iteration-count: infinite; background: linear-gradient(to right, #f5f7fb 8%, #e7e7e7 38%, #f5f7fb 54%); background-size: 1000px 640px; + animation-fill-mode: forwards; } @keyframes placeholder-shimmer { 0% { @@ -40,14 +40,14 @@ body.path-frontend-editing { /* Styles for action buttons */ .editing-container__actions { + position: absolute; display: flex; - height: 0; align-items: center; justify-content: space-between; - padding: 0 1rem; - position: absolute; - width: 100%; box-sizing: border-box; + width: 100%; + height: 0; + padding: 0 1rem; } .editing-container__actions button { @@ -61,7 +61,8 @@ button.editing-container__close { height: 24px; cursor: pointer; border: none; - background: url('data:image/svg+xml,%3Csvg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M17 1L9 9l8 8M1 1l8 8-8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') center no-repeat; + background: url('data:image/svg+xml,%3Csvg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M17 1L9 9l8 8M1 1l8 8-8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') + center no-repeat; } /* Styles for width button */ @@ -70,28 +71,30 @@ button.editing-container__toggle { height: 24px; cursor: pointer; border: none; - background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') center no-repeat; + background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') + center no-repeat; } .editing-container--wide .editing-container__toggle { - background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" transform="rotate(180 5 9)"/%3E%3C/svg%3E') center no-repeat; + background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" transform="rotate(180 5 9)"/%3E%3C/svg%3E') + center no-repeat; } -/* Styles for iframe*/ +/* Styles for iframe */ #editing-container iframe { + width: 100%; height: 100%; border: none; - width: 100%; } .frontend-editing-preview-content, .frontend-editing-update-content { + visibility: hidden; overflow: hidden; - text-indent: -9999rem; + order: 100; width: 32px; height: 32px; - visibility: hidden; - order: 100; + text-indent: -9999rem; } /* Style container of editable elements */ @@ -99,7 +102,9 @@ button.editing-container__toggle { position: relative; } -.frontend-editing:has(.frontend-editing:hover) > .frontend-editing-actions .add-paragraphs { +.frontend-editing:has(.frontend-editing:hover) + > .frontend-editing-actions + .add-paragraphs { display: none; } @@ -107,20 +112,23 @@ button.editing-container__toggle { display: none; } -body:not(.frontend-editing--hidden) .frontend-editing:has(.add-paragraphs.hover-highlight) { +body:not(.frontend-editing--hidden) + .frontend-editing:has(.add-paragraphs.hover-highlight) { transition: padding ease-in-out 0.4s; } -body:not(.frontend-editing--hidden) .frontend-editing:has(.add-paragraphs.hover-highlight):hover { +body:not(.frontend-editing--hidden) + .frontend-editing:has(.add-paragraphs.hover-highlight):hover { padding: 25px 0; } body:not(.frontend-editing--hidden) .frontend-editing:hover { - outline: 3px solid rgba(var(--fe-editing-primary-color), 0.8); z-index: 10; + outline: 3px solid rgba(var(--fe-editing-primary-color), 0.8); } -body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hover) { +body:not(.frontend-editing--hidden) + .frontend-editing:has(.frontend-editing:hover) { outline: 3px solid rgba(var(--fe-editing-primary-color), 0.2); } @@ -128,40 +136,42 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove display: none; } -.frontend-editing:hover .frontend-editing:not(:hover) .frontend-editing-actions { +.frontend-editing:hover + .frontend-editing:not(:hover) + .frontend-editing-actions { display: none; } /* Styled for editing action */ .common-actions-container { - display: flex; position: absolute; + z-index: 2; top: 10px; left: 0; + display: flex; width: auto; - z-index: 2; } .title-edit-container, .icons-container { - margin-left: 0.5rem; margin-right: 0.5rem; + margin-left: 0.5rem; } .action-title { - opacity: 0; display: block; + align-self: center; width: 100%; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 15px; + white-space: nowrap; letter-spacing: 0.2em; pointer-events: none; - font-weight: 500; - font-size: 0.75rem; + opacity: 0; color: #222330; - white-space: nowrap; - align-self: center; - padding-left: 15px; - padding-top: 5px; - padding-bottom: 5px; + font-size: 0.75rem; + font-weight: 500; } .frontend-editing:hover .frontend-editing__action, @@ -172,23 +182,23 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove .frontend-editing:hover .title-edit-container, .frontend-editing:hover .icons-container { display: flex; - border-radius: 8px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border: 1px solid #d3d3d3; + border-radius: 8px; background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .frontend-editing-actions .ajax-progress { display: inline-flex; justify-content: center; + /* Ensure AJAX throbber is always last item */ + order: 6; width: 32px; height: 32px; padding: 0; - /* Ensure AJAX throbber is always last item */ - order: 6; opacity: 1; - background: #e8e8e8; border-left: 1px solid #dddcdc; + background: #e8e8e8; } .frontend-editing-actions .ajax-progress .throbber { @@ -197,28 +207,28 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove padding: 0; opacity: 0.4; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36' viewBox='0 0 24 24'%3E%3Cstyle%3E@keyframes spinner%7Bto%7Btransform:rotate(360deg)%7D%7D%3C/style%3E%3Cpath d='M12 4a8 8 0 0 1 7.89 6.7 1.53 1.53 0 0 0 1.49 1.3 1.5 1.5 0 0 0 1.48-1.75 11 11 0 0 0-21.72 0A1.5 1.5 0 0 0 2.62 12a1.53 1.53 0 0 0 1.49-1.3A8 8 0 0 1 12 4Z' style='transform-origin:center;animation:spinner .75s infinite linear'/%3E%3C/svg%3E"); - background-size: 18px; background-position: center; + background-size: 18px; } -.frontend-editing--outline:hover .frontend-editing-actions:before { +.frontend-editing--outline:hover .frontend-editing-actions::before { opacity: 1; } /* Style editing icon */ .frontend-editing__action { + z-index: 1; display: inline-block; + overflow: hidden; width: 37px; height: 32px; - z-index: 1; - opacity: 0; transition-duration: 0s; - background-position: center; - overflow: hidden; text-indent: -9999rem; - font-size: 0px; + opacity: 0; color: transparent; border-right: 1px solid #dddcdc; + background-position: center; + font-size: 0; } .frontend-editing__action--edit { @@ -239,23 +249,25 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove .frontend-editing__action--edit:hover, .frontend-editing__action--down:hover { - background-color: rgba(var(--fe-editing-primary-color), 0.25); border-top-right-radius: 7px; border-bottom-right-radius: 7px; + background-color: rgba(var(--fe-editing-primary-color), 0.25); } .frontend-editing__action--up:hover { - background-color: rgba(var(--fe-editing-primary-color), 0.25); border-top-left-radius: 7px; border-bottom-left-radius: 7px; + background-color: rgba(var(--fe-editing-primary-color), 0.25); } -.move-paragraphs.icons-container:not(:has(.frontend-editing__action--up)) .frontend-editing__action--down:hover { +.move-paragraphs.icons-container:not(:has(.frontend-editing__action--up)) + .frontend-editing__action--down:hover { border-top-left-radius: 7px; border-bottom-left-radius: 7px; } -.move-paragraphs.icons-container:not(:has(.frontend-editing__action--down)) .frontend-editing__action--up:hover { +.move-paragraphs.icons-container:not(:has(.frontend-editing__action--down)) + .frontend-editing__action--up:hover { border-top-right-radius: 7px; border-bottom-right-radius: 7px; } @@ -264,31 +276,31 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove border-right-width: 0; } -.frontend-editing__action:hover:before { +.frontend-editing__action:hover::before { opacity: 1; } .add-paragraphs { - height: 0; width: 0; + height: 0; } .add-paragraphs a { - display: flex; position: absolute; - left: 0; + z-index: 1; right: 0; + left: 0; + display: flex; + overflow: visible; width: fit-content; height: 25px; margin: auto; border: 0; - overflow: visible; - z-index: 1; } .add-paragraphs.hover-highlight a { - background-color: rgba(var(--fe-editing-primary-color), 0.25); width: 100%; + background-color: rgba(var(--fe-editing-primary-color), 0.25); } .add-paragraphs a:hover { @@ -296,7 +308,7 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove } .frontend-editing:hover .add-paragraphs.icons-container { - border-width: 0px; + border-width: 0; } .frontend-editing .move-paragraphs.icons-container:not(:has(*)) { @@ -315,26 +327,29 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove pointer-events: none; } -.frontend-editing__action:not(.frontend-editing__action--before):not(.frontend-editing__action--after):before { +.frontend-editing__action:not( + .frontend-editing__action--before, + .frontend-editing__action--after + )::before { display: block; - content: ''; width: 100%; height: 100%; - background-size: 16px; + content: ""; background-repeat: no-repeat; background-position: center; + background-size: 16px; } .frontend-editing__action--before::before, .frontend-editing__action--after::before { - content: ' '; + position: absolute; z-index: 10; - width: 40px; - height: 40px; - left: 0; right: 0; + left: 0; display: block; - position: absolute; + width: 40px; + height: 40px; + content: " "; } .frontend-editing__action--before::before { @@ -342,41 +357,41 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove } .frontend-editing__action--before svg { - pointer-events: none; z-index: 10; - margin: -1.5rem auto 0 auto; width: 40px; height: 40px; + margin: -1.5rem auto 0 auto; + pointer-events: none; color: rgb(var(--fe-editing-primary-color)); } .frontend-editing__action--after::before { + bottom: 0; margin: auto; margin-bottom: -1.5rem; - bottom: 0; } .frontend-editing__action--after svg { - pointer-events: none; z-index: 10; - margin: auto; - margin-bottom: -1.5rem; width: 40px; height: 40px; + margin: auto; + margin-bottom: -1.5rem; + pointer-events: none; color: rgb(var(--fe-editing-primary-color)); } -.frontend-editing__action--up:before { +.frontend-editing__action--up::before { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTIgNGExIDEgMCAwIDEgLjcwNy4yOTNsNyA3YTEgMSAwIDAgMS0xLjQxNCAxLjQxNEwxMyA3LjQxNFYxOWExIDEgMCAxIDEtMiAwVjcuNDE0bC01LjI5MyA1LjI5M2ExIDEgMCAwIDEtMS40MTQtMS40MTRsNy03QTEgMSAwIDAgMSAxMiA0WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+"); background-size: 20px; } -.frontend-editing__action--down:before { +.frontend-editing__action--down::before { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTMgNWExIDEgMCAxIDAtMiAwdjExLjU4NmwtNS4yOTMtNS4yOTNhMSAxIDAgMSAwLTEuNDE0IDEuNDE0bDYuOTk1IDYuOTk1QS45OTMuOTkzIDAgMCAwIDEyIDIwYS45OTcuOTk3IDAgMCAwIC43MTItLjI5OGw2Ljk5NS02Ljk5NWExIDEgMCAwIDAtMS40MTQtMS40MTRMMTMgMTYuNTg2VjVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4="); background-size: 20px; } -.frontend-editing__action--edit:before { +.frontend-editing__action--edit::before { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkgMy4xNzFhMS44MjkgMS44MjkgMCAwIDAtMS4yOTMuNTM2TDQuMzk1IDE3LjAxOWwtLjk3IDMuNTU2IDMuNTU2LS45N0wyMC4yOTMgNi4yOTNBMS44MjkgMS44MjkgMCAwIDAgMTkgMy4xN1ptLTEuNDY1LTEuNzA4YTMuODI5IDMuODI5IDAgMCAxIDQuMTcyIDYuMjQ0bC0xMy41IDEzLjVhMSAxIDAgMCAxLS40NDQuMjU4bC01LjUgMS41YTEgMSAwIDAgMS0xLjIyOC0xLjIyOGwxLjUtNS41YTEgMSAwIDAgMSAuMjU4LS40NDRsMTMuNS0xMy41YTMuODI5IDMuODI5IDAgMCAxIDEuMjQyLS44M1oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=="); } diff --git a/src/Controller/FrontendEditingController.php b/src/Controller/FrontendEditingController.php index b1dc981..26ff965 100644 --- a/src/Controller/FrontendEditingController.php +++ b/src/Controller/FrontendEditingController.php @@ -11,6 +11,7 @@ use Drupal\Core\Ajax\InvokeCommand; use Drupal\Core\Ajax\MessageCommand; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityFormBuilder; +use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Render\Element; use Drupal\Core\Render\RendererInterface; @@ -82,7 +83,13 @@ class FrontendEditingController extends ControllerBase { * @param \Drupal\user\UserDataInterface $userData * The user data storage. */ - public function __construct(RendererInterface $renderer, EntityFormBuilder $builder, EntityRepositoryInterface $entity_repository, ParagraphsHelperInterface $paragraphs_helper, UserDataInterface $userData) { + public function __construct( + RendererInterface $renderer, + EntityFormBuilder $builder, + EntityRepositoryInterface $entity_repository, + ParagraphsHelperInterface $paragraphs_helper, + UserDataInterface $userData, + ) { $this->renderer = $renderer; $this->builder = $builder; $this->entityRepository = $entity_repository; @@ -94,13 +101,11 @@ class FrontendEditingController extends ControllerBase { * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static( - $container->get('renderer'), + return new static($container->get('renderer'), $container->get('entity.form_builder'), $container->get('entity.repository'), $container->get('frontend_editing.paragraphs_helper'), - $container->get('user.data') - ); + $container->get('user.data')); } /** @@ -114,31 +119,42 @@ class FrontendEditingController extends ControllerBase { throw new NotFoundHttpException(); } // Get current state. - $current_state = (bool) $this->userData->get('frontend_editing', $this->currentUser()->id(), 'enabled'); + $current_state = (bool) $this->userData->get('frontend_editing', + $this->currentUser()->id(), 'enabled'); // Revert it, as requested. $new_state = !$current_state; // Set the new value. - $this->userData->set('frontend_editing', $this->currentUser()->id(), 'enabled', $new_state); + $this->userData->set('frontend_editing', $this->currentUser()->id(), + 'enabled', $new_state); // Prepare the response. $response = new AjaxResponse(); if ($new_state) { $message = $this->t('Frontend editing has been enabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'addClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('On')])); - $response->addCommand(new InvokeCommand('body', 'removeClass', ['frontend-editing--hidden'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'addClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'text', [$this->t('On')])); + $response->addCommand(new InvokeCommand('body', 'removeClass', + ['frontend-editing--hidden'])); } else { $message = $this->t('Frontend editing has been disabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('Off')])); - $response->addCommand(new InvokeCommand('body', 'addClass', ['frontend-editing--hidden'])); - } - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'status'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'attr', [ - 'data-toggle-state', - $new_state, - ])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing-toggle-not-configured'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'removeClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'text', [$this->t('Off')])); + $response->addCommand(new InvokeCommand('body', 'addClass', + ['frontend-editing--hidden'])); + } + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'status'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'attr', [ + 'data-toggle-state', + $new_state, + ])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'removeClass', ['frontend-editing-toggle-not-configured'])); return $response; } @@ -169,9 +185,9 @@ class FrontendEditingController extends ControllerBase { } $entity = $storage->load($id); if (!$entity) { - $this->messenger()->addWarning($this->t('Entity of type @type and id @id was not found', - ['@type' => $type, '@id' => $id] - )); + $this->messenger() + ->addWarning($this->t('Entity of type @type and id @id was not found', + ['@type' => $type, '@id' => $id])); return []; } // Remove all messages. @@ -232,7 +248,8 @@ class FrontendEditingController extends ControllerBase { $url = Url::fromRoute('entity.' . $type . '.edit_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, + $form_state_additions); $entityForm['#action'] = $url->toString(); $delete_url = Url::fromRoute('frontend_editing.form', [ @@ -244,7 +261,8 @@ class FrontendEditingController extends ControllerBase { if ($entity instanceof ParagraphInterface) { $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name) + ->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { $delete_access = FALSE; } @@ -297,7 +315,8 @@ class FrontendEditingController extends ControllerBase { // definition will identify that the field is translatable. $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name) + ->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { throw new AccessDeniedHttpException('You are not allowed to delete this paragraph, because paragraph parent field is not translatable.'); } @@ -314,13 +333,17 @@ class FrontendEditingController extends ControllerBase { else { $url = Url::fromRoute('entity.' . $type . '.delete_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, + $form_state_additions); if (function_exists('_gin_form_actions')) { // Remove sticky class from form actions. array_shift($entityForm['actions']['#attributes']['class']); } $entityForm['title'] = [ - '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', ['@type' => $entity->getEntityType()->getSingularLabel()]) . '</h3>', + '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', + [ + '@type' => $entity->getEntityType()->getSingularLabel(), + ]) . '</h3>', '#weight' => -10, ]; $entityForm['#action'] = $url->toString(); @@ -358,8 +381,14 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessAddType(ParagraphsTypeInterface $paragraphs_type, $parent_type, $parent, $parent_field_name) { - return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, $parent, $parent_field_name); + public function accessAddType( + ParagraphsTypeInterface $paragraphs_type, + $parent_type, + $parent, + $parent_field_name, + ) { + return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, + $parent, $parent_field_name); } /** @@ -369,7 +398,8 @@ class FrontendEditingController extends ControllerBase { * The access result. */ public function accessAdd($parent_type, $parent, $parent_field_name) { - return $this->paragraphsHelper->allowAdd($parent_type, $parent, $parent_field_name); + return $this->paragraphsHelper->allowAdd($parent_type, $parent, + $parent_field_name); } /** @@ -400,8 +430,15 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessUpdateContent($entity_type_id, $entity_id, $field_name, $view_mode) { - $entity = $this->entityTypeManager()->getStorage($entity_type_id)->load($entity_id); + public function accessUpdateContent( + $entity_type_id, + $entity_id, + $field_name, + $view_mode, + ) { + $entity = $this->entityTypeManager() + ->getStorage($entity_type_id) + ->load($entity_id); if (!$entity) { $result = AccessResult::forbidden('Entity does not exist.'); } @@ -429,26 +466,14 @@ class FrontendEditingController extends ControllerBase { $message = $this->t('The paragraph could not be moved up.'); } if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); + return $this->ajaxUpdateParagraphs($paragraph, $message, + $request->get('view_mode_id', 'default')); } if (!empty($message)) { $this->messenger()->addError($message); } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); - } - - /** - * Shift down a single paragraph. - */ - public function down(ParagraphInterface $paragraph, Request $request) { - $message = FALSE; - if (!$this->paragraphsHelper->move($paragraph, 'down')) { - $message = $this->t('The paragraph could not be moved down.'); - } - if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); - } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) + ->toString()); } /** @@ -464,10 +489,15 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - protected function ajaxUpdateParagraphs(ParagraphInterface $paragraph, $message, $view_mode_id = 'default') { + protected function ajaxUpdateParagraphs( + ParagraphInterface $paragraph, + $message, + $view_mode_id = 'default', + ) { $response = new AjaxResponse(); if ($message) { - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'error'])); } if ($view_mode_id == '_custom') { $view_mode_id = 'default'; @@ -476,11 +506,18 @@ class FrontendEditingController extends ControllerBase { $parent_entity = $paragraph->getParentEntity(); $parent_field_name = $paragraph->get('parent_field_name')->value; // Load the view display. We need to know whether it uses layout builder. - $view_display_id = implode('.', [$parent_entity->getEntityTypeId(), $parent_entity->bundle(), $view_mode_id]); + $view_display_id = implode('.', [ + $parent_entity->getEntityTypeId(), + $parent_entity->bundle(), + $view_mode_id, + ]); /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_display */ - $view_display = $this->entityTypeManager()->getStorage('entity_view_display')->load($view_display_id); + $view_display = $this->entityTypeManager() + ->getStorage('entity_view_display') + ->load($view_display_id); if ($view_display) { - $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', 'enabled'); + $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', + 'enabled'); if ($is_layout_builder) { $layout_builder_field_block_id_parts = [ 'field_block', @@ -488,8 +525,10 @@ class FrontendEditingController extends ControllerBase { $parent_entity->bundle(), $parent_field_name, ]; - $layout_builder_field_block_id = implode(':', $layout_builder_field_block_id_parts); - $sections = $view_display->getThirdPartySetting('layout_builder', 'sections'); + $layout_builder_field_block_id = implode(':', + $layout_builder_field_block_id_parts); + $sections = $view_display->getThirdPartySetting('layout_builder', + 'sections'); /** @var \Drupal\layout_builder\Section $section */ foreach ($sections as $section) { foreach ($section->getComponents() as $component) { @@ -512,11 +551,29 @@ class FrontendEditingController extends ControllerBase { $updated_content[$delta]['#parent_field_view_mode'] = $updated_content['#view_mode']; } } - $selector = '[data-frontend-editing="' . $paragraph->getParentEntity()->getEntityTypeId() . '--' . $paragraph->getParentEntity()->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; + $selector = '[data-frontend-editing="' . $paragraph->getParentEntity() + ->getEntityTypeId() . '--' . $paragraph->getParentEntity() + ->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; $response->addCommand(new HtmlCommand($selector, $updated_content)); return $response; } + /** + * Shift down a single paragraph. + */ + public function down(ParagraphInterface $paragraph, Request $request) { + $message = FALSE; + if (!$this->paragraphsHelper->move($paragraph, 'down')) { + $message = $this->t('The paragraph could not be moved down.'); + } + if ($request->isXmlHttpRequest()) { + return $this->ajaxUpdateParagraphs($paragraph, $message, + $request->get('view_mode_id', 'default')); + } + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) + ->toString()); + } + /** * Update content with ajax. * @@ -534,7 +591,13 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - public function updateContent($entity_type_id, $entity_id, $field_name, $view_mode, Request $request) { + public function updateContent( + $entity_type_id, + $entity_id, + $field_name, + $view_mode, + Request $request, + ) { if (!$request->isXmlHttpRequest()) { throw new NotFoundHttpException(); } @@ -550,15 +613,15 @@ class FrontendEditingController extends ControllerBase { } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id] - ); - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id]); + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'error'])); } if (!$entity) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id] - ); - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id]); + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'error'])); } // If there are errors, early return and reload the page. if (!empty($response->getCommands())) { @@ -604,9 +667,17 @@ class FrontendEditingController extends ControllerBase { * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public function paragraphAddPage($parent_type, $parent, $parent_field_name, $current_paragraph, $before, Request $request) { + public function paragraphAddPage( + $parent_type, + $parent, + $parent_field_name, + $current_paragraph, + $before, + Request $request, + ) { try { - $parent_entity = $this->entityTypeManager()->getStorage($parent_type) + $parent_entity = $this->entityTypeManager() + ->getStorage($parent_type) ->load($parent); } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { @@ -639,43 +710,64 @@ class FrontendEditingController extends ControllerBase { ->loadMultiple($allowed_paragraphs); $items = []; foreach ($allowed_paragraphs as $paragraphs_type) { - $items[$paragraphs_type->id()] = [ - '#type' => 'link', - '#title' => $this->t('Add @type', ['@type' => $paragraphs_type->label()]), - '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ - 'parent_type' => $parent_type, - 'parent' => $parent, - 'parent_field_name' => $parent_field_name, - 'paragraphs_type' => $paragraphs_type->id(), - 'current_paragraph' => $current_paragraph, - 'before' => $before, - ], [ - 'query' => $request->query->all(), - ]), + $item = [ + '#type' => 'container', '#attributes' => [ - 'class' => 'field-add-more-submit button--small button js-form-submit form-submit', - 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', + 'class' => [ + 'paragraphs-add-dialog-row', + 'field-add-more-submit', + 'button--large', + 'button', + 'js-form-submit', + 'form-submit', + ], ], - '#wrapper_attributes' => [ - 'class' => ['paragraphs-add-dialog-row'], + 'link' => [ + '#type' => 'link', + '#title' => $this->t('Add @type', + ['@type' => $paragraphs_type->label()]), + '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ + 'parent_type' => $parent_type, + 'parent' => $parent, + 'parent_field_name' => $parent_field_name, + 'paragraphs_type' => $paragraphs_type->id(), + 'current_paragraph' => $current_paragraph, + 'before' => $before, + ], [ + 'query' => $request->query->all(), + ]), + '#attributes' => [ + 'class' => [''], + 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', + ], ], ]; + + if (!empty($paragraphs_type->get('icon_default'))) { + $item['icon'] = $this->buildIconElement($paragraphs_type); + } + + $items[$paragraphs_type->id()] = $item; } if (!empty($settings['handler_settings']['target_bundles_drag_drop'])) { - uasort($settings['handler_settings']['target_bundles_drag_drop'], function ($a, $b) { - return $a['weight'] <=> $b['weight']; - }); - if (!empty($settings['handler_settings']['negate'])) { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { - return !$value['enabled']; + uasort($settings['handler_settings']['target_bundles_drag_drop'], + function ($a, $b) { + return $a['weight'] <=> $b['weight']; }); + if (!empty($settings['handler_settings']['negate'])) { + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], + function ($value) { + return !$value['enabled']; + }); } else { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { - return $value['enabled']; - }); + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], + function ($value) { + return $value['enabled']; + }); } - $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), $items); + $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), + $items); $items = array_values($items); } return [ @@ -693,4 +785,34 @@ class FrontendEditingController extends ControllerBase { ]; } + /** + * Builds the icon element for a given Paragraphs type. + * + * This method generates a render array for the icon element using the value + * from the 'icon_default' field. It assumes that an icon is present and + * should only be called when an icon is defined. + * + * @param \Drupal\paragraphs\ParagraphsTypeInterface $paragraphs_type + * The Paragraphs type entity. + * + * @return array + * A render array for the icon element. + */ + protected function buildIconElement( + EntityInterface $paragraphs_type, + ): array { + $icon = $paragraphs_type->get('icon_default'); + return [ + '#type' => 'container', + '#attributes' => [ + 'class' => ['paragraph-type-icon', $paragraphs_type->id()], + ], + 'image' => [ + '#theme' => 'image', + '#uri' => $icon, + '#alt' => $paragraphs_type->label(), + ], + ]; + } + } -- GitLab From 9d24982ce61ba45cd634b0cde631df26c2080405 Mon Sep 17 00:00:00 2001 From: "Philipps, Marc" <Marc.Philipps@adesso.de> Date: Thu, 27 Feb 2025 10:43:39 +0100 Subject: [PATCH 02/10] feat(frontend_editing): display icon_default from Paragraphs in overlay with improved styling Adjusted rendering logic so that when adding Paragraph entities via the frontend editing overlay, the icon_default from the Paragraphs module is displayed if available. Added CSS classes to enhance the visual appearance of the icon, ensuring a consistent and appealing user interface. --- css/forms_helper.css | 27 ++ src/Controller/FrontendEditingController.php | 264 +++++++------------ 2 files changed, 122 insertions(+), 169 deletions(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index 923516b..4a03ff1 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -35,6 +35,8 @@ body.path-frontend-editing { width: 100%; z-index: 2; background-color: #f5f7fb; + cursor: pointer; + text-decoration: none; } .path-frontend-editing .block-system-main-block > form { @@ -54,3 +56,28 @@ body.path-frontend-editing { .frontend-editing-hide-sticky .region-sticky { display: none; } + +.path-frontend-editing .paragraphs-add-dialog-row { + display: flex; + flex-direction: row; + align-items: center; + width: 100%; + gap: 10px; +} +.path-frontend-editing .paragraphs-add-dialog-row img { + width: 60px; + height: 60px; + object-fit: contain; + border-radius: 5px; + background: #fff; +} +.path-frontend-editing ul.paragraphs-add-dialog-list li { + list-style: none; +} +.path-frontend-editing .field-add-more-submit:hover a { + color: #fff; +} +.path-frontend-editing ul.paragraphs-add-dialog-list .button.button--small { + padding-left: unset; + border: unset; +} \ No newline at end of file diff --git a/src/Controller/FrontendEditingController.php b/src/Controller/FrontendEditingController.php index 26ff965..e2c4d84 100644 --- a/src/Controller/FrontendEditingController.php +++ b/src/Controller/FrontendEditingController.php @@ -83,13 +83,7 @@ class FrontendEditingController extends ControllerBase { * @param \Drupal\user\UserDataInterface $userData * The user data storage. */ - public function __construct( - RendererInterface $renderer, - EntityFormBuilder $builder, - EntityRepositoryInterface $entity_repository, - ParagraphsHelperInterface $paragraphs_helper, - UserDataInterface $userData, - ) { + public function __construct(RendererInterface $renderer, EntityFormBuilder $builder, EntityRepositoryInterface $entity_repository, ParagraphsHelperInterface $paragraphs_helper, UserDataInterface $userData) { $this->renderer = $renderer; $this->builder = $builder; $this->entityRepository = $entity_repository; @@ -101,11 +95,13 @@ class FrontendEditingController extends ControllerBase { * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static($container->get('renderer'), + return new static( + $container->get('renderer'), $container->get('entity.form_builder'), $container->get('entity.repository'), $container->get('frontend_editing.paragraphs_helper'), - $container->get('user.data')); + $container->get('user.data') + ); } /** @@ -119,42 +115,31 @@ class FrontendEditingController extends ControllerBase { throw new NotFoundHttpException(); } // Get current state. - $current_state = (bool) $this->userData->get('frontend_editing', - $this->currentUser()->id(), 'enabled'); + $current_state = (bool) $this->userData->get('frontend_editing', $this->currentUser()->id(), 'enabled'); // Revert it, as requested. $new_state = !$current_state; // Set the new value. - $this->userData->set('frontend_editing', $this->currentUser()->id(), - 'enabled', $new_state); + $this->userData->set('frontend_editing', $this->currentUser()->id(), 'enabled', $new_state); // Prepare the response. $response = new AjaxResponse(); if ($new_state) { $message = $this->t('Frontend editing has been enabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'addClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'text', [$this->t('On')])); - $response->addCommand(new InvokeCommand('body', 'removeClass', - ['frontend-editing--hidden'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'addClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('On')])); + $response->addCommand(new InvokeCommand('body', 'removeClass', ['frontend-editing--hidden'])); } else { $message = $this->t('Frontend editing has been disabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'removeClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'text', [$this->t('Off')])); - $response->addCommand(new InvokeCommand('body', 'addClass', - ['frontend-editing--hidden'])); - } - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'status'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'attr', [ - 'data-toggle-state', - $new_state, - ])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'removeClass', ['frontend-editing-toggle-not-configured'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('Off')])); + $response->addCommand(new InvokeCommand('body', 'addClass', ['frontend-editing--hidden'])); + } + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'status'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'attr', [ + 'data-toggle-state', + $new_state, + ])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing-toggle-not-configured'])); return $response; } @@ -185,9 +170,9 @@ class FrontendEditingController extends ControllerBase { } $entity = $storage->load($id); if (!$entity) { - $this->messenger() - ->addWarning($this->t('Entity of type @type and id @id was not found', - ['@type' => $type, '@id' => $id])); + $this->messenger()->addWarning($this->t('Entity of type @type and id @id was not found', + ['@type' => $type, '@id' => $id] + )); return []; } // Remove all messages. @@ -248,8 +233,7 @@ class FrontendEditingController extends ControllerBase { $url = Url::fromRoute('entity.' . $type . '.edit_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, - $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); $entityForm['#action'] = $url->toString(); $delete_url = Url::fromRoute('frontend_editing.form', [ @@ -261,8 +245,7 @@ class FrontendEditingController extends ControllerBase { if ($entity instanceof ParagraphInterface) { $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name) - ->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { $delete_access = FALSE; } @@ -315,8 +298,7 @@ class FrontendEditingController extends ControllerBase { // definition will identify that the field is translatable. $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name) - ->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { throw new AccessDeniedHttpException('You are not allowed to delete this paragraph, because paragraph parent field is not translatable.'); } @@ -333,17 +315,13 @@ class FrontendEditingController extends ControllerBase { else { $url = Url::fromRoute('entity.' . $type . '.delete_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, - $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); if (function_exists('_gin_form_actions')) { // Remove sticky class from form actions. array_shift($entityForm['actions']['#attributes']['class']); } $entityForm['title'] = [ - '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', - [ - '@type' => $entity->getEntityType()->getSingularLabel(), - ]) . '</h3>', + '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', ['@type' => $entity->getEntityType()->getSingularLabel()]) . '</h3>', '#weight' => -10, ]; $entityForm['#action'] = $url->toString(); @@ -381,14 +359,8 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessAddType( - ParagraphsTypeInterface $paragraphs_type, - $parent_type, - $parent, - $parent_field_name, - ) { - return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, - $parent, $parent_field_name); + public function accessAddType(ParagraphsTypeInterface $paragraphs_type, $parent_type, $parent, $parent_field_name) { + return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, $parent, $parent_field_name); } /** @@ -398,8 +370,7 @@ class FrontendEditingController extends ControllerBase { * The access result. */ public function accessAdd($parent_type, $parent, $parent_field_name) { - return $this->paragraphsHelper->allowAdd($parent_type, $parent, - $parent_field_name); + return $this->paragraphsHelper->allowAdd($parent_type, $parent, $parent_field_name); } /** @@ -430,15 +401,8 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessUpdateContent( - $entity_type_id, - $entity_id, - $field_name, - $view_mode, - ) { - $entity = $this->entityTypeManager() - ->getStorage($entity_type_id) - ->load($entity_id); + public function accessUpdateContent($entity_type_id, $entity_id, $field_name, $view_mode) { + $entity = $this->entityTypeManager()->getStorage($entity_type_id)->load($entity_id); if (!$entity) { $result = AccessResult::forbidden('Entity does not exist.'); } @@ -466,14 +430,26 @@ class FrontendEditingController extends ControllerBase { $message = $this->t('The paragraph could not be moved up.'); } if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, - $request->get('view_mode_id', 'default')); + return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); } if (!empty($message)) { $this->messenger()->addError($message); } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) - ->toString()); + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); + } + + /** + * Shift down a single paragraph. + */ + public function down(ParagraphInterface $paragraph, Request $request) { + $message = FALSE; + if (!$this->paragraphsHelper->move($paragraph, 'down')) { + $message = $this->t('The paragraph could not be moved down.'); + } + if ($request->isXmlHttpRequest()) { + return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); + } + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); } /** @@ -489,15 +465,10 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - protected function ajaxUpdateParagraphs( - ParagraphInterface $paragraph, - $message, - $view_mode_id = 'default', - ) { + protected function ajaxUpdateParagraphs(ParagraphInterface $paragraph, $message, $view_mode_id = 'default') { $response = new AjaxResponse(); if ($message) { - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'error'])); + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); } if ($view_mode_id == '_custom') { $view_mode_id = 'default'; @@ -506,18 +477,11 @@ class FrontendEditingController extends ControllerBase { $parent_entity = $paragraph->getParentEntity(); $parent_field_name = $paragraph->get('parent_field_name')->value; // Load the view display. We need to know whether it uses layout builder. - $view_display_id = implode('.', [ - $parent_entity->getEntityTypeId(), - $parent_entity->bundle(), - $view_mode_id, - ]); + $view_display_id = implode('.', [$parent_entity->getEntityTypeId(), $parent_entity->bundle(), $view_mode_id]); /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_display */ - $view_display = $this->entityTypeManager() - ->getStorage('entity_view_display') - ->load($view_display_id); + $view_display = $this->entityTypeManager()->getStorage('entity_view_display')->load($view_display_id); if ($view_display) { - $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', - 'enabled'); + $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', 'enabled'); if ($is_layout_builder) { $layout_builder_field_block_id_parts = [ 'field_block', @@ -525,10 +489,8 @@ class FrontendEditingController extends ControllerBase { $parent_entity->bundle(), $parent_field_name, ]; - $layout_builder_field_block_id = implode(':', - $layout_builder_field_block_id_parts); - $sections = $view_display->getThirdPartySetting('layout_builder', - 'sections'); + $layout_builder_field_block_id = implode(':', $layout_builder_field_block_id_parts); + $sections = $view_display->getThirdPartySetting('layout_builder', 'sections'); /** @var \Drupal\layout_builder\Section $section */ foreach ($sections as $section) { foreach ($section->getComponents() as $component) { @@ -551,29 +513,11 @@ class FrontendEditingController extends ControllerBase { $updated_content[$delta]['#parent_field_view_mode'] = $updated_content['#view_mode']; } } - $selector = '[data-frontend-editing="' . $paragraph->getParentEntity() - ->getEntityTypeId() . '--' . $paragraph->getParentEntity() - ->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; + $selector = '[data-frontend-editing="' . $paragraph->getParentEntity()->getEntityTypeId() . '--' . $paragraph->getParentEntity()->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; $response->addCommand(new HtmlCommand($selector, $updated_content)); return $response; } - /** - * Shift down a single paragraph. - */ - public function down(ParagraphInterface $paragraph, Request $request) { - $message = FALSE; - if (!$this->paragraphsHelper->move($paragraph, 'down')) { - $message = $this->t('The paragraph could not be moved down.'); - } - if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, - $request->get('view_mode_id', 'default')); - } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) - ->toString()); - } - /** * Update content with ajax. * @@ -591,13 +535,7 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - public function updateContent( - $entity_type_id, - $entity_id, - $field_name, - $view_mode, - Request $request, - ) { + public function updateContent($entity_type_id, $entity_id, $field_name, $view_mode, Request $request) { if (!$request->isXmlHttpRequest()) { throw new NotFoundHttpException(); } @@ -613,15 +551,15 @@ class FrontendEditingController extends ControllerBase { } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id]); - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id] + ); + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); } if (!$entity) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id]); - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id] + ); + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); } // If there are errors, early return and reload the page. if (!empty($response->getCommands())) { @@ -667,17 +605,9 @@ class FrontendEditingController extends ControllerBase { * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public function paragraphAddPage( - $parent_type, - $parent, - $parent_field_name, - $current_paragraph, - $before, - Request $request, - ) { + public function paragraphAddPage($parent_type, $parent, $parent_field_name, $current_paragraph, $before, Request $request) { try { - $parent_entity = $this->entityTypeManager() - ->getStorage($parent_type) + $parent_entity = $this->entityTypeManager()->getStorage($parent_type) ->load($parent); } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { @@ -722,52 +652,48 @@ class FrontendEditingController extends ControllerBase { 'form-submit', ], ], - 'link' => [ - '#type' => 'link', - '#title' => $this->t('Add @type', - ['@type' => $paragraphs_type->label()]), - '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ - 'parent_type' => $parent_type, - 'parent' => $parent, - 'parent_field_name' => $parent_field_name, - 'paragraphs_type' => $paragraphs_type->id(), - 'current_paragraph' => $current_paragraph, - 'before' => $before, - ], [ - 'query' => $request->query->all(), - ]), - '#attributes' => [ - 'class' => [''], - 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', - ], - ], ]; if (!empty($paragraphs_type->get('icon_default'))) { $item['icon'] = $this->buildIconElement($paragraphs_type); } + $item['link'] = [ + '#type' => 'link', + '#title' => $this->t('Add @type', ['@type' => $paragraphs_type->label()]), + '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ + 'parent_type' => $parent_type, + 'parent' => $parent, + 'parent_field_name' => $parent_field_name, + 'paragraphs_type' => $paragraphs_type->id(), + 'current_paragraph' => $current_paragraph, + 'before' => $before, + ], [ + 'query' => $request->query->all(), + ]), + '#attributes' => [ + 'class' => 'field-add-more-submit js-form-submit form-submit', + 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', + ], + ]; + $items[$paragraphs_type->id()] = $item; } if (!empty($settings['handler_settings']['target_bundles_drag_drop'])) { - uasort($settings['handler_settings']['target_bundles_drag_drop'], - function ($a, $b) { - return $a['weight'] <=> $b['weight']; - }); + uasort($settings['handler_settings']['target_bundles_drag_drop'], function ($a, $b) { + return $a['weight'] <=> $b['weight']; + }); if (!empty($settings['handler_settings']['negate'])) { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], - function ($value) { - return !$value['enabled']; - }); + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { + return !$value['enabled']; + }); } else { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], - function ($value) { - return $value['enabled']; - }); + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { + return $value['enabled']; + }); } - $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), - $items); + $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), $items); $items = array_values($items); } return [ -- GitLab From 80dfdece0e5fc424c13772155ef7cab6aa104e56 Mon Sep 17 00:00:00 2001 From: "Philipps, Marc" <Marc.Philipps@adesso.de> Date: Wed, 26 Feb 2025 07:22:13 +0100 Subject: [PATCH 03/10] feat(frontend_editing): display icon_default from Paragraphs in overlay with improved styling Adjusted rendering logic so that when adding Paragraph entities via the frontend editing overlay, the icon_default from the Paragraphs module is displayed if available. Added CSS classes to enhance the visual appearance of the icon, ensuring a consistent and appealing user interface. --- css/frontend_editing.css | 171 +++++----- src/Controller/FrontendEditingController.php | 308 +++++++++++++------ 2 files changed, 308 insertions(+), 171 deletions(-) diff --git a/css/frontend_editing.css b/css/frontend_editing.css index 4bd208a..bf4b9d1 100644 --- a/css/frontend_editing.css +++ b/css/frontend_editing.css @@ -5,29 +5,29 @@ body.path-frontend-editing { } .editing-container { - height: 100%; position: fixed; + z-index: 1000; top: 0; right: 0; - z-index: 1000; - background-color: white; - box-shadow: -0.2rem 0 1rem rgb(116 116 116 / 40%); + overflow: auto; width: 30%; min-width: 300px; + height: 100%; transition: width 0.5s; - overflow: auto; + background-color: white; + box-shadow: -0.2rem 0 1rem rgb(116, 116, 116, 0.4); } .editing-container--wide { width: 80%; } .editing-container--loading { - animation-duration: 1.8s; - animation-fill-mode: forwards; - animation-iteration-count: infinite; animation-name: placeholder-shimmer; + animation-duration: 1.8s; animation-timing-function: linear; + animation-iteration-count: infinite; background: linear-gradient(to right, #f5f7fb 8%, #e7e7e7 38%, #f5f7fb 54%); background-size: 1000px 640px; + animation-fill-mode: forwards; } @keyframes placeholder-shimmer { 0% { @@ -40,14 +40,14 @@ body.path-frontend-editing { /* Styles for action buttons */ .editing-container__actions { + position: absolute; display: flex; - height: 0; align-items: center; justify-content: space-between; - padding: 0 1rem; - position: absolute; - width: 100%; box-sizing: border-box; + width: 100%; + height: 0; + padding: 0 1rem; } .editing-container__actions button { @@ -61,7 +61,8 @@ button.editing-container__close { height: 24px; cursor: pointer; border: none; - background: url('data:image/svg+xml,%3Csvg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M17 1L9 9l8 8M1 1l8 8-8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') center no-repeat; + background: url('data:image/svg+xml,%3Csvg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M17 1L9 9l8 8M1 1l8 8-8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') + center no-repeat; } /* Styles for width button */ @@ -70,28 +71,30 @@ button.editing-container__toggle { height: 24px; cursor: pointer; border: none; - background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') center no-repeat; + background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E') + center no-repeat; } .editing-container--wide .editing-container__toggle { - background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" transform="rotate(180 5 9)"/%3E%3C/svg%3E') center no-repeat; + background: url('data:image/svg+xml,%3Csvg width="10" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M9 1L1 9l8 8" stroke="%23222330" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" transform="rotate(180 5 9)"/%3E%3C/svg%3E') + center no-repeat; } -/* Styles for iframe*/ +/* Styles for iframe */ #editing-container iframe { + width: 100%; height: 100%; border: none; - width: 100%; } .frontend-editing-preview-content, .frontend-editing-update-content { + visibility: hidden; overflow: hidden; - text-indent: -9999rem; + order: 100; width: 32px; height: 32px; - visibility: hidden; - order: 100; + text-indent: -9999rem; } /* Style container of editable elements */ @@ -99,7 +102,9 @@ button.editing-container__toggle { position: relative; } -.frontend-editing:has(.frontend-editing:hover) > .frontend-editing-actions .add-paragraphs { +.frontend-editing:has(.frontend-editing:hover) + > .frontend-editing-actions + .add-paragraphs { display: none; } @@ -107,20 +112,23 @@ button.editing-container__toggle { display: none; } -body:not(.frontend-editing--hidden) .frontend-editing:has(.add-paragraphs.hover-highlight) { +body:not(.frontend-editing--hidden) + .frontend-editing:has(.add-paragraphs.hover-highlight) { transition: padding ease-in-out 0.4s; } -body:not(.frontend-editing--hidden) .frontend-editing:has(.add-paragraphs.hover-highlight):hover { +body:not(.frontend-editing--hidden) + .frontend-editing:has(.add-paragraphs.hover-highlight):hover { padding: 25px 0; } body:not(.frontend-editing--hidden) .frontend-editing:hover { - outline: 3px solid rgba(var(--fe-editing-primary-color), 0.8); z-index: 10; + outline: 3px solid rgba(var(--fe-editing-primary-color), 0.8); } -body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hover) { +body:not(.frontend-editing--hidden) + .frontend-editing:has(.frontend-editing:hover) { outline: 3px solid rgba(var(--fe-editing-primary-color), 0.2); } @@ -128,40 +136,42 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove display: none; } -.frontend-editing:hover .frontend-editing:not(:hover) .frontend-editing-actions { +.frontend-editing:hover + .frontend-editing:not(:hover) + .frontend-editing-actions { display: none; } /* Styled for editing action */ .common-actions-container { - display: flex; position: absolute; + z-index: 2; top: 10px; left: 0; + display: flex; width: auto; - z-index: 2; } .title-edit-container, .icons-container { - margin-left: 0.5rem; margin-right: 0.5rem; + margin-left: 0.5rem; } .action-title { - opacity: 0; display: block; + align-self: center; width: 100%; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 15px; + white-space: nowrap; letter-spacing: 0.2em; pointer-events: none; - font-weight: 500; - font-size: 0.75rem; + opacity: 0; color: #222330; - white-space: nowrap; - align-self: center; - padding-left: 15px; - padding-top: 5px; - padding-bottom: 5px; + font-size: 0.75rem; + font-weight: 500; } .frontend-editing:hover .frontend-editing__action, @@ -172,23 +182,23 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove .frontend-editing:hover .title-edit-container, .frontend-editing:hover .icons-container { display: flex; - border-radius: 8px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border: 1px solid #d3d3d3; + border-radius: 8px; background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .frontend-editing-actions .ajax-progress { display: inline-flex; justify-content: center; + /* Ensure AJAX throbber is always last item */ + order: 6; width: 32px; height: 32px; padding: 0; - /* Ensure AJAX throbber is always last item */ - order: 6; opacity: 1; - background: #e8e8e8; border-left: 1px solid #dddcdc; + background: #e8e8e8; } .frontend-editing-actions .ajax-progress .throbber { @@ -197,28 +207,28 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove padding: 0; opacity: 0.4; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36' viewBox='0 0 24 24'%3E%3Cstyle%3E@keyframes spinner%7Bto%7Btransform:rotate(360deg)%7D%7D%3C/style%3E%3Cpath d='M12 4a8 8 0 0 1 7.89 6.7 1.53 1.53 0 0 0 1.49 1.3 1.5 1.5 0 0 0 1.48-1.75 11 11 0 0 0-21.72 0A1.5 1.5 0 0 0 2.62 12a1.53 1.53 0 0 0 1.49-1.3A8 8 0 0 1 12 4Z' style='transform-origin:center;animation:spinner .75s infinite linear'/%3E%3C/svg%3E"); - background-size: 18px; background-position: center; + background-size: 18px; } -.frontend-editing--outline:hover .frontend-editing-actions:before { +.frontend-editing--outline:hover .frontend-editing-actions::before { opacity: 1; } /* Style editing icon */ .frontend-editing__action { + z-index: 1; display: inline-block; + overflow: hidden; width: 37px; height: 32px; - z-index: 1; - opacity: 0; transition-duration: 0s; - background-position: center; - overflow: hidden; text-indent: -9999rem; - font-size: 0px; + opacity: 0; color: transparent; border-right: 1px solid #dddcdc; + background-position: center; + font-size: 0; } .frontend-editing__action--edit { @@ -239,23 +249,25 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove .frontend-editing__action--edit:hover, .frontend-editing__action--down:hover { - background-color: rgba(var(--fe-editing-primary-color), 0.25); border-top-right-radius: 7px; border-bottom-right-radius: 7px; + background-color: rgba(var(--fe-editing-primary-color), 0.25); } .frontend-editing__action--up:hover { - background-color: rgba(var(--fe-editing-primary-color), 0.25); border-top-left-radius: 7px; border-bottom-left-radius: 7px; + background-color: rgba(var(--fe-editing-primary-color), 0.25); } -.move-paragraphs.icons-container:not(:has(.frontend-editing__action--up)) .frontend-editing__action--down:hover { +.move-paragraphs.icons-container:not(:has(.frontend-editing__action--up)) + .frontend-editing__action--down:hover { border-top-left-radius: 7px; border-bottom-left-radius: 7px; } -.move-paragraphs.icons-container:not(:has(.frontend-editing__action--down)) .frontend-editing__action--up:hover { +.move-paragraphs.icons-container:not(:has(.frontend-editing__action--down)) + .frontend-editing__action--up:hover { border-top-right-radius: 7px; border-bottom-right-radius: 7px; } @@ -264,31 +276,31 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove border-right-width: 0; } -.frontend-editing__action:hover:before { +.frontend-editing__action:hover::before { opacity: 1; } .add-paragraphs { - height: 0; width: 0; + height: 0; } .add-paragraphs a { - display: flex; position: absolute; - left: 0; + z-index: 1; right: 0; + left: 0; + display: flex; + overflow: visible; width: fit-content; height: 25px; margin: auto; border: 0; - overflow: visible; - z-index: 1; } .add-paragraphs.hover-highlight a { - background-color: rgba(var(--fe-editing-primary-color), 0.25); width: 100%; + background-color: rgba(var(--fe-editing-primary-color), 0.25); } .add-paragraphs a:hover { @@ -296,7 +308,7 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove } .frontend-editing:hover .add-paragraphs.icons-container { - border-width: 0px; + border-width: 0; } .frontend-editing .move-paragraphs.icons-container:not(:has(*)) { @@ -315,26 +327,29 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove pointer-events: none; } -.frontend-editing__action:not(.frontend-editing__action--before):not(.frontend-editing__action--after):before { +.frontend-editing__action:not( + .frontend-editing__action--before, + .frontend-editing__action--after + )::before { display: block; - content: ''; width: 100%; height: 100%; - background-size: 16px; + content: ""; background-repeat: no-repeat; background-position: center; + background-size: 16px; } .frontend-editing__action--before::before, .frontend-editing__action--after::before { - content: ' '; + position: absolute; z-index: 10; - width: 40px; - height: 40px; - left: 0; right: 0; + left: 0; display: block; - position: absolute; + width: 40px; + height: 40px; + content: " "; } .frontend-editing__action--before::before { @@ -342,41 +357,41 @@ body:not(.frontend-editing--hidden) .frontend-editing:has(.frontend-editing:hove } .frontend-editing__action--before svg { - pointer-events: none; z-index: 10; - margin: -1.5rem auto 0 auto; width: 40px; height: 40px; + margin: -1.5rem auto 0 auto; + pointer-events: none; color: rgb(var(--fe-editing-primary-color)); } .frontend-editing__action--after::before { + bottom: 0; margin: auto; margin-bottom: -1.5rem; - bottom: 0; } .frontend-editing__action--after svg { - pointer-events: none; z-index: 10; - margin: auto; - margin-bottom: -1.5rem; width: 40px; height: 40px; + margin: auto; + margin-bottom: -1.5rem; + pointer-events: none; color: rgb(var(--fe-editing-primary-color)); } -.frontend-editing__action--up:before { +.frontend-editing__action--up::before { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTIgNGExIDEgMCAwIDEgLjcwNy4yOTNsNyA3YTEgMSAwIDAgMS0xLjQxNCAxLjQxNEwxMyA3LjQxNFYxOWExIDEgMCAxIDEtMiAwVjcuNDE0bC01LjI5MyA1LjI5M2ExIDEgMCAwIDEtMS40MTQtMS40MTRsNy03QTEgMSAwIDAgMSAxMiA0WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+"); background-size: 20px; } -.frontend-editing__action--down:before { +.frontend-editing__action--down::before { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTMgNWExIDEgMCAxIDAtMiAwdjExLjU4NmwtNS4yOTMtNS4yOTNhMSAxIDAgMSAwLTEuNDE0IDEuNDE0bDYuOTk1IDYuOTk1QS45OTMuOTkzIDAgMCAwIDEyIDIwYS45OTcuOTk3IDAgMCAwIC43MTItLjI5OGw2Ljk5NS02Ljk5NWExIDEgMCAwIDAtMS40MTQtMS40MTRMMTMgMTYuNTg2VjVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4="); background-size: 20px; } -.frontend-editing__action--edit:before { +.frontend-editing__action--edit::before { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkgMy4xNzFhMS44MjkgMS44MjkgMCAwIDAtMS4yOTMuNTM2TDQuMzk1IDE3LjAxOWwtLjk3IDMuNTU2IDMuNTU2LS45N0wyMC4yOTMgNi4yOTNBMS44MjkgMS44MjkgMCAwIDAgMTkgMy4xN1ptLTEuNDY1LTEuNzA4YTMuODI5IDMuODI5IDAgMCAxIDQuMTcyIDYuMjQ0bC0xMy41IDEzLjVhMSAxIDAgMCAxLS40NDQuMjU4bC01LjUgMS41YTEgMSAwIDAgMS0xLjIyOC0xLjIyOGwxLjUtNS41YTEgMSAwIDAgMSAuMjU4LS40NDRsMTMuNS0xMy41YTMuODI5IDMuODI5IDAgMCAxIDEuMjQyLS44M1oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=="); } diff --git a/src/Controller/FrontendEditingController.php b/src/Controller/FrontendEditingController.php index b1dc981..26ff965 100644 --- a/src/Controller/FrontendEditingController.php +++ b/src/Controller/FrontendEditingController.php @@ -11,6 +11,7 @@ use Drupal\Core\Ajax\InvokeCommand; use Drupal\Core\Ajax\MessageCommand; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityFormBuilder; +use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Render\Element; use Drupal\Core\Render\RendererInterface; @@ -82,7 +83,13 @@ class FrontendEditingController extends ControllerBase { * @param \Drupal\user\UserDataInterface $userData * The user data storage. */ - public function __construct(RendererInterface $renderer, EntityFormBuilder $builder, EntityRepositoryInterface $entity_repository, ParagraphsHelperInterface $paragraphs_helper, UserDataInterface $userData) { + public function __construct( + RendererInterface $renderer, + EntityFormBuilder $builder, + EntityRepositoryInterface $entity_repository, + ParagraphsHelperInterface $paragraphs_helper, + UserDataInterface $userData, + ) { $this->renderer = $renderer; $this->builder = $builder; $this->entityRepository = $entity_repository; @@ -94,13 +101,11 @@ class FrontendEditingController extends ControllerBase { * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static( - $container->get('renderer'), + return new static($container->get('renderer'), $container->get('entity.form_builder'), $container->get('entity.repository'), $container->get('frontend_editing.paragraphs_helper'), - $container->get('user.data') - ); + $container->get('user.data')); } /** @@ -114,31 +119,42 @@ class FrontendEditingController extends ControllerBase { throw new NotFoundHttpException(); } // Get current state. - $current_state = (bool) $this->userData->get('frontend_editing', $this->currentUser()->id(), 'enabled'); + $current_state = (bool) $this->userData->get('frontend_editing', + $this->currentUser()->id(), 'enabled'); // Revert it, as requested. $new_state = !$current_state; // Set the new value. - $this->userData->set('frontend_editing', $this->currentUser()->id(), 'enabled', $new_state); + $this->userData->set('frontend_editing', $this->currentUser()->id(), + 'enabled', $new_state); // Prepare the response. $response = new AjaxResponse(); if ($new_state) { $message = $this->t('Frontend editing has been enabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'addClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('On')])); - $response->addCommand(new InvokeCommand('body', 'removeClass', ['frontend-editing--hidden'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'addClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'text', [$this->t('On')])); + $response->addCommand(new InvokeCommand('body', 'removeClass', + ['frontend-editing--hidden'])); } else { $message = $this->t('Frontend editing has been disabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('Off')])); - $response->addCommand(new InvokeCommand('body', 'addClass', ['frontend-editing--hidden'])); - } - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'status'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'attr', [ - 'data-toggle-state', - $new_state, - ])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing-toggle-not-configured'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'removeClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'text', [$this->t('Off')])); + $response->addCommand(new InvokeCommand('body', 'addClass', + ['frontend-editing--hidden'])); + } + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'status'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'attr', [ + 'data-toggle-state', + $new_state, + ])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', + 'removeClass', ['frontend-editing-toggle-not-configured'])); return $response; } @@ -169,9 +185,9 @@ class FrontendEditingController extends ControllerBase { } $entity = $storage->load($id); if (!$entity) { - $this->messenger()->addWarning($this->t('Entity of type @type and id @id was not found', - ['@type' => $type, '@id' => $id] - )); + $this->messenger() + ->addWarning($this->t('Entity of type @type and id @id was not found', + ['@type' => $type, '@id' => $id])); return []; } // Remove all messages. @@ -232,7 +248,8 @@ class FrontendEditingController extends ControllerBase { $url = Url::fromRoute('entity.' . $type . '.edit_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, + $form_state_additions); $entityForm['#action'] = $url->toString(); $delete_url = Url::fromRoute('frontend_editing.form', [ @@ -244,7 +261,8 @@ class FrontendEditingController extends ControllerBase { if ($entity instanceof ParagraphInterface) { $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name) + ->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { $delete_access = FALSE; } @@ -297,7 +315,8 @@ class FrontendEditingController extends ControllerBase { // definition will identify that the field is translatable. $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name) + ->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { throw new AccessDeniedHttpException('You are not allowed to delete this paragraph, because paragraph parent field is not translatable.'); } @@ -314,13 +333,17 @@ class FrontendEditingController extends ControllerBase { else { $url = Url::fromRoute('entity.' . $type . '.delete_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, + $form_state_additions); if (function_exists('_gin_form_actions')) { // Remove sticky class from form actions. array_shift($entityForm['actions']['#attributes']['class']); } $entityForm['title'] = [ - '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', ['@type' => $entity->getEntityType()->getSingularLabel()]) . '</h3>', + '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', + [ + '@type' => $entity->getEntityType()->getSingularLabel(), + ]) . '</h3>', '#weight' => -10, ]; $entityForm['#action'] = $url->toString(); @@ -358,8 +381,14 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessAddType(ParagraphsTypeInterface $paragraphs_type, $parent_type, $parent, $parent_field_name) { - return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, $parent, $parent_field_name); + public function accessAddType( + ParagraphsTypeInterface $paragraphs_type, + $parent_type, + $parent, + $parent_field_name, + ) { + return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, + $parent, $parent_field_name); } /** @@ -369,7 +398,8 @@ class FrontendEditingController extends ControllerBase { * The access result. */ public function accessAdd($parent_type, $parent, $parent_field_name) { - return $this->paragraphsHelper->allowAdd($parent_type, $parent, $parent_field_name); + return $this->paragraphsHelper->allowAdd($parent_type, $parent, + $parent_field_name); } /** @@ -400,8 +430,15 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessUpdateContent($entity_type_id, $entity_id, $field_name, $view_mode) { - $entity = $this->entityTypeManager()->getStorage($entity_type_id)->load($entity_id); + public function accessUpdateContent( + $entity_type_id, + $entity_id, + $field_name, + $view_mode, + ) { + $entity = $this->entityTypeManager() + ->getStorage($entity_type_id) + ->load($entity_id); if (!$entity) { $result = AccessResult::forbidden('Entity does not exist.'); } @@ -429,26 +466,14 @@ class FrontendEditingController extends ControllerBase { $message = $this->t('The paragraph could not be moved up.'); } if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); + return $this->ajaxUpdateParagraphs($paragraph, $message, + $request->get('view_mode_id', 'default')); } if (!empty($message)) { $this->messenger()->addError($message); } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); - } - - /** - * Shift down a single paragraph. - */ - public function down(ParagraphInterface $paragraph, Request $request) { - $message = FALSE; - if (!$this->paragraphsHelper->move($paragraph, 'down')) { - $message = $this->t('The paragraph could not be moved down.'); - } - if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); - } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) + ->toString()); } /** @@ -464,10 +489,15 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - protected function ajaxUpdateParagraphs(ParagraphInterface $paragraph, $message, $view_mode_id = 'default') { + protected function ajaxUpdateParagraphs( + ParagraphInterface $paragraph, + $message, + $view_mode_id = 'default', + ) { $response = new AjaxResponse(); if ($message) { - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'error'])); } if ($view_mode_id == '_custom') { $view_mode_id = 'default'; @@ -476,11 +506,18 @@ class FrontendEditingController extends ControllerBase { $parent_entity = $paragraph->getParentEntity(); $parent_field_name = $paragraph->get('parent_field_name')->value; // Load the view display. We need to know whether it uses layout builder. - $view_display_id = implode('.', [$parent_entity->getEntityTypeId(), $parent_entity->bundle(), $view_mode_id]); + $view_display_id = implode('.', [ + $parent_entity->getEntityTypeId(), + $parent_entity->bundle(), + $view_mode_id, + ]); /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_display */ - $view_display = $this->entityTypeManager()->getStorage('entity_view_display')->load($view_display_id); + $view_display = $this->entityTypeManager() + ->getStorage('entity_view_display') + ->load($view_display_id); if ($view_display) { - $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', 'enabled'); + $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', + 'enabled'); if ($is_layout_builder) { $layout_builder_field_block_id_parts = [ 'field_block', @@ -488,8 +525,10 @@ class FrontendEditingController extends ControllerBase { $parent_entity->bundle(), $parent_field_name, ]; - $layout_builder_field_block_id = implode(':', $layout_builder_field_block_id_parts); - $sections = $view_display->getThirdPartySetting('layout_builder', 'sections'); + $layout_builder_field_block_id = implode(':', + $layout_builder_field_block_id_parts); + $sections = $view_display->getThirdPartySetting('layout_builder', + 'sections'); /** @var \Drupal\layout_builder\Section $section */ foreach ($sections as $section) { foreach ($section->getComponents() as $component) { @@ -512,11 +551,29 @@ class FrontendEditingController extends ControllerBase { $updated_content[$delta]['#parent_field_view_mode'] = $updated_content['#view_mode']; } } - $selector = '[data-frontend-editing="' . $paragraph->getParentEntity()->getEntityTypeId() . '--' . $paragraph->getParentEntity()->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; + $selector = '[data-frontend-editing="' . $paragraph->getParentEntity() + ->getEntityTypeId() . '--' . $paragraph->getParentEntity() + ->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; $response->addCommand(new HtmlCommand($selector, $updated_content)); return $response; } + /** + * Shift down a single paragraph. + */ + public function down(ParagraphInterface $paragraph, Request $request) { + $message = FALSE; + if (!$this->paragraphsHelper->move($paragraph, 'down')) { + $message = $this->t('The paragraph could not be moved down.'); + } + if ($request->isXmlHttpRequest()) { + return $this->ajaxUpdateParagraphs($paragraph, $message, + $request->get('view_mode_id', 'default')); + } + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) + ->toString()); + } + /** * Update content with ajax. * @@ -534,7 +591,13 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - public function updateContent($entity_type_id, $entity_id, $field_name, $view_mode, Request $request) { + public function updateContent( + $entity_type_id, + $entity_id, + $field_name, + $view_mode, + Request $request, + ) { if (!$request->isXmlHttpRequest()) { throw new NotFoundHttpException(); } @@ -550,15 +613,15 @@ class FrontendEditingController extends ControllerBase { } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id] - ); - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id]); + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'error'])); } if (!$entity) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id] - ); - $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id]); + $response->addCommand(new MessageCommand($message, NULL, + ['type' => 'error'])); } // If there are errors, early return and reload the page. if (!empty($response->getCommands())) { @@ -604,9 +667,17 @@ class FrontendEditingController extends ControllerBase { * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public function paragraphAddPage($parent_type, $parent, $parent_field_name, $current_paragraph, $before, Request $request) { + public function paragraphAddPage( + $parent_type, + $parent, + $parent_field_name, + $current_paragraph, + $before, + Request $request, + ) { try { - $parent_entity = $this->entityTypeManager()->getStorage($parent_type) + $parent_entity = $this->entityTypeManager() + ->getStorage($parent_type) ->load($parent); } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { @@ -639,43 +710,64 @@ class FrontendEditingController extends ControllerBase { ->loadMultiple($allowed_paragraphs); $items = []; foreach ($allowed_paragraphs as $paragraphs_type) { - $items[$paragraphs_type->id()] = [ - '#type' => 'link', - '#title' => $this->t('Add @type', ['@type' => $paragraphs_type->label()]), - '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ - 'parent_type' => $parent_type, - 'parent' => $parent, - 'parent_field_name' => $parent_field_name, - 'paragraphs_type' => $paragraphs_type->id(), - 'current_paragraph' => $current_paragraph, - 'before' => $before, - ], [ - 'query' => $request->query->all(), - ]), + $item = [ + '#type' => 'container', '#attributes' => [ - 'class' => 'field-add-more-submit button--small button js-form-submit form-submit', - 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', + 'class' => [ + 'paragraphs-add-dialog-row', + 'field-add-more-submit', + 'button--large', + 'button', + 'js-form-submit', + 'form-submit', + ], ], - '#wrapper_attributes' => [ - 'class' => ['paragraphs-add-dialog-row'], + 'link' => [ + '#type' => 'link', + '#title' => $this->t('Add @type', + ['@type' => $paragraphs_type->label()]), + '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ + 'parent_type' => $parent_type, + 'parent' => $parent, + 'parent_field_name' => $parent_field_name, + 'paragraphs_type' => $paragraphs_type->id(), + 'current_paragraph' => $current_paragraph, + 'before' => $before, + ], [ + 'query' => $request->query->all(), + ]), + '#attributes' => [ + 'class' => [''], + 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', + ], ], ]; + + if (!empty($paragraphs_type->get('icon_default'))) { + $item['icon'] = $this->buildIconElement($paragraphs_type); + } + + $items[$paragraphs_type->id()] = $item; } if (!empty($settings['handler_settings']['target_bundles_drag_drop'])) { - uasort($settings['handler_settings']['target_bundles_drag_drop'], function ($a, $b) { - return $a['weight'] <=> $b['weight']; - }); - if (!empty($settings['handler_settings']['negate'])) { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { - return !$value['enabled']; + uasort($settings['handler_settings']['target_bundles_drag_drop'], + function ($a, $b) { + return $a['weight'] <=> $b['weight']; }); + if (!empty($settings['handler_settings']['negate'])) { + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], + function ($value) { + return !$value['enabled']; + }); } else { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { - return $value['enabled']; - }); + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], + function ($value) { + return $value['enabled']; + }); } - $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), $items); + $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), + $items); $items = array_values($items); } return [ @@ -693,4 +785,34 @@ class FrontendEditingController extends ControllerBase { ]; } + /** + * Builds the icon element for a given Paragraphs type. + * + * This method generates a render array for the icon element using the value + * from the 'icon_default' field. It assumes that an icon is present and + * should only be called when an icon is defined. + * + * @param \Drupal\paragraphs\ParagraphsTypeInterface $paragraphs_type + * The Paragraphs type entity. + * + * @return array + * A render array for the icon element. + */ + protected function buildIconElement( + EntityInterface $paragraphs_type, + ): array { + $icon = $paragraphs_type->get('icon_default'); + return [ + '#type' => 'container', + '#attributes' => [ + 'class' => ['paragraph-type-icon', $paragraphs_type->id()], + ], + 'image' => [ + '#theme' => 'image', + '#uri' => $icon, + '#alt' => $paragraphs_type->label(), + ], + ]; + } + } -- GitLab From 457aecf0fc929407c5ffd08c53aa9fa796fd2687 Mon Sep 17 00:00:00 2001 From: "Philipps, Marc" <Marc.Philipps@adesso.de> Date: Thu, 27 Feb 2025 10:43:39 +0100 Subject: [PATCH 04/10] feat(frontend_editing): display icon_default from Paragraphs in overlay with improved styling Adjusted rendering logic so that when adding Paragraph entities via the frontend editing overlay, the icon_default from the Paragraphs module is displayed if available. Added CSS classes to enhance the visual appearance of the icon, ensuring a consistent and appealing user interface. --- css/forms_helper.css | 31 +++ src/Controller/FrontendEditingController.php | 264 +++++++------------ 2 files changed, 126 insertions(+), 169 deletions(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index da3443a..7e41bc1 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -35,6 +35,8 @@ body.path-frontend-editing { width: 100%; z-index: 2; background-color: #f5f7fb; + cursor: pointer; + text-decoration: none; } .path-frontend-editing .block-system-main-block > form { @@ -68,3 +70,32 @@ body.frontend-editing-hide-sidebar.gin--horizontal-toolbar, body.frontend-editing-hide-sidebar.gin--classic-toolbar { padding-inline-start: 0 !important; } + +.path-frontend-editing .paragraphs-add-dialog-row { + display: flex; + flex-direction: row; + align-items: center; + width: 100%; + gap: 10px; +} + +.path-frontend-editing .paragraphs-add-dialog-row img { + width: 60px; + height: 60px; + object-fit: contain; + border-radius: 5px; + background: #fff; +} + +.path-frontend-editing ul.paragraphs-add-dialog-list li { + list-style: none; +} + +.path-frontend-editing .field-add-more-submit:hover a { + color: #fff; +} + +.path-frontend-editing ul.paragraphs-add-dialog-list .button.button--small { + padding-left: unset; + border: unset; +} diff --git a/src/Controller/FrontendEditingController.php b/src/Controller/FrontendEditingController.php index 26ff965..e2c4d84 100644 --- a/src/Controller/FrontendEditingController.php +++ b/src/Controller/FrontendEditingController.php @@ -83,13 +83,7 @@ class FrontendEditingController extends ControllerBase { * @param \Drupal\user\UserDataInterface $userData * The user data storage. */ - public function __construct( - RendererInterface $renderer, - EntityFormBuilder $builder, - EntityRepositoryInterface $entity_repository, - ParagraphsHelperInterface $paragraphs_helper, - UserDataInterface $userData, - ) { + public function __construct(RendererInterface $renderer, EntityFormBuilder $builder, EntityRepositoryInterface $entity_repository, ParagraphsHelperInterface $paragraphs_helper, UserDataInterface $userData) { $this->renderer = $renderer; $this->builder = $builder; $this->entityRepository = $entity_repository; @@ -101,11 +95,13 @@ class FrontendEditingController extends ControllerBase { * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static($container->get('renderer'), + return new static( + $container->get('renderer'), $container->get('entity.form_builder'), $container->get('entity.repository'), $container->get('frontend_editing.paragraphs_helper'), - $container->get('user.data')); + $container->get('user.data') + ); } /** @@ -119,42 +115,31 @@ class FrontendEditingController extends ControllerBase { throw new NotFoundHttpException(); } // Get current state. - $current_state = (bool) $this->userData->get('frontend_editing', - $this->currentUser()->id(), 'enabled'); + $current_state = (bool) $this->userData->get('frontend_editing', $this->currentUser()->id(), 'enabled'); // Revert it, as requested. $new_state = !$current_state; // Set the new value. - $this->userData->set('frontend_editing', $this->currentUser()->id(), - 'enabled', $new_state); + $this->userData->set('frontend_editing', $this->currentUser()->id(), 'enabled', $new_state); // Prepare the response. $response = new AjaxResponse(); if ($new_state) { $message = $this->t('Frontend editing has been enabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'addClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'text', [$this->t('On')])); - $response->addCommand(new InvokeCommand('body', 'removeClass', - ['frontend-editing--hidden'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'addClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('On')])); + $response->addCommand(new InvokeCommand('body', 'removeClass', ['frontend-editing--hidden'])); } else { $message = $this->t('Frontend editing has been disabled.'); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'removeClass', ['frontend-editing--enabled'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'text', [$this->t('Off')])); - $response->addCommand(new InvokeCommand('body', 'addClass', - ['frontend-editing--hidden'])); - } - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'status'])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'attr', [ - 'data-toggle-state', - $new_state, - ])); - $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', - 'removeClass', ['frontend-editing-toggle-not-configured'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing--enabled'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'text', [$this->t('Off')])); + $response->addCommand(new InvokeCommand('body', 'addClass', ['frontend-editing--hidden'])); + } + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'status'])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'attr', [ + 'data-toggle-state', + $new_state, + ])); + $response->addCommand(new InvokeCommand('#frontend-editing-toggle-link', 'removeClass', ['frontend-editing-toggle-not-configured'])); return $response; } @@ -185,9 +170,9 @@ class FrontendEditingController extends ControllerBase { } $entity = $storage->load($id); if (!$entity) { - $this->messenger() - ->addWarning($this->t('Entity of type @type and id @id was not found', - ['@type' => $type, '@id' => $id])); + $this->messenger()->addWarning($this->t('Entity of type @type and id @id was not found', + ['@type' => $type, '@id' => $id] + )); return []; } // Remove all messages. @@ -248,8 +233,7 @@ class FrontendEditingController extends ControllerBase { $url = Url::fromRoute('entity.' . $type . '.edit_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, - $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); $entityForm['#action'] = $url->toString(); $delete_url = Url::fromRoute('frontend_editing.form', [ @@ -261,8 +245,7 @@ class FrontendEditingController extends ControllerBase { if ($entity instanceof ParagraphInterface) { $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name) - ->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { $delete_access = FALSE; } @@ -315,8 +298,7 @@ class FrontendEditingController extends ControllerBase { // definition will identify that the field is translatable. $parent_field_name = $entity->get('parent_field_name')->value; $parent_entity = $entity->getParentEntity(); - $parent_field_definition = $parent_entity->get($parent_field_name) - ->getFieldDefinition(); + $parent_field_definition = $parent_entity->get($parent_field_name)->getFieldDefinition(); if ($parent_entity->isTranslatable() && !$parent_entity->isDefaultTranslation() && !$parent_field_definition->isTranslatable()) { throw new AccessDeniedHttpException('You are not allowed to delete this paragraph, because paragraph parent field is not translatable.'); } @@ -333,17 +315,13 @@ class FrontendEditingController extends ControllerBase { else { $url = Url::fromRoute('entity.' . $type . '.delete_form', [$type => $id]); } - $entityForm = $this->builder->getForm($entity, $display, - $form_state_additions); + $entityForm = $this->builder->getForm($entity, $display, $form_state_additions); if (function_exists('_gin_form_actions')) { // Remove sticky class from form actions. array_shift($entityForm['actions']['#attributes']['class']); } $entityForm['title'] = [ - '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', - [ - '@type' => $entity->getEntityType()->getSingularLabel(), - ]) . '</h3>', + '#markup' => '<h3>' . $this->t('Are you sure you want to delete this @type?', ['@type' => $entity->getEntityType()->getSingularLabel()]) . '</h3>', '#weight' => -10, ]; $entityForm['#action'] = $url->toString(); @@ -381,14 +359,8 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessAddType( - ParagraphsTypeInterface $paragraphs_type, - $parent_type, - $parent, - $parent_field_name, - ) { - return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, - $parent, $parent_field_name); + public function accessAddType(ParagraphsTypeInterface $paragraphs_type, $parent_type, $parent, $parent_field_name) { + return $this->paragraphsHelper->allowAddType($paragraphs_type, $parent_type, $parent, $parent_field_name); } /** @@ -398,8 +370,7 @@ class FrontendEditingController extends ControllerBase { * The access result. */ public function accessAdd($parent_type, $parent, $parent_field_name) { - return $this->paragraphsHelper->allowAdd($parent_type, $parent, - $parent_field_name); + return $this->paragraphsHelper->allowAdd($parent_type, $parent, $parent_field_name); } /** @@ -430,15 +401,8 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessUpdateContent( - $entity_type_id, - $entity_id, - $field_name, - $view_mode, - ) { - $entity = $this->entityTypeManager() - ->getStorage($entity_type_id) - ->load($entity_id); + public function accessUpdateContent($entity_type_id, $entity_id, $field_name, $view_mode) { + $entity = $this->entityTypeManager()->getStorage($entity_type_id)->load($entity_id); if (!$entity) { $result = AccessResult::forbidden('Entity does not exist.'); } @@ -466,14 +430,26 @@ class FrontendEditingController extends ControllerBase { $message = $this->t('The paragraph could not be moved up.'); } if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, - $request->get('view_mode_id', 'default')); + return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); } if (!empty($message)) { $this->messenger()->addError($message); } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) - ->toString()); + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); + } + + /** + * Shift down a single paragraph. + */ + public function down(ParagraphInterface $paragraph, Request $request) { + $message = FALSE; + if (!$this->paragraphsHelper->move($paragraph, 'down')) { + $message = $this->t('The paragraph could not be moved down.'); + } + if ($request->isXmlHttpRequest()) { + return $this->ajaxUpdateParagraphs($paragraph, $message, $request->get('view_mode_id', 'default')); + } + return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph)->toString()); } /** @@ -489,15 +465,10 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - protected function ajaxUpdateParagraphs( - ParagraphInterface $paragraph, - $message, - $view_mode_id = 'default', - ) { + protected function ajaxUpdateParagraphs(ParagraphInterface $paragraph, $message, $view_mode_id = 'default') { $response = new AjaxResponse(); if ($message) { - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'error'])); + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); } if ($view_mode_id == '_custom') { $view_mode_id = 'default'; @@ -506,18 +477,11 @@ class FrontendEditingController extends ControllerBase { $parent_entity = $paragraph->getParentEntity(); $parent_field_name = $paragraph->get('parent_field_name')->value; // Load the view display. We need to know whether it uses layout builder. - $view_display_id = implode('.', [ - $parent_entity->getEntityTypeId(), - $parent_entity->bundle(), - $view_mode_id, - ]); + $view_display_id = implode('.', [$parent_entity->getEntityTypeId(), $parent_entity->bundle(), $view_mode_id]); /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_display */ - $view_display = $this->entityTypeManager() - ->getStorage('entity_view_display') - ->load($view_display_id); + $view_display = $this->entityTypeManager()->getStorage('entity_view_display')->load($view_display_id); if ($view_display) { - $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', - 'enabled'); + $is_layout_builder = (bool) $view_display->getThirdPartySetting('layout_builder', 'enabled'); if ($is_layout_builder) { $layout_builder_field_block_id_parts = [ 'field_block', @@ -525,10 +489,8 @@ class FrontendEditingController extends ControllerBase { $parent_entity->bundle(), $parent_field_name, ]; - $layout_builder_field_block_id = implode(':', - $layout_builder_field_block_id_parts); - $sections = $view_display->getThirdPartySetting('layout_builder', - 'sections'); + $layout_builder_field_block_id = implode(':', $layout_builder_field_block_id_parts); + $sections = $view_display->getThirdPartySetting('layout_builder', 'sections'); /** @var \Drupal\layout_builder\Section $section */ foreach ($sections as $section) { foreach ($section->getComponents() as $component) { @@ -551,29 +513,11 @@ class FrontendEditingController extends ControllerBase { $updated_content[$delta]['#parent_field_view_mode'] = $updated_content['#view_mode']; } } - $selector = '[data-frontend-editing="' . $paragraph->getParentEntity() - ->getEntityTypeId() . '--' . $paragraph->getParentEntity() - ->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; + $selector = '[data-frontend-editing="' . $paragraph->getParentEntity()->getEntityTypeId() . '--' . $paragraph->getParentEntity()->id() . '--' . $paragraph->get('parent_field_name')->value . '--' . $view_mode_id . '"]'; $response->addCommand(new HtmlCommand($selector, $updated_content)); return $response; } - /** - * Shift down a single paragraph. - */ - public function down(ParagraphInterface $paragraph, Request $request) { - $message = FALSE; - if (!$this->paragraphsHelper->move($paragraph, 'down')) { - $message = $this->t('The paragraph could not be moved down.'); - } - if ($request->isXmlHttpRequest()) { - return $this->ajaxUpdateParagraphs($paragraph, $message, - $request->get('view_mode_id', 'default')); - } - return new RedirectResponse($this->paragraphsHelper->getRedirectUrl($paragraph) - ->toString()); - } - /** * Update content with ajax. * @@ -591,13 +535,7 @@ class FrontendEditingController extends ControllerBase { * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response. */ - public function updateContent( - $entity_type_id, - $entity_id, - $field_name, - $view_mode, - Request $request, - ) { + public function updateContent($entity_type_id, $entity_id, $field_name, $view_mode, Request $request) { if (!$request->isXmlHttpRequest()) { throw new NotFoundHttpException(); } @@ -613,15 +551,15 @@ class FrontendEditingController extends ControllerBase { } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id]); - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id] + ); + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); } if (!$entity) { $message = $this->t('Entity of type @type and id @id was not found', - ['@type' => $entity_type_id, '@id' => $entity_id]); - $response->addCommand(new MessageCommand($message, NULL, - ['type' => 'error'])); + ['@type' => $entity_type_id, '@id' => $entity_id] + ); + $response->addCommand(new MessageCommand($message, NULL, ['type' => 'error'])); } // If there are errors, early return and reload the page. if (!empty($response->getCommands())) { @@ -667,17 +605,9 @@ class FrontendEditingController extends ControllerBase { * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public function paragraphAddPage( - $parent_type, - $parent, - $parent_field_name, - $current_paragraph, - $before, - Request $request, - ) { + public function paragraphAddPage($parent_type, $parent, $parent_field_name, $current_paragraph, $before, Request $request) { try { - $parent_entity = $this->entityTypeManager() - ->getStorage($parent_type) + $parent_entity = $this->entityTypeManager()->getStorage($parent_type) ->load($parent); } catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { @@ -722,52 +652,48 @@ class FrontendEditingController extends ControllerBase { 'form-submit', ], ], - 'link' => [ - '#type' => 'link', - '#title' => $this->t('Add @type', - ['@type' => $paragraphs_type->label()]), - '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ - 'parent_type' => $parent_type, - 'parent' => $parent, - 'parent_field_name' => $parent_field_name, - 'paragraphs_type' => $paragraphs_type->id(), - 'current_paragraph' => $current_paragraph, - 'before' => $before, - ], [ - 'query' => $request->query->all(), - ]), - '#attributes' => [ - 'class' => [''], - 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', - ], - ], ]; if (!empty($paragraphs_type->get('icon_default'))) { $item['icon'] = $this->buildIconElement($paragraphs_type); } + $item['link'] = [ + '#type' => 'link', + '#title' => $this->t('Add @type', ['@type' => $paragraphs_type->label()]), + '#url' => Url::fromRoute('frontend_editing.paragraph_add', [ + 'parent_type' => $parent_type, + 'parent' => $parent, + 'parent_field_name' => $parent_field_name, + 'paragraphs_type' => $paragraphs_type->id(), + 'current_paragraph' => $current_paragraph, + 'before' => $before, + ], [ + 'query' => $request->query->all(), + ]), + '#attributes' => [ + 'class' => 'field-add-more-submit js-form-submit form-submit', + 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', + ], + ]; + $items[$paragraphs_type->id()] = $item; } if (!empty($settings['handler_settings']['target_bundles_drag_drop'])) { - uasort($settings['handler_settings']['target_bundles_drag_drop'], - function ($a, $b) { - return $a['weight'] <=> $b['weight']; - }); + uasort($settings['handler_settings']['target_bundles_drag_drop'], function ($a, $b) { + return $a['weight'] <=> $b['weight']; + }); if (!empty($settings['handler_settings']['negate'])) { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], - function ($value) { - return !$value['enabled']; - }); + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { + return !$value['enabled']; + }); } else { - $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], - function ($value) { - return $value['enabled']; - }); + $settings['handler_settings']['target_bundles_drag_drop'] = array_filter($settings['handler_settings']['target_bundles_drag_drop'], function ($value) { + return $value['enabled']; + }); } - $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), - $items); + $items = array_replace(array_flip(array_keys($settings['handler_settings']['target_bundles_drag_drop'])), $items); $items = array_values($items); } return [ -- GitLab From 4956ca370e7cd154414f29f59abf377487678262 Mon Sep 17 00:00:00 2001 From: Artem Dmitriiev <a.dmitriiev@1xinternet.de> Date: Thu, 27 Feb 2025 16:56:35 +0100 Subject: [PATCH 05/10] Fix style linting --- css/forms_helper.css | 22 +++++++++++----------- css/ui_toggle.css | 26 +++++++++++++------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index 7e41bc1..89657a3 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -3,16 +3,16 @@ } .path-frontend-editing .layout-node-form__actions { - display: block; z-index: 2; + display: block; } .path-frontend-editing .layout-node-form__actions .gin-sticky { position: fixed; bottom: 0; - background: white; - border: 1px solid gray; padding: 0 15px; + border: 1px solid gray; + background: white; border-radius: 8px; } @@ -24,25 +24,25 @@ body.path-frontend-editing { } .path-frontend-editing > h1 { - align-items: center; display: flex; + align-items: center; font-size: 1.125em; - font-weight: 500; - height: 80px; justify-content: center; - margin: 0; + height: 80px; + font-weight: 500; position: fixed; - width: 100%; + margin: 0; z-index: 2; - background-color: #f5f7fb; + width: 100%; cursor: pointer; + background-color: #f5f7fb; text-decoration: none; } .path-frontend-editing .block-system-main-block > form { - border-radius: 0; - border: 0; position: relative; + border: 0; + border-radius: 0; } .path-frontend-editing .dialog-off-canvas-main-canvas { diff --git a/css/ui_toggle.css b/css/ui_toggle.css index 687609d..37d914f 100644 --- a/css/ui_toggle.css +++ b/css/ui_toggle.css @@ -3,12 +3,12 @@ top: var(--fe-editing-toggle-top, auto); right: var(--fe-editing-toggle-right, auto); bottom: var(--fe-editing-toggle-bottom, auto); - left: var(--fe-editing-toggle-left, auto); z-index: 20; + left: var(--fe-editing-toggle-left, auto); border-radius: 9999px; + width: fit-content !important; background-color: white; /* Required to prevent the toggle's position from being affected by external styles. */ - width: fit-content !important; height: fit-content !important; margin: 0 !important; padding: 0 !important; @@ -19,40 +19,40 @@ } .frontend-editing-toggle a { - background: rgba(var(--fe-editing-primary-color), 0.6); padding: 0.5rem 0.75rem; + background: rgba(var(--fe-editing-primary-color), 0.6); text-transform: uppercase; - color: white; display: block; + color: white; width: 5.5rem; - font-weight: 500; border-radius: 999px; - box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + font-weight: 500; position: relative; + box-shadow: rgba(0, 0, 0, 0.16) 0 1px 4px; text-align: right; } .frontend-editing-toggle a::before { - content: ' '; position: absolute; + content: " "; top: 0; - left: 0.5rem; bottom: 0; + left: 0.5rem; width: 1.75rem; height: 1.75rem; - margin-bottom: auto; margin-top: auto; + margin-bottom: auto; background-color: #fff; background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkgMy4xNzFhMS44MjkgMS44MjkgMCAwIDAtMS4yOTMuNTM2TDQuMzk1IDE3LjAxOWwtLjk3IDMuNTU2IDMuNTU2LS45N0wyMC4yOTMgNi4yOTNBMS44MjkgMS44MjkgMCAwIDAgMTkgMy4xN1ptLTEuNDY1LTEuNzA4YTMuODI5IDMuODI5IDAgMCAxIDQuMTcyIDYuMjQ0bC0xMy41IDEzLjVhMSAxIDAgMCAxLS40NDQuMjU4bC01LjUgMS41YTEgMSAwIDAgMS0xLjIyOC0xLjIyOGwxLjUtNS41YTEgMSAwIDAgMSAuMjU4LS40NDRsMTMuNS0xMy41YTMuODI5IDMuODI5IDAgMCAxIDEuMjQyLS44M1oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=="); - background-size: 16px; background-repeat: no-repeat; - background-position: center; + background-size: 16px; border-radius: 999px; + background-position: center; } .frontend-editing-toggle a.frontend-editing--enabled { - background: rgb(var(--fe-editing-primary-color)); text-align: left; + background: rgb(var(--fe-editing-primary-color)); } .frontend-editing-toggle a.frontend-editing--enabled::before { @@ -60,8 +60,8 @@ } .frontend-editing-toggle-not-configured { - box-shadow: 0 0 0 0 rgba(255, 0, 0, 1); transform: scale(1); + box-shadow: 0 0 0 0 rgba(255, 0, 0, 1); animation: pulse 2s infinite; } -- GitLab From 6826df3aca969ea0798f6d91d80b2696feae765c Mon Sep 17 00:00:00 2001 From: Artem Dmitriiev <a.dmitriiev@1xinternet.de> Date: Thu, 27 Feb 2025 17:19:26 +0100 Subject: [PATCH 06/10] Remove 100% width as it goes out of screen with Gin theme --- css/forms_helper.css | 1 - 1 file changed, 1 deletion(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index 89657a3..6d7a3ab 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -75,7 +75,6 @@ body.frontend-editing-hide-sidebar.gin--classic-toolbar { display: flex; flex-direction: row; align-items: center; - width: 100%; gap: 10px; } -- GitLab From d7dab5a0b213e988a0d5b67c79b6a4f42f67ca83 Mon Sep 17 00:00:00 2001 From: Artem Dmitriiev <a.dmitriiev@1xinternet.de> Date: Thu, 27 Feb 2025 17:25:30 +0100 Subject: [PATCH 07/10] Fix linting --- css/forms_helper.css | 10 +++++----- css/ui_toggle.css | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index 6d7a3ab..bfd4bf5 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -12,8 +12,8 @@ bottom: 0; padding: 0 15px; border: 1px solid gray; - background: white; border-radius: 8px; + background: white; } body.gin--vertical-toolbar.path-frontend-editing, @@ -26,17 +26,17 @@ body.path-frontend-editing { .path-frontend-editing > h1 { display: flex; align-items: center; - font-size: 1.125em; justify-content: center; + font-size: 1.125em; height: 80px; - font-weight: 500; position: fixed; - margin: 0; + font-weight: 500; z-index: 2; + margin: 0; width: 100%; cursor: pointer; - background-color: #f5f7fb; text-decoration: none; + background-color: #f5f7fb; } .path-frontend-editing .block-system-main-block > form { diff --git a/css/ui_toggle.css b/css/ui_toggle.css index 37d914f..34b99f2 100644 --- a/css/ui_toggle.css +++ b/css/ui_toggle.css @@ -1,15 +1,15 @@ .frontend-editing-toggle { position: fixed; + z-index: 20; top: var(--fe-editing-toggle-top, auto); right: var(--fe-editing-toggle-right, auto); bottom: var(--fe-editing-toggle-bottom, auto); - z-index: 20; left: var(--fe-editing-toggle-left, auto); - border-radius: 9999px; - width: fit-content !important; - background-color: white; /* Required to prevent the toggle's position from being affected by external styles. */ + width: fit-content !important; height: fit-content !important; + border-radius: 9999px; + background-color: white; margin: 0 !important; padding: 0 !important; } @@ -20,33 +20,33 @@ .frontend-editing-toggle a { padding: 0.5rem 0.75rem; - background: rgba(var(--fe-editing-primary-color), 0.6); - text-transform: uppercase; display: block; - color: white; + text-transform: uppercase; + background: rgba(var(--fe-editing-primary-color), 0.6); width: 5.5rem; + color: white; border-radius: 999px; - font-weight: 500; position: relative; - box-shadow: rgba(0, 0, 0, 0.16) 0 1px 4px; + font-weight: 500; text-align: right; + box-shadow: rgba(0, 0, 0, 0.16) 0 1px 4px; } .frontend-editing-toggle a::before { position: absolute; - content: " "; top: 0; + content: " "; bottom: 0; left: 0.5rem; width: 1.75rem; height: 1.75rem; margin-top: auto; margin-bottom: auto; + border-radius: 999px; background-color: #fff; background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkgMy4xNzFhMS44MjkgMS44MjkgMCAwIDAtMS4yOTMuNTM2TDQuMzk1IDE3LjAxOWwtLjk3IDMuNTU2IDMuNTU2LS45N0wyMC4yOTMgNi4yOTNBMS44MjkgMS44MjkgMCAwIDAgMTkgMy4xN1ptLTEuNDY1LTEuNzA4YTMuODI5IDMuODI5IDAgMCAxIDQuMTcyIDYuMjQ0bC0xMy41IDEzLjVhMSAxIDAgMCAxLS40NDQuMjU4bC01LjUgMS41YTEgMSAwIDAgMS0xLjIyOC0xLjIyOGwxLjUtNS41YTEgMSAwIDAgMSAuMjU4LS40NDRsMTMuNS0xMy41YTMuODI5IDMuODI5IDAgMCAxIDEuMjQyLS44M1oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=="); background-repeat: no-repeat; background-size: 16px; - border-radius: 999px; background-position: center; } @@ -61,8 +61,8 @@ .frontend-editing-toggle-not-configured { transform: scale(1); - box-shadow: 0 0 0 0 rgba(255, 0, 0, 1); animation: pulse 2s infinite; + box-shadow: 0 0 0 0 rgba(255, 0, 0, 1); } @keyframes pulse { -- GitLab From 73044989e38e9e077e6ebec04eb525578737eb5b Mon Sep 17 00:00:00 2001 From: Artem Dmitriiev <a.dmitriiev@1xinternet.de> Date: Fri, 28 Feb 2025 08:15:28 +0100 Subject: [PATCH 08/10] Fix style lint --- css/forms_helper.css | 8 ++++---- css/ui_toggle.css | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index bfd4bf5..3ced948 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -27,13 +27,13 @@ body.path-frontend-editing { display: flex; align-items: center; justify-content: center; - font-size: 1.125em; - height: 80px; position: fixed; - font-weight: 500; + height: 80px; z-index: 2; - margin: 0; + font-size: 1.125em; + font-weight: 500; width: 100%; + margin: 0; cursor: pointer; text-decoration: none; background-color: #f5f7fb; diff --git a/css/ui_toggle.css b/css/ui_toggle.css index 34b99f2..4927323 100644 --- a/css/ui_toggle.css +++ b/css/ui_toggle.css @@ -9,8 +9,8 @@ width: fit-content !important; height: fit-content !important; border-radius: 9999px; - background-color: white; margin: 0 !important; + background-color: white; padding: 0 !important; } @@ -19,24 +19,24 @@ } .frontend-editing-toggle a { - padding: 0.5rem 0.75rem; display: block; + padding: 0.5rem 0.75rem; text-transform: uppercase; - background: rgba(var(--fe-editing-primary-color), 0.6); width: 5.5rem; + background: rgba(var(--fe-editing-primary-color), 0.6); color: white; - border-radius: 999px; position: relative; - font-weight: 500; + border-radius: 999px; text-align: right; + font-weight: 500; box-shadow: rgba(0, 0, 0, 0.16) 0 1px 4px; } .frontend-editing-toggle a::before { position: absolute; top: 0; - content: " "; bottom: 0; + content: " "; left: 0.5rem; width: 1.75rem; height: 1.75rem; @@ -46,8 +46,8 @@ background-color: #fff; background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkgMy4xNzFhMS44MjkgMS44MjkgMCAwIDAtMS4yOTMuNTM2TDQuMzk1IDE3LjAxOWwtLjk3IDMuNTU2IDMuNTU2LS45N0wyMC4yOTMgNi4yOTNBMS44MjkgMS44MjkgMCAwIDAgMTkgMy4xN1ptLTEuNDY1LTEuNzA4YTMuODI5IDMuODI5IDAgMCAxIDQuMTcyIDYuMjQ0bC0xMy41IDEzLjVhMSAxIDAgMCAxLS40NDQuMjU4bC01LjUgMS41YTEgMSAwIDAgMS0xLjIyOC0xLjIyOGwxLjUtNS41YTEgMSAwIDAgMSAuMjU4LS40NDRsMTMuNS0xMy41YTMuODI5IDMuODI5IDAgMCAxIDEuMjQyLS44M1oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=="); background-repeat: no-repeat; - background-size: 16px; background-position: center; + background-size: 16px; } .frontend-editing-toggle a.frontend-editing--enabled { -- GitLab From d2d5f5e6e6abb78d5bf18ff357fa2d5ef4d4dee2 Mon Sep 17 00:00:00 2001 From: Artem Dmitriiev <a.dmitriiev@1xinternet.de> Date: Fri, 28 Feb 2025 09:53:30 +0100 Subject: [PATCH 09/10] Fix all style lint issues --- css/forms_helper.css | 10 +++++----- css/ui_toggle.css | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index 3ced948..65e84d9 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -24,19 +24,19 @@ body.path-frontend-editing { } .path-frontend-editing > h1 { + position: fixed; + z-index: 2; display: flex; align-items: center; justify-content: center; - position: fixed; - height: 80px; - z-index: 2; - font-size: 1.125em; - font-weight: 500; width: 100%; + height: 80px; margin: 0; cursor: pointer; text-decoration: none; background-color: #f5f7fb; + font-size: 1.125em; + font-weight: 500; } .path-frontend-editing .block-system-main-block > form { diff --git a/css/ui_toggle.css b/css/ui_toggle.css index 4927323..ab7bd6d 100644 --- a/css/ui_toggle.css +++ b/css/ui_toggle.css @@ -8,10 +8,10 @@ /* Required to prevent the toggle's position from being affected by external styles. */ width: fit-content !important; height: fit-content !important; - border-radius: 9999px; margin: 0 !important; - background-color: white; padding: 0 !important; + border-radius: 9999px; + background-color: white; } .frontend-editing-toggle *:not(.frontend-editing-toggle-link) { @@ -19,29 +19,29 @@ } .frontend-editing-toggle a { + position: relative; display: block; + width: 5.5rem; padding: 0.5rem 0.75rem; + text-align: right; text-transform: uppercase; - width: 5.5rem; - background: rgba(var(--fe-editing-primary-color), 0.6); color: white; - position: relative; border-radius: 999px; - text-align: right; - font-weight: 500; + background: rgba(var(--fe-editing-primary-color), 0.6); box-shadow: rgba(0, 0, 0, 0.16) 0 1px 4px; + font-weight: 500; } .frontend-editing-toggle a::before { position: absolute; top: 0; bottom: 0; - content: " "; left: 0.5rem; width: 1.75rem; height: 1.75rem; margin-top: auto; margin-bottom: auto; + content: " "; border-radius: 999px; background-color: #fff; background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzIzMjIyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkgMy4xNzFhMS44MjkgMS44MjkgMCAwIDAtMS4yOTMuNTM2TDQuMzk1IDE3LjAxOWwtLjk3IDMuNTU2IDMuNTU2LS45N0wyMC4yOTMgNi4yOTNBMS44MjkgMS44MjkgMCAwIDAgMTkgMy4xN1ptLTEuNDY1LTEuNzA4YTMuODI5IDMuODI5IDAgMCAxIDQuMTcyIDYuMjQ0bC0xMy41IDEzLjVhMSAxIDAgMCAxLS40NDQuMjU4bC01LjUgMS41YTEgMSAwIDAgMS0xLjIyOC0xLjIyOGwxLjUtNS41YTEgMSAwIDAgMSAuMjU4LS40NDRsMTMuNS0xMy41YTMuODI5IDMuODI5IDAgMCAxIDEuMjQyLS44M1oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=="); -- GitLab From 9dd7acd9f500100dca2984cbadbe0add3c19fbeb Mon Sep 17 00:00:00 2001 From: Artem Dmitriiev <a.dmitriiev@1xinternet.de> Date: Fri, 28 Feb 2025 11:17:24 +0100 Subject: [PATCH 10/10] No div inside li --- css/forms_helper.css | 49 +++++++++++++++++--- src/Controller/FrontendEditingController.php | 19 ++++---- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/css/forms_helper.css b/css/forms_helper.css index 65e84d9..89698f5 100644 --- a/css/forms_helper.css +++ b/css/forms_helper.css @@ -71,23 +71,60 @@ body.frontend-editing-hide-sidebar.gin--classic-toolbar { padding-inline-start: 0 !important; } +.path-frontend-editing .paragraphs-add-dialog-list { + padding: 0 20px; + column-count: 1; + list-style: none; +} + +@media (min-width: 48em) { + .path-frontend-editing .paragraphs-add-dialog-list { + column-count: 3; + column-gap: 14px; + } +} + .path-frontend-editing .paragraphs-add-dialog-row { - display: flex; - flex-direction: row; - align-items: center; - gap: 10px; + position: relative; +} + +.path-frontend-editing .paragraphs-add-dialog-row .paragraph-type-icon { + position: absolute; + top: 10px; + left: 10px; + display: block; + box-sizing: border-box; + border: none; + box-shadow: none; } .path-frontend-editing .paragraphs-add-dialog-row img { - width: 60px; - height: 60px; + width: 50px; + height: 50px; object-fit: contain; border-radius: 5px; background: #fff; } .path-frontend-editing ul.paragraphs-add-dialog-list li { + width: 100%; + margin: 0 0 10px 0; list-style: none; + text-align: left; +} + +.path-frontend-editing ul.paragraphs-add-dialog-list li a { + display: block; + box-sizing: border-box; + width: 100%; + min-height: 70px; + margin: 0; + text-align: left; + line-height: 45px; +} + +.path-frontend-editing ul.paragraphs-add-dialog-list li.with-icon a { + padding-left: 75px; } .path-frontend-editing .field-add-more-submit:hover a { diff --git a/src/Controller/FrontendEditingController.php b/src/Controller/FrontendEditingController.php index e2c4d84..41281c3 100644 --- a/src/Controller/FrontendEditingController.php +++ b/src/Controller/FrontendEditingController.php @@ -641,21 +641,15 @@ class FrontendEditingController extends ControllerBase { $items = []; foreach ($allowed_paragraphs as $paragraphs_type) { $item = [ - '#type' => 'container', - '#attributes' => [ + '#wrapper_attributes' => [ 'class' => [ 'paragraphs-add-dialog-row', - 'field-add-more-submit', - 'button--large', - 'button', - 'js-form-submit', - 'form-submit', ], ], ]; - if (!empty($paragraphs_type->get('icon_default'))) { $item['icon'] = $this->buildIconElement($paragraphs_type); + $item['#wrapper_attributes']['class'][] = 'with-icon'; } $item['link'] = [ @@ -672,11 +666,16 @@ class FrontendEditingController extends ControllerBase { 'query' => $request->query->all(), ]), '#attributes' => [ - 'class' => 'field-add-more-submit js-form-submit form-submit', + 'class' => [ + 'js-form-submit', + 'form-submit', + 'button', + 'button--large', + 'field-add-more-submit', + ], 'name' => $parent_field_name . '_' . $paragraphs_type->id() . '_add_more', ], ]; - $items[$paragraphs_type->id()] = $item; } if (!empty($settings['handler_settings']['target_bundles_drag_drop'])) { -- GitLab