utilikit-1.0.0/src/Controller/UtilikitReferenceController.php

src/Controller/UtilikitReferenceController.php
<?php

declare(strict_types=1);

namespace Drupal\utilikit\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\utilikit\Service\UtilikitRules;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides the UtiliKit Admin Reference page.
 *
 * This controller generates a comprehensive reference page displaying all
 * available UtiliKit utility classes, their usage patterns, examples, and
 * interactive demonstrations. It organizes utility classes by category and
 * provides copy-to-clipboard functionality and live preview capabilities.
 */
class UtilikitReferenceController extends ControllerBase {

  /**
   * The UtiliKit rules service.
   *
   * @var \Drupal\utilikit\Service\UtilikitRules
   */
  protected UtilikitRules $rulesService;

  /**
   * Constructs a new UtilikitReferenceController object.
   *
   * @param \Drupal\utilikit\Service\UtilikitRules $rulesService
   *   The UtiliKit rules service for accessing utility class definitions.
   */
  public function __construct(UtilikitRules $rulesService) {
    $this->rulesService = $rulesService;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): self {
    return new self(
      $container->get('utilikit.rules')
    );
  }

  /**
   * Builds the UtiliKit reference admin page.
   *
   * Creates a comprehensive reference page with utility class documentation,
   * grouped by category, with interactive examples and quick reference guide.
   *
   * @return array
   *   Render array for the UtiliKit reference page including cheatsheet,
   *   categorized utility class tables, and interactive components.
   */
  public function referencePage(): array {
    $rules = $this->rulesService->getRules();
    $groups = $this->groupRules($rules);

    // At the beginning of the build array in referencePage():
    $build = [
      '#type' => 'container',
      '#attributes' => ['class' => ['utilikit-reference-page']],
      '#title' => $this->t('UtiliKit - Utility Class Reference'),
      '#attached' => [
        'library' => ['utilikit/utilikit.reference', 'utilikit/utilikit.engine'],
      ],
      'description' => [
        '#markup' => '<p>' . $this->t('This reference page lists all available UtiliKit dynamic utility classes, their prefixes, and usage examples for your site.') . '</p>',
      ],
    ];

    // Add cheatsheet at the top.
    $build['cheatsheet'] = [
      '#type' => 'container',
      '#attributes' => ['class' => ['utilikit-cheatsheet']],
      'content' => [
        '#markup' => $this->buildCheatsheet($rules),
        '#allowed_tags' => ['div', 'span', 'h3', 'button', 'code'],
      ],
      '#prefix' => '<div class="out-wrapper">',
      '#suffix' => '</div>',
    ];

    foreach ($groups as $group => $items) {
      $header = [
        $this->t('Property'),
        $this->t('Prefix'),
        $this->t('Example'),
        $this->t('Responsive'),
        $this->t('Value Type'),
        $this->t('Notes'),
      ];

      $rows = [];
      foreach ($items as [$prefix, $rule]) {
        $example = $this->getExample($prefix, $rule);
        $note_full = $this->getNotes($rule, $prefix);
        $note_short = $this->getShortNote($rule, $prefix);

        $rows[] = [
          $rule['css'],
          ['data' => ['#markup' => '<code>uk-' . $prefix . '</code>']],
          ['data' => ['#markup' => '<code>' . $example . '</code>']],
          ['data' => ['#markup' => '<code>' . $this->getResponsiveExample($example) . '</code>']],
          $this->getValueType($rule),
          [
            'data' => [
              '#markup' => '<span title="' . htmlspecialchars($note_full) . '">' . htmlspecialchars($note_short) . '</span>',
            ],
          ],
        ];
      }

      $build[] = [
        '#markup' => '<h3>' . $group . '</h3>',
      ];

      $build[] = [
        '#type' => 'table',
        '#header' => $header,
        '#rows' => $rows,
        '#attributes' => ['class' => ['utilikit-admin-reference']],
      ];
    }

    return $build;
  }

