Adiciona bloco MicrositeHeaderBlock e regiões ao tema do microsite

- Novo bloco MicrositeHeaderBlock (site_users_microsite): exibe foto
  circular (220×280px), nome (h1), biografia e contatos (telefone,
  e-mail). Título oculto por padrão; biografia renderizada via
  ->processed com |raw no template.
- Remove UserInfoBlock e seu template (não estava em uso).
- Adiciona regiões Top Bar e Navigation ao tema; menu.html.twig para
  gerar classes .menu__item/.menu__link compatíveis com o CSS.
- CSS: estilos das novas regiões e do bloco de cabeçalho.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 07:12:55 -03:00
parent 505c9fb64a
commit 84f4661798
7 changed files with 343 additions and 289 deletions

View File

@@ -0,0 +1,166 @@
<?php
namespace Drupal\site_users_microsite\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\user\UserInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Bloco de cabeçalho do microsite com informações do usuário.
*
* Exibe foto (circular), nome, biografia e
* informações de contato (telefone, e-mail).
*
* @Block(
* id = "site_users_microsite_header",
* admin_label = @Translation("Microsite — cabeçalho do usuário"),
* category = @Translation("Site Users")
* )
*/
class MicrositeHeaderBlock extends BlockBase implements ContainerFactoryPluginInterface {
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
protected RouteMatchInterface $routeMatch,
protected EntityTypeManagerInterface $entityTypeManager,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('current_route_match'),
$container->get('entity_type.manager'),
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration(): array {
return ['label_display' => '0'] + parent::defaultConfiguration();
}
/**
* {@inheritdoc}
*/
public function build(): array {
$user = $this->getUser();
if (!$user instanceof UserInterface) {
return [];
}
return [
'#theme' => 'microsite_header_block',
'#photo_url' => $this->getPhotoUrl($user),
'#photo_alt' => $this->getPhotoAlt($user),
'#name' => $this->getFieldValue($user, 'field_user_name') ?: $user->getDisplayName(),
'#bio' => $this->getProcessedValue($user, 'field_user_bio'),
'#phone' => $this->getFieldValue($user, 'field_user_phone'),
'#email' => $user->getEmail(),
'#cache' => [
'tags' => $user->getCacheTags(),
'contexts' => ['route'],
],
];
}
/**
* Retorna o usuário da rota atual.
*/
protected function getUser(): ?UserInterface {
$user = $this->routeMatch->getParameter('user');
if ($user instanceof UserInterface) {
return $user;
}
if (is_numeric($user)) {
return $this->entityTypeManager->getStorage('user')->load($user);
}
return NULL;
}
/**
* Retorna a URL absoluta da foto padrão do usuário.
*/
protected function getPhotoUrl(UserInterface $user): ?string {
if (!function_exists('site_users_get_default_photo')) {
return NULL;
}
$media = site_users_get_default_photo($user);
if (!$media) {
return NULL;
}
$source_field = $media->getSource()->getConfiguration()['source_field'];
if (!$media->hasField($source_field) || $media->get($source_field)->isEmpty()) {
return NULL;
}
$file = $media->get($source_field)->entity;
if (!$file) {
return NULL;
}
return \Drupal::service('file_url_generator')->generateAbsoluteString($file->getFileUri());
}
/**
* Retorna o texto alternativo da foto padrão.
*/
protected function getPhotoAlt(UserInterface $user): string {
if (!function_exists('site_users_get_default_photo')) {
return '';
}
$media = site_users_get_default_photo($user);
return $media ? $media->label() : '';
}
/**
* Retorna o valor de texto de um campo do usuário.
*/
protected function getFieldValue(UserInterface $user, string $field_name): ?string {
if ($user->hasField($field_name) && !$user->get($field_name)->isEmpty()) {
return $user->get($field_name)->value;
}
return NULL;
}
/**
* Retorna o valor processado (HTML filtrado) de um campo text_long.
*
* Usa ->processed, que aplica o formato de texto configurado e retorna um
* objeto Markup — o Twig renderiza como HTML sem escape adicional.
*/
protected function getProcessedValue(UserInterface $user, string $field_name): ?string {
if ($user->hasField($field_name) && !$user->get($field_name)->isEmpty()) {
return $user->get($field_name)->processed;
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function getCacheTags(): array {
$user = $this->getUser();
if ($user instanceof UserInterface) {
return Cache::mergeTags(parent::getCacheTags(), $user->getCacheTags());
}
return parent::getCacheTags();
}
/**
* {@inheritdoc}
*/
public function getCacheContexts(): array {
return Cache::mergeContexts(parent::getCacheContexts(), ['route']);
}
}