10 changed files with 604 additions and 9 deletions
@ -0,0 +1,63 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace App\Twig\Components\Atoms; |
||||||
|
|
||||||
|
use App\Repository\UserEntityRepository; |
||||||
|
use App\Service\RedisCacheService; |
||||||
|
use App\Util\NostrKeyUtil; |
||||||
|
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; |
||||||
|
|
||||||
|
#[AsTwigComponent] |
||||||
|
final class FeaturedWriters |
||||||
|
{ |
||||||
|
public array $writers = []; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
private readonly RedisCacheService $redisCacheService, |
||||||
|
private readonly UserEntityRepository $userRepository |
||||||
|
) {} |
||||||
|
|
||||||
|
public function mount(): void |
||||||
|
{ |
||||||
|
// Get top 3 featured writers ordered by most recent article |
||||||
|
$featuredUsers = $this->userRepository->findTopFeaturedWriters(3); |
||||||
|
|
||||||
|
if (empty($featuredUsers)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Convert npubs to hex pubkeys for metadata lookup |
||||||
|
$hexPubkeys = []; |
||||||
|
$npubToHex = []; |
||||||
|
foreach ($featuredUsers as $user) { |
||||||
|
$npub = $user->getNpub(); |
||||||
|
if (NostrKeyUtil::isNpub($npub)) { |
||||||
|
$hex = NostrKeyUtil::npubToHex($npub); |
||||||
|
$hexPubkeys[] = $hex; |
||||||
|
$npubToHex[$npub] = $hex; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($hexPubkeys)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Batch fetch metadata for all featured writers |
||||||
|
$metadataMap = $this->redisCacheService->getMultipleMetadata($hexPubkeys); |
||||||
|
|
||||||
|
// Build writers array with npub and metadata |
||||||
|
foreach ($featuredUsers as $user) { |
||||||
|
$npub = $user->getNpub(); |
||||||
|
$hex = $npubToHex[$npub] ?? null; |
||||||
|
if ($hex && isset($metadataMap[$hex])) { |
||||||
|
$this->writers[] = [ |
||||||
|
'npub' => $npub, |
||||||
|
'pubkey' => $hex, |
||||||
|
'metadata' => $metadataMap[$hex], |
||||||
|
'user' => $user, |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,47 @@ |
|||||||
|
{% if writers is not empty %} |
||||||
|
<div class="featured-writers"> |
||||||
|
<div class="d-flex gap-3 center mt-3 mb-3 ln-section--reader"> |
||||||
|
<h2 class="mb-4"> |
||||||
|
<a href="{{ path('forum') }}">Writers</a> |
||||||
|
</h2> |
||||||
|
</div> |
||||||
|
<ul class="featured-writers-list list-unstyled"> |
||||||
|
{% for writer in writers %} |
||||||
|
<li class="featured-writer-item"> |
||||||
|
<a href="{{ path('author-profile', { npub: writer.npub }) }}" class="featured-writer-link"> |
||||||
|
{% if writer.metadata.picture is defined and writer.metadata.picture %} |
||||||
|
<img src="{{ writer.metadata.picture }}" |
||||||
|
alt="{{ writer.metadata.display_name ?? writer.metadata.name ?? 'Writer' }}" |
||||||
|
class="featured-writer-avatar" |
||||||
|
loading="lazy" |
||||||
|
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';" |
||||||
|
/> |
||||||
|
<span class="featured-writer-avatar-placeholder" style="display: none;"> |
||||||
|
<twig:ux:icon name="iconoir:user" class="icon" /> |
||||||
|
</span> |
||||||
|
{% else %} |
||||||
|
<span class="featured-writer-avatar-placeholder"> |
||||||
|
<twig:ux:icon name="iconoir:user" class="icon" /> |
||||||
|
</span> |
||||||
|
{% endif %} |
||||||
|
<span class="featured-writer-info"> |
||||||
|
<span class="featured-writer-name"> |
||||||
|
<twig:Atoms:NameOrNpub :author="writer.metadata" :npub="writer.npub" /> |
||||||
|
</span> |
||||||
|
{% if writer.metadata.nip05 is defined and writer.metadata.nip05 %} |
||||||
|
<span class="featured-writer-nip05"> |
||||||
|
{% if writer.metadata.nip05 is iterable %} |
||||||
|
{{ writer.metadata.nip05|first }} |
||||||
|
{% else %} |
||||||
|
{{ writer.metadata.nip05 }} |
||||||
|
{% endif %} |
||||||
|
</span> |
||||||
|
{% endif %} |
||||||
|
</span> |
||||||
|
</a> |
||||||
|
</li> |
||||||
|
{% endfor %} |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
|
||||||
Loading…
Reference in new issue