  /**
   * Build the cheatsheet with color-coded syntax.
   *
   * Creates an interactive quick reference guide with organized utility
   * classes, copy functionality, and a live preview playground for testing
   * utility class combinations.
   *
   * @param array $rules
   *   Array of utility class rules from the rules service.
   *
   * @return string
   *   HTML markup for the interactive cheatsheet component.
   */
  protected function buildCheatsheet(array $rules): string {
    $output = '<div class="utilikit-cheatsheet">';
    $output .= '<h3>' . $this->t('Quick Reference Guide') . '</h3>';

    // Group rules by their group property.
    $groups = [];
    foreach ($rules as $prefix => $rule) {
      $group = $rule['group'] ?? 'Other';
      if (!isset($groups[$group])) {
        $groups[$group] = [];
      }
      $groups[$group][$prefix] = $rule;
    }

    // Define group icons.
    $groupIcons = [
      'Box Model' => '▢',
      'Sizing' => '↕',
      'Positioning' => '⊞',
      'Typography' => 'T',
      'Colors' => '●',
      'Layout' => '▦',
      'Flexbox' => '⇄',
      'Grid' => '▦',
      'Transform' => '↻',
      'Effects' => '✦',
    ];

    // Output each group.
    foreach ($groups as $groupName => $groupRules) {
      $output .= '<div class="syntax-group">';
      $output .= '<div class="syntax-group-title">';
      $output .= '<span class="syntax-group-icon">' . ($groupIcons[$groupName] ?? '•') . '</span>';
      $output .= $groupName;
      $output .= '<button type="button" class="copy-group-btn" data-group="' . htmlspecialchars($groupName) . '">' . $this->t('Copy All') . '</button>';
      $output .= '</div>';
      $output .= '<div class="syntax-items">';

      foreach ($groupRules as $prefix => $rule) {
        $cssProperty = str_replace(['backgroundColor', 'borderWidth', 'borderRadius', 'borderStyle', 'borderColor',
          'maxWidth', 'minWidth', 'maxHeight', 'minHeight', 'fontSize', 'lineHeight',
          'fontWeight', 'letterSpacing', 'textAlign', 'zIndex', 'aspectRatio',
          'flexGrow', 'flexShrink', 'flexBasis', 'flexDirection', 'justifyContent',
          'alignItems', 'alignContent', 'flexWrap', 'gridTemplateColumns',
          'gridTemplateRows', 'gridColumn', 'gridRow', 'userSelect', 'backgroundSize',
        ],
                                  ['background-color', 'border-width', 'border-radius', 'border-style', 'border-color',
                                    'max-width', 'min-width', 'max-height', 'min-height', 'font-size', 'line-height',
                                    'font-weight', 'letter-spacing', 'text-align', 'z-index', 'aspect-ratio',
                                    'flex-grow', 'flex-shrink', 'flex-basis', 'flex-direction', 'justify-content',
                                    'align-items', 'align-content', 'flex-wrap', 'grid-template-columns',
                                    'grid-template-rows', 'grid-column', 'grid-row', 'user-select', 'background-size',
                                  ],
                                  $rule['css']);

        $output .= '<div class="syntax-item">';
        $output .= '<span class="property-name">' . $cssProperty . '</span>';
        $output .= '<span class="syntax">';
        $output .= '<span class="syntax-uk">uk</span>';
        $output .= '<span class="syntax-dash">-</span>';
        $output .= '<span class="syntax-prefix">' . htmlspecialchars($prefix, ENT_QUOTES, 'UTF-8') . '</span>';
        $output .= '<span class="syntax-dash">--</span>';
        $output .= '<span class="syntax-value">value</span>';
        $output .= '</span>';
        $output .= '</div>';
      }

      $output .= '</div></div>';
    }

    return $output;
  }

  /**
   * Groups rules by category for display.
   *
   * Organizes utility class rules into logical groups for better presentation
   * and sorts items within each group alphabetically by CSS property name.
   *
   * @param array $rules
   *   Array of utility class rules from the rules service.
   *
   * @return array
   *   Grouped and sorted rules organized by category.
   */
  protected function groupRules(array $rules): array {
    $groups = [];
    foreach ($rules as $prefix => $rule) {
      $group = $rule['group'] ?? 'Other';
      $groups[$group][] = [$prefix, $rule];
    }

    foreach ($groups as &$items) {
      usort($items, fn($a, $b) => strcmp($a[1]['css'], $b[1]['css']));
    }

    ksort($groups);
    return $groups;
  }

