display_builder-1.0.x-dev/src/Plugin/display_builder/Island/ComponentLibraryPanel.php

src/Plugin/display_builder/Island/ComponentLibraryPanel.php
<?php

declare(strict_types=1);

namespace Drupal\display_builder\Plugin\display_builder\Island;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\display_builder\Attribute\Island;
use Drupal\display_builder\IslandPluginBase;
use Drupal\display_builder\IslandType;

/**
 * Component library island plugin implementation.
 */
#[Island(
  id: 'component_library',
  label: new TranslatableMarkup('Components library'),
  description: new TranslatableMarkup('List of available Components to use.'),
  type: IslandType::Library,
)]
class ComponentLibraryPanel extends IslandPluginBase {

  /**
   * Component provider to exclude.
   *
   * Include known UI Suite modules.
   *
   * @todo have this as a configuration in the island.
   *
   * @var array
   *   The providers to exclude.
   */
  private const PROVIDER_EXCLUDE = ['display_builder', 'sdc_devel'];

  /**
   * The definitions filtered for current theme.
   *
   * @var array
   *   The definitions filtered.
   */
  private array $definitionsFiltered = [];

  /**
   * The definitions filtered and grouped for current theme.
   *
   * @var array
   *   The definitions filtered and grouped.
   */
  private array $definitionsGrouped = [];

  /**
   * {@inheritdoc}
   */
  public function label(): string {
    return 'Components';
  }

  /**
   * {@inheritdoc}
   */
  public function build(string $builder_id, array $data, array $options = []): array {
    // Try to call only once for each sub islands.
    $definitions = $this->getDefinitionsForProvider();

    $this->definitionsFiltered = $definitions['filtered'] ?? [];
    $this->definitionsGrouped = $definitions['grouped'] ?? [];

    $panes = [
      'grouped' => [
        'title' => $this->t('Grouped'),
        'content' => $this->getComponentsGrouped($builder_id),
      ],
      'variants' => [
        'title' => $this->t('Variants'),
        'content' => $this->getComponentsVariants($builder_id),
      ],
      'mosaic' => [
        'title' => $this->t('Mosaic'),
        'content' => $this->getComponentsMosaic($builder_id),
      ],
    ];
    $tabs = [];
    $content = [];

    foreach ($panes as $pane_id => $pane) {
      $id = 'db-' . $builder_id . '-components-tab---' . $pane_id;
      $tabs[] = [
        'title' => $pane['title'],
        'url' => '#' . $id,
      ];
      $content[] = $this->wrapContent($pane['content'], $id);
    }

    return [
      '#type' => 'component',
      '#component' => 'display_builder:library_panel',
      '#slots' => [
        'tabs' => $this->buildTabs('db-' . $builder_id . '-components-tabs', $tabs),
        'content' => $content,
      ],
    ];
  }

  /**
   * Gets the grouped components view.
   *
   * @param string $builder_id
   *   Builder ID.
   *
   * @return array
   *   A renderable array containing the grouped components.
   */
  private function getComponentsGrouped(string $builder_id): array {
    $build = [];

    /** @var \Drupal\ui_patterns_overrides\SourcesBundlerInterface $source */
    $source = $this->sourceManager->createInstance('component');

    foreach ($this->definitionsGrouped as $group_name => $group) {
      $build[] = [
        '#type' => 'html_tag',
        '#tag' => 'h4',
        '#value' => $group_name,
        '#attributes' => [
          'class' => ['db-filter-hide-on-search'],
        ],
      ];

      foreach ($group as $component_id => $definition) {
        $component_id = (string) $component_id;
        $component_preview_url = Url::fromRoute('display_builder.api_component_preview', ['component_id' => $component_id]);

        $data = $source->getDataSkeleton($component_id);
        // Used for search filter.
        $keywords = \sprintf('%s %s', $definition['label'], $definition['provider']);
        $build[] = $this->buildPlaceholderButtonWithPreview($builder_id, $definition['annotated_name'], $data, $component_preview_url, $keywords);
      }
    }

    return $this->buildDraggables($builder_id, $build);
  }

