17 changed files with 297 additions and 37 deletions
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Service; |
||||
|
||||
use App\Repository\FeaturedAuthorRepository; |
||||
use swentel\nostr\Key\Key; |
||||
|
||||
/** |
||||
* NIP-05 / listed featured author rows (same shape as {@see \App\Controller\FeaturedAuthorsController}). |
||||
*/ |
||||
final class FeaturedAuthorListedRows |
||||
{ |
||||
public function __construct( |
||||
private readonly FeaturedAuthorRepository $featuredAuthorRepository, |
||||
private readonly CacheService $cacheService, |
||||
) { |
||||
} |
||||
|
||||
/** |
||||
* @return list<array{npub: string, pubkey: string, display_name: string, picture: string, local_part: string}> |
||||
*/ |
||||
public function buildListedByLocalPartPage(int $limit, int $offset = 0): array |
||||
{ |
||||
$keys = new Key(); |
||||
$authors = []; |
||||
foreach ($this->featuredAuthorRepository->findListedOrderByLocalPartPaginated($limit, $offset) as $fa) { |
||||
$npub = $keys->convertPublicKeyToBech32($fa->getPubkeyHex()); |
||||
$bundle = $this->cacheService->getMetadataBundle($npub); |
||||
$author = $bundle['content']; |
||||
$displayName = trim((string) ($author->display_name ?? $author->name ?? '')); |
||||
$picture = trim((string) ($author->picture ?? '')); |
||||
$authors[] = [ |
||||
'npub' => $npub, |
||||
'pubkey' => strtolower($fa->getPubkeyHex()), |
||||
'display_name' => $displayName, |
||||
'picture' => $picture, |
||||
'local_part' => $fa->getLocalPart(), |
||||
]; |
||||
} |
||||
|
||||
return $authors; |
||||
} |
||||
} |
||||
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Twig; |
||||
|
||||
use App\Service\FeaturedAuthorListedRows; |
||||
use Twig\Extension\AbstractExtension; |
||||
use Twig\TwigFunction; |
||||
|
||||
/** Twig function for the left nav featured-author avatars (avoids Symfony UX component context quirks). */ |
||||
final class SidebarFeaturedAuthorsExtension extends AbstractExtension |
||||
{ |
||||
public function __construct( |
||||
private readonly FeaturedAuthorListedRows $featuredAuthorListedRows, |
||||
) { |
||||
} |
||||
|
||||
public function getFunctions(): array |
||||
{ |
||||
return [ |
||||
new TwigFunction('sidebar_featured_author_rows', function (int $limit = 12): array { |
||||
return $this->featuredAuthorListedRows->buildListedByLocalPartPage($limit, 0); |
||||
}), |
||||
]; |
||||
} |
||||
} |
||||
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
{% if rows is defined and rows is not empty %} |
||||
<section class="sidebar-featured-authors" aria-label="{{ 'sidebar.featured_authors'|trans }}"> |
||||
<h2 class="sidebar-featured-authors__title">{{ 'sidebar.featured_authors'|trans }}</h2> |
||||
<ul class="sidebar-featured-authors__grid" role="list"> |
||||
{% for row in rows %} |
||||
{% set _name = row.display_name|default('')|trim %} |
||||
{% set _label = _name != '' ? _name : (row.npub|shortenNpub) %} |
||||
{% set _avatar_src = row.picture|default('')|trim != '' ? row.picture : asset('icons/favicon-96x96.png') %} |
||||
<li class="sidebar-featured-authors__item"> |
||||
<a |
||||
class="sidebar-featured-authors__link" |
||||
href="{{ path('author-profile', { npub: row.npub }) }}" |
||||
title="{{ _label|e('html_attr') }}" |
||||
> |
||||
<span class="sidebar-featured-authors__avatar"> |
||||
<img |
||||
src="{{ _avatar_src|e('html_attr') }}" |
||||
alt="" |
||||
width="40" |
||||
height="40" |
||||
loading="lazy" |
||||
decoding="async" |
||||
onerror="this.onerror=null;this.src='{{ asset('icons/favicon-96x96.png')|e('js') }}';" |
||||
> |
||||
</span> |
||||
<span class="visually-hidden">{{ _label }}</span> |
||||
</a> |
||||
</li> |
||||
{% endfor %} |
||||
</ul> |
||||
</section> |
||||
{% endif %} |
||||
Loading…
Reference in new issue