  /**
   * Generates example usage strings.
   *
   * Creates contextually appropriate examples for each utility class type,
   * demonstrating proper syntax and common use cases.
   *
   * @param string $prefix
   *   The utility class prefix (e.g., 'pd', 'mg', 'bg').
   * @param array $rule
   *   The rule definition containing type and configuration information.
   *
   * @return string
   *   Example utility class usage string (e.g., 'uk-pd--20').
   */
  protected function getExample(string $prefix, array $rule): string {
    // Color properties.
    if (!empty($rule['isColor'])) {
      return "uk-{$prefix}--ff0000";
    }

    // Properties with sides.
    if (!empty($rule['sides'])) {
      return "uk-{$prefix}--t-20";
    }

    // Keyword properties.
    if (!empty($rule['isKeyword'])) {
      $examples = [
        'dp' => 'flex',
        'ps' => 'relative',
        'ta' => 'center',
        'ov' => 'hidden',
        'cu' => 'pointer',
        'fl' => 'left',
        'cl' => 'both',
        'us' => 'none',
        'bs' => 'solid',
        'bz' => 'cover',
        'fd' => 'row',
        'jc' => 'center',
        'ai' => 'center',
        'ac' => 'center',
        'fx' => 'wrap',
      ];
      return "uk-{$prefix}--" . ($examples[$prefix] ?? 'value');
    }

    // Transform properties.
    if (!empty($rule['isTransform'])) {
      return $rule['isTransform'] === 'rotate'
        ? "uk-{$prefix}--45"
        : "uk-{$prefix}--150";
    }

    // Grid template properties.
    if (!empty($rule['isGridTrackList'])) {
      return $prefix === 'gc'
        ? "uk-gc--repeat-3-1fr"
        : "uk-gr--100px-auto-1fr";
    }

    // Range properties (grid positioning, aspect ratio)
    if (!empty($rule['isRange'])) {
      return $prefix === 'ar'
        ? "uk-ar--16-9"
        : "uk-{$prefix}--1-3";
    }

    // Opacity (0-100)
    if (!empty($rule['isOpacity'])) {
      return "uk-op--50";
    }

    // Integer properties (z-index, font-weight, order)
    if (!empty($rule['isInteger']) && empty($rule['isOpacity'])) {
      $examples = [
        'zi' => '10',
        'fw' => '700',
        'or' => '2',
      ];
      return "uk-{$prefix}--" . ($examples[$prefix] ?? '1');
    }

    // Decimal fixed (flex-grow, flex-shrink)
    if (!empty($rule['isDecimalFixed'])) {
      return "uk-{$prefix}--1d500";
    }

    // Numeric flexible (most common - px, %, em, rem)
    if (!empty($rule['isNumericFlexible'])) {
      // Show different unit examples.
      if (in_array($prefix, ['wd', 'ht', 'xw', 'xh', 'nw', 'nh'])) {
        // Show percentage.
        return "uk-{$prefix}--100pr";
      }
      if (in_array($prefix, ['fs', 'lh'])) {
        // Show rem.
        return "uk-{$prefix}--1d5rem";
      }
      if ($prefix === 'gp') {
        // Gap with two values.
        return "uk-gp--16-32";
      }
      // Default pixels.
      return "uk-{$prefix}--20";
    }

    return "uk-{$prefix}--20";
  }

  /**
   * Generates a responsive example string.
   *
   * Creates a responsive variant of the given utility class example by
   * adding a breakpoint prefix.
   *
   * @param string $example
   *   Base utility class example string.
   *
   * @return string
   *   Responsive variant with breakpoint prefix (e.g., 'uk-md-pd--20').
   */
  protected function getResponsiveExample(string $example): string {
    return preg_replace('/^uk-/', 'uk-md-', $example);
  }

  /**
   * Returns the value type for the rule.
   *
   * Determines and returns a human-readable description of the value type
   * accepted by a utility class rule.
   *
   * @param array $rule
   *   The rule definition containing type flags and configuration.
   *
   * @return string
   *   Human-readable value type description.
   */
  protected function getValueType(array $rule): string {
    if (!empty($rule['isColor'])) {
      return 'Hex color';
    }
    if (!empty($rule['isKeyword'])) {
      return 'CSS keyword';
    }
    if (!empty($rule['isOpacity'])) {
      return '0-100 (%)';
    }
    if (!empty($rule['isInteger'])) {
      return 'Integer';
    }
    if (!empty($rule['isDecimalFixed'])) {
      return 'Decimal number';
    }
    if (!empty($rule['isTransform'])) {
      return $rule['isTransform'] === 'rotate' ? 'Degrees' : 'Scale (%)';
    }
    if (!empty($rule['isGridTrackList'])) {
      return 'Grid track list';
    }
    if (!empty($rule['isRange'])) {
      return 'Range (start-end)';
    }
    if (!empty($rule['isNumericFlexible'])) {
      $viewport = in_array($rule['css'], ['width', 'height', 'maxWidth',
        'maxHeight', 'minWidth', 'minHeight', 'fontSize',
      ]);
      return $viewport ? 'px, %, em, rem, vh, vw' : 'px, %, em, rem';
    }
    return 'Value';
  }

  /**
   * Returns notes for the rule.
   *
   * Provides detailed usage notes and syntax information for specific
   * utility class types to help users understand proper usage patterns.
   *
   * @param array $rule
   *   The rule definition containing type flags and configuration.
   * @param string $prefix
   *   The utility class prefix for context-specific notes.
   *
   * @return string
   *   Detailed usage notes and syntax information.
   */
  protected function getNotes(array $rule, string $prefix): string {
    if (!empty($rule['isColor'])) {
      return 'Use 6-digit hex (ff0000) or 3-digit (f00). Add -50 for 50% opacity: uk-bg--ff0000-50';
    }

    if (!empty($rule['sides'])) {
      return $prefix === 'br'
        ? 'Use t/r/b/l for specific corners (uk-br--t-10) or shorthand (uk-br--10-20-30-40)'
        : 'Use t/r/b/l for specific sides (uk-pd--t-20) or shorthand (uk-pd--10-20)';
    }

    if (!empty($rule['isNumericFlexible'])) {
      $units = 'Units: px (default), pr (%), em, rem';
      if (in_array($prefix, ['wd', 'ht', 'xw', 'xh', 'nw', 'nh', 'fs'])) {
        $units .= ', vh, vw';
      }
      if (!empty($rule['allowAuto'])) {
        $units .= ', auto';
      }
      return $units;
    }

    if (!empty($rule['isTransform'])) {
      return $rule['isTransform'] === 'rotate'
        ? 'Rotation in degrees (0-360)'
        : 'Scale as percentage (100 = 1x, 150 = 1.5x)';
    }

    if (!empty($rule['isGridTrackList'])) {
      return 'Complex grid syntax: repeat(), minmax(), fr units, auto-fit/auto-fill';
    }

    if (!empty($rule['isRange'])) {
      return $prefix === 'ar'
        ? 'Common ratios: 16-9, 4-3, 1-1, 21-9'
        : 'Grid line numbers: 1-3 (start at 1, end at 3)';
    }

    if (!empty($rule['isOpacity'])) {
      return 'Value 0-100 converts to 0-1 opacity';
    }

    if (!empty($rule['isInteger'])) {
      $notes = [
        'zi' => 'Can be negative (-1) or positive (9999)',
        'fw' => 'Font weights: 100-900 in steps of 100',
        'or' => 'Flex/grid item order, can be negative',
      ];
      return $notes[$prefix] ?? 'Integer values only';
    }

    if (!empty($rule['isDecimalFixed'])) {
      return 'Decimal values like 1, 1.5, 2.25';
    }

    if ($prefix === 'gp') {
      return 'Single value (uk-gp--20) or two values (uk-gp--20-40) for row/column gap';
    }

    return '';
  }

  /**
   * Returns short notes for the rule.
   *
   * Provides concise summary notes suitable for table display with limited
   * space, focusing on the most important usage information.
   *
   * @param array $rule
   *   The rule definition containing type flags and configuration.
   * @param string $prefix
   *   The utility class prefix for context-specific notes.
   *
   * @return string
   *   Short summary of usage notes.
   */
  protected function getShortNote(array $rule, string $prefix): string {
    if (!empty($rule['isColor'])) {
      return 'Hex + optional opacity';
    }
    if (!empty($rule['sides'])) {
      return 'Supports sides + shorthand';
    }
    if (!empty($rule['isNumericFlexible'])) {
      if (!empty($rule['allowAuto'])) {
        return 'px, %, em, rem, auto';
      }
      return 'Multiple units';
    }
    if (!empty($rule['isKeyword'])) {
      return 'CSS keywords';
    }
    if (!empty($rule['isTransform'])) {
      return 'Transform value';
    }
    if (!empty($rule['isGridTrackList'])) {
      return 'Grid syntax';
    }
    if (!empty($rule['isRange'])) {
      return 'Range format';
    }
    if (!empty($rule['isOpacity'])) {
      return '0-100 → 0-1';
    }
    if (!empty($rule['isInteger'])) {
      return 'Integer only';
    }
    if (!empty($rule['isDecimalFixed'])) {
      return 'Decimal values';
    }

    return '';
  }

}

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

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