  /**
   * Gets the components variants view.
   *
   * @param string $builder_id
   *   Builder ID.
   *
   * @return array
   *   A renderable array containing the variants placeholders.
   */
  private function getComponentsVariants(string $builder_id): array {
    $build = [];

    /** @var \Drupal\ui_patterns_overrides\SourcesBundlerInterface $source */
    $source = $this->sourceManager->createInstance('component');

    foreach ($this->definitionsFiltered as $component_id => $definition) {
      $build[] = [
        '#type' => 'html_tag',
        '#tag' => 'h4',
        '#value' => $definition['annotated_name'],
        '#attributes' => [
          'data-filter-parent' => $definition['machineName'],
        ],
      ];
      $data = $source->getDataSkeleton($component_id);

      if (!isset($definition['variants'])) {
        $component_preview_url = Url::fromRoute('display_builder.api_component_preview', ['component_id' => $component_id]);
        // Used for search filter.
        $keywords = \sprintf('%s %s', $definition['label'], $definition['provider']);
        $build_variant = $this->buildPlaceholderButtonWithPreview($builder_id, $this->t('Default'), $data, $component_preview_url, $keywords);
        $build_variant['#attributes']['data-filter-child'] = $definition['machineName'];
        $build[] = $build_variant;
        continue;
      }

      foreach ($definition['variants'] ?? [] as $variant_id => $variant) {
        $params = ['component_id' => $component_id, 'variant_id' => $variant_id];
        $component_preview_url = Url::fromRoute('display_builder.api_component_preview', $params);
        $data['source']['component']['variant_id'] = [
          'source_id' => 'select',
          'source' => [
            'value' => $variant_id,
          ],
        ];
        // Used for search filter.
        $keywords = \sprintf('%s %s %s', $definition['label'], $variant['title'], $definition['provider']);
        $build_variant = $this->buildPlaceholderButtonWithPreview($builder_id, $variant['title'], $data, $component_preview_url, $keywords);
        $build_variant['#attributes']['data-filter-child'] = $definition['machineName'];
        $build[] = $build_variant;
      }
    }

    return $this->buildDraggables($builder_id, $build);
  }

  /**
   * Gets the mosaic view of components.
   *
   * @param string $builder_id
   *   Builder ID.
   *
   * @return array
   *   A renderable array containing the mosaic view of components.
   */
  private function getComponentsMosaic(string $builder_id): array {
    $components = [];

    $source = $this->sourceManager->createInstance('component');

    foreach (array_keys($this->definitionsFiltered) as $component_id) {
      $component_id = (string) $component_id;
      $component = $this->sdcManager->find($component_id);
      $component_preview_url = Url::fromRoute('display_builder.api_component_preview', ['component_id' => $component_id]);

      /** @var \Drupal\ui_patterns_overrides\SourcesBundlerInterface $source */
      $vals = $source->getDataSkeleton($component_id);
      $thumbnail = $component->metadata->getThumbnailPath();

      // Used for search filter.
      $keywords = \sprintf('%s %s', $component->metadata->name, str_replace(':', ' ', $component_id));
      $build = $this->buildPlaceholderCardWithPreview($component->metadata->name, $vals, $component_preview_url, $keywords, $thumbnail);
      $components[] = $build;
    }

    return $this->buildDraggables($builder_id, $components, 'mosaic');
  }

  /**
   * Get definition for current provider.
   *
   * @return array
   *   The definitions filtered and grouped.
   */
  private function getDefinitionsForProvider(): array {
    // @phpstan-ignore-next-line
    $definitions = $this->sdcManager->getSortedDefinitions($this->sdcManager->getDefinitions());
    $default_active_theme = \Drupal::service('theme.manager')->getActiveTheme();
    $all_active_themes = array_merge([$default_active_theme->getName()], array_keys($default_active_theme->getBaseThemeExtensions()));

    $filtered_definitions = $grouped_definitions = [];
    foreach ($definitions as $id => $definition) {
      if (isset($definition['status']) && $definition['status'] === 'obsolete') {
        continue;
      }
      if ($definition['extension_type']->value === 'theme' && !in_array($definition['provider'], $all_active_themes)) {
        continue;
      }
      if (in_array($definition['provider'], self::PROVIDER_EXCLUDE)) {
        continue;
      }
      // Because of multiple themes, annotated name contains the theme name.
      // We do not need it.
      $definition['annotated_name'] = $definition['name'] ?? 'n/a';
      $filtered_definitions[$id] = $definition;
      // @phpstan-ignore-next-line
      $grouped_definitions[(string) $definition['category']][$id] = $definition;
    }

    // Order list ignoring starting '(' that is used for components names that
    // are sub components.
    uasort($filtered_definitions, function ($a, $b) {
      // @phpstan-ignore-next-line
      $nameA = ltrim($a['name'] ?? $a['label'], '(');
      // @phpstan-ignore-next-line
      return strnatcasecmp($nameA, ltrim($b['name'] ?? $b['label'], '('));
    });

    return [
      'grouped' => $grouped_definitions,
      'filtered' => $filtered_definitions,
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc