7 changed files with 194 additions and 27 deletions
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Service; |
||||
|
||||
use App\Entity\Article; |
||||
use App\Repository\ArticleHighlightRepository; |
||||
use App\Util\CommonMark\Converter; |
||||
use League\CommonMark\Exception\CommonMarkException; |
||||
|
||||
/** |
||||
* Markdown → HTML for an {@see Article}, with the same kind-9802 highlight injection as {@see \App\Controller\ArticleController}. |
||||
*/ |
||||
final class ArticleBodyHtmlRenderer |
||||
{ |
||||
public function __construct( |
||||
private readonly Converter $converter, |
||||
private readonly ArticleHighlightRepository $articleHighlightRepository, |
||||
private readonly ArticleBodyHighlightInjector $articleBodyHighlightInjector, |
||||
) { |
||||
} |
||||
|
||||
public function renderForArticle(Article $article): string |
||||
{ |
||||
$raw = (string) ($article->getContent() ?? ''); |
||||
try { |
||||
$html = $this->converter->convertToHTML($raw); |
||||
} catch (CommonMarkException) { |
||||
$html = htmlspecialchars($raw, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); |
||||
} |
||||
$highlights = $this->articleHighlightRepository->findByArticle($article); |
||||
|
||||
return $this->articleBodyHighlightInjector->inject($html, $highlights)['html']; |
||||
} |
||||
} |
||||
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
{# |
||||
NIP-51 30004 home strip: section title from list `title` tag; each item reads like a static landing |
||||
section — illustration (max 400px, natural aspect), headline, then full article body (Markdown + |
||||
highlights as on /p/…/d/…). Body is not wrapped in a single <a> (markdown may contain links). |
||||
#} |
||||
{% if tiles is not empty %} |
||||
<section |
||||
class="home-curation-landmark" |
||||
{% if section_title|default('') != '' %} |
||||
aria-labelledby="home-curation-landmark-heading" |
||||
{% else %} |
||||
aria-label="{{ (website_name ~ ' — curated articles')|e('html_attr') }}" |
||||
{% endif %} |
||||
> |
||||
{% if section_title|default('') != '' %} |
||||
<h2 id="home-curation-landmark-heading" class="home-curation-landmark__title">{{ section_title|e }}</h2> |
||||
{% endif %} |
||||
<div class="home-curation-landmark__articles"> |
||||
{% for tile in tiles %} |
||||
{% set item = tile.article %} |
||||
{% set article_href = (item.pubkey and npub_from_hex(item.pubkey) != '') ? path('article', { npub: npub_from_hex(item.pubkey), slug: item.slug }) : path('article-legacy-redirect', { slug: item.slug }) %} |
||||
<article class="curation-article-display"> |
||||
<div class="curation-article-display__media"> |
||||
<a href="{{ article_href }}" tabindex="-1" aria-hidden="true"> |
||||
<img |
||||
src="{{ article_card_cover(item.image, item.pubkey) }}" |
||||
alt="{{ ('Illustration for ' ~ item.title)|e('html_attr') }}" |
||||
loading="{{ loop.first ? 'eager' : 'lazy' }}" |
||||
decoding="async" |
||||
> |
||||
</a> |
||||
</div> |
||||
<div class="curation-article-display__body"> |
||||
<h3 class="curation-article-display__headline"> |
||||
<a class="curation-article-display__title-link" href="{{ article_href }}">{{ item.title|e }}</a> |
||||
</h3> |
||||
<div |
||||
class="article-main curation-article-display__main" |
||||
data-controller="user-highlight-tooltip" |
||||
> |
||||
{{ tile.body_html|raw }} |
||||
</div> |
||||
</div> |
||||
</article> |
||||
{% endfor %} |
||||
</div> |
||||
</section> |
||||
{% endif %} |
||||
Loading…
Reference in new issue