Verified Commit b4ee91dd authored by Cristina Chumillas's avatar Cristina Chumillas
Browse files

Issue #3424744 by bronzehedwick, ckrina, m4olivei, finnsky, smustgrave,...

Issue #3424744 by bronzehedwick, ckrina, m4olivei, finnsky, smustgrave, plopesc, kostyashupenko, KeyboardCowboy: If no icon for a top-level item is provided, use the first two letters
parent 2477c009
Loading
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -85,17 +85,21 @@
}
/* Class starts with `toolbar-button--icon`  */
[class*="toolbar-button--icon"] {
  --icon: url("data:image/svg+xml,%3csvg width='24' height='24' viewbox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3e  %3cpath d='M19.5 3H4.5C4.10218 3 3.72064 3.15804 3.43934 3.43934C3.15804 3.72064 3 4.10218 3 4.5V19.5C3 19.8978 3.15804 20.2794 3.43934 20.5607C3.72064 20.842 4.10218 21 4.5 21H19.5C19.8978 21 20.2794 20.842 20.5607 20.5607C20.842 20.2794 21 19.8978 21 19.5V4.5C21 4.10218 20.842 3.72064 20.5607 3.43934C20.2794 3.15804 19.8978 3 19.5 3ZM4.5 19.5V5.56031L18.4397 19.5H4.5ZM5.56031 4.5H19.5V18.4406L5.56031 4.5Z' fill='currentColor'/%3e%3c/svg%3e"); /* Default icon, aka --basic */

  padding-inline: calc(0.75 * var(--admin-toolbar-rem));
}
[class*="toolbar-button--icon"]::before {
  display: block;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  content: attr(data-icon-text);
  color: currentColor;
  background-image: linear-gradient(currentColor, currentColor 50%, transparent 50%);
  background-position-y: calc(100% - (100% * var(--icon, 0)));
  background-size: 100% 200%;
  font-size: calc(0.75 * var(--admin-toolbar-rem));
  inline-size: var(--admin-toolbar-space-20);
  block-size: var(--admin-toolbar-space-20);
  content: "";
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center center;
@@ -106,7 +110,7 @@
  mask-image: var(--icon);
}
[class*="toolbar-button--icon"]:hover::before {
  background-color: var(--admin-toolbar-color-blue-600);
  background-color: linear-gradient(var(--admin-toolbar-color-blue-600), var(--admin-toolbar-color-blue-600) 50%, transparent 50%);
}
@media (forced-colors: active) {
  [class*="toolbar-button--icon"]::before,
+10 −6
Original line number Diff line number Diff line
@@ -92,17 +92,21 @@

/* Class starts with `toolbar-button--icon`  */
[class*="toolbar-button--icon"] {
  --icon: url(../../assets/icons/basic.svg); /* Default icon, aka --basic */

  padding-inline: calc(0.75 * var(--admin-toolbar-rem));

  &::before {
    display: block;
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    content: attr(data-icon-text);
    color: currentColor;
    background-image: linear-gradient(currentColor, currentColor 50%, transparent 50%);
    background-position-y: calc(100% - (100% * var(--icon, 0)));
    background-size: 100% 200%;
    font-size: calc(0.75 * var(--admin-toolbar-rem));
    inline-size: var(--admin-toolbar-space-20);
    block-size: var(--admin-toolbar-space-20);
    content: "";
    background-color: currentColor;
    mask-repeat: no-repeat;
    mask-position: center center;
    mask-size: 100% auto;
@@ -111,7 +115,7 @@
  }

  &:hover::before {
    background-color: var(--admin-toolbar-color-blue-600);
    background-color: linear-gradient(var(--admin-toolbar-color-blue-600), var(--admin-toolbar-color-blue-600) 50%, transparent 50%);
  }

  @media (--forced-colors) {
+5 −1
Original line number Diff line number Diff line
@@ -7,7 +7,11 @@ appear after main classes #}
    extra_classes,
  ]
%}
<{{html_tag|default('button')}}{{ attributes.addClass(classes) }} data-index-text="{{ text|first|lower }}">
<{{html_tag|default('button')}}
  {{ attributes.addClass(classes) }}
  data-index-text="{{ text|first|lower }}"
  data-icon-text={{- text|render|trim|slice(0, 2)|join('') }}
>
  {% if avatar %}
    <span class="toolbar-button__avatar">{{~ avatar ~}}</span>
  {% endif %}
+163 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Tests\navigation\Kernel;

use Drupal\Core\Render\MetadataBubblingUrlGenerator;
use Drupal\Core\Routing\UrlGenerator;
use Drupal\KernelTests\KernelTestBase;
use Drupal\navigation\Plugin\Block\NavigationMenuBlock;
use Drupal\system\Entity\Menu;
use Drupal\system\Tests\Routing\MockRouteProvider;
use Drupal\Tests\Core\Menu\MenuLinkMock;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

/**
 * Tests \Drupal\navigation\Plugin\Block\NavigationMenuBlock.
 *
 * @group navigation
 * @see \Drupal\navigation\Plugin\Derivative\SystemMenuNavigationBlock
 * @see \Drupal\navigation\Plugin\Block\NavigationMenuBlock
 */
class NavigationMenuMarkupTest extends KernelTestBase {

  /**
   * Modules to enable.
   *
   * @var array
   */
  protected static $modules = [
    'system',
    'navigation',
    'menu_test',
    'menu_link_content',
    'field',
    'block',
    'user',
    'link',
    'layout_builder',
  ];

  /**
   * The menu for testing.
   *
   * @var \Drupal\system\MenuInterface
   */
  protected $menu;

  /**
   * The menu link tree service.
   *
   * @var \Drupal\Core\Menu\MenuLinkTree
   */
  protected $linkTree;

  /**
   * The menu link plugin manager service.
   *
   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
   */
  protected $menuLinkManager;

  /**
   * The block manager service.
   *
   * @var \Drupal\Core\Block\BlockManager
   */
  protected $blockManager;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('menu_link_content');

    $this->menuLinkManager = $this->container->get('plugin.manager.menu.link');
    $this->linkTree = $this->container->get('menu.link_tree');
    $this->blockManager = $this->container->get('plugin.manager.block');

    $routes = new RouteCollection();
    $requirements = ['_access' => 'TRUE'];
    $options = ['_access_checks' => ['access_check.default']];
    $routes->add('example1', new Route('/example1', [], $requirements, $options));
    $routes->add('example2', new Route('/example2', [], $requirements, $options));
    $routes->add('example3', new Route('/example3', [], $requirements, $options));

    // Define our RouteProvider mock.
    $mock_route_provider = new MockRouteProvider($routes);
    $this->container->set('router.route_provider', $mock_route_provider);

    // Define our UrlGenerator service that use the new RouteProvider.
    $url_generator_non_bubbling = new UrlGenerator(
      $mock_route_provider,
      $this->container->get('path_processor_manager'),
      $this->container->get('route_processor_manager'),
      $this->container->get('request_stack'),
      $this->container->getParameter('filter_protocols')
    );
    $url_generator = new MetadataBubblingUrlGenerator($url_generator_non_bubbling, $this->container->get('renderer'));
    $this->container->set('url_generator', $url_generator);

    // Add a new custom menu.
    $menu_name = 'mock';
    $label = $this->randomMachineName(16);

    $this->menu = Menu::create([
      'id' => $menu_name,
      'label' => $label,
      'description' => 'Description text',
    ]);
    $this->menu->save();

    // This creates a tree with the following structure:
    // - 1
    // - 2
    //   - 3
    // phpcs:disable
    $links = [
      1 => MenuLinkMock::create(['id' => 'test.example1', 'route_name' => 'example1', 'title' => 'title 1', 'parent' => '', 'weight' => 0]),
      2 => MenuLinkMock::create(['id' => 'test.example2', 'route_name' => 'example2', 'title' => 'Another title', 'parent' => '', 'route_parameters' => ['foo' => 'bar'], 'weight' => 1]),
      3 => MenuLinkMock::create(['id' => 'test.example3', 'route_name' => 'example3', 'title' => 'A menu link', 'parent' => 'test.example2', 'weight' => 2]),
    ];
    // phpcs:enable
    foreach ($links as $instance) {
      $this->menuLinkManager->addDefinition($instance->getPluginId(), $instance->getPluginDefinition());
    }
  }

  /**
   * Tests the generated HTML markup.
   */
  public function testToolbarButtonAttributes(): void {
    $block = $this->blockManager->createInstance('navigation_menu:' . $this->menu->id(), [
      'region' => 'content',
      'id' => 'machine_name',
      'level' => 1,
      'depth' => NavigationMenuBlock::NAVIGATION_MAX_DEPTH - 1,
    ]);

    $block_build = $block->build();
    $render = \Drupal::service('renderer')->renderRoot($block_build);

    $dom = new \DOMDocument();
    $dom->loadHTML((string) $render);
    $xpath = new \DOMXPath($dom);

    $items_query = [
      "//li[contains(@class,'toolbar-block__list-item')]/a[@data-index-text='t']",
      "//li[contains(@class,'toolbar-block__list-item')]/a[@data-icon-text='ti']",
      "//li[contains(@class,'toolbar-block__list-item')]/button[@data-index-text='a']",
      "//li[contains(@class,'toolbar-block__list-item')]/button[@data-icon-text='An']",
      "//li[contains(@class,'toolbar-menu__item--level-1')]/a[@data-index-text='a']",
      "//li[contains(@class,'toolbar-menu__item--level-1')]/a[not(@data-icon-text)]",
    ];
    foreach ($items_query as $query) {
      $span = $xpath->query($query);
      $this->assertEquals(1, $span->length, $query);
    }
  }

}