fd866418bb
Build & Deploy / build-and-deploy (push) Successful in 1m49s
Listing pages (blog, frontpage, likes, bookmarks, reposts, replies,
featured) only checked post.data.youtubeVideoId from frontmatter.
Older posts without that field fell through to unfurl, which cannot
scrape YouTube and returns a text-only fallback — no thumbnail image.
Apply the same URL-derived fallback already used in reply-context.njk:
{% set _ytId = post.data.youtubeVideoId or (likedUrl | youtubeId) %}
Frontmatter value still takes precedence; youtubeId filter handles
both youtube.com?v= and youtu.be/ formats.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
288 lines
15 KiB
Plaintext
288 lines
15 KiB
Plaintext
{#
|
|
Featured Posts Section - displays curated posts with `featured: true` frontmatter
|
|
Rendered by homepage-builder when featured-posts section is configured
|
|
Supports type-aware rendering for articles, notes, likes, bookmarks, reposts, replies, photos
|
|
#}
|
|
|
|
{% set sectionConfig = section.config or {} %}
|
|
{% set maxItems = sectionConfig.maxItems or 6 %}
|
|
{% set showSummary = sectionConfig.showSummary if sectionConfig.showSummary is defined else true %}
|
|
|
|
{% if collections.featuredPosts and collections.featuredPosts.length %}
|
|
<section class="mb-8 sm:mb-12">
|
|
<h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6 flex items-center gap-2">
|
|
<svg class="w-5 h-5 text-amber-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
|
|
</svg>
|
|
{{ sectionConfig.title or "Featured" }}
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
{% for post in collections.featuredPosts | head(maxItems) %}
|
|
{# Detect post type from frontmatter properties #}
|
|
{% set likedUrl = post.data.likeOf or post.data.like_of %}
|
|
{% set bookmarkedUrl = post.data.bookmarkOf or post.data.bookmark_of %}
|
|
{% set repostedUrl = post.data.repostOf or post.data.repost_of %}
|
|
{% set replyToUrl = post.data.inReplyTo or post.data.in_reply_to %}
|
|
{% set hasPhotos = post.data.photo and post.data.photo.length %}
|
|
|
|
{# Determine border color by post type #}
|
|
{% set borderClass = "" %}
|
|
{% if likedUrl %}
|
|
{% set borderClass = "border-l-[3px] border-l-red-400 dark:border-l-red-500" %}
|
|
{% elif bookmarkedUrl %}
|
|
{% set borderClass = "border-l-[3px] border-l-amber-400 dark:border-l-amber-500" %}
|
|
{% elif repostedUrl %}
|
|
{% set borderClass = "border-l-[3px] border-l-green-400 dark:border-l-green-500" %}
|
|
{% elif replyToUrl %}
|
|
{% set borderClass = "border-l-[3px] border-l-sky-400 dark:border-l-sky-500" %}
|
|
{% elif hasPhotos %}
|
|
{% set borderClass = "border-l-[3px] border-l-purple-400 dark:border-l-purple-500" %}
|
|
{% else %}
|
|
{% set borderClass = "border-l-[3px] border-l-surface-300 dark:border-l-surface-600" %}
|
|
{% endif %}
|
|
|
|
<article class="h-entry p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors {{ borderClass }}">
|
|
|
|
{% if likedUrl %}
|
|
{# ── Like card ── #}
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0 mt-1">
|
|
<svg class="w-5 h-5 text-red-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
|
|
</svg>
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-3 text-xs text-surface-600 dark:text-surface-400">
|
|
<span class="font-medium text-red-600 dark:text-red-400">Liked</span>
|
|
<time class="dt-published font-mono" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
</div>
|
|
{% set _ytId = post.data.youtubeVideoId or (likedUrl | youtubeId) %}
|
|
{% if _ytId %}
|
|
<div class="video-embed eleventy-plugin-youtube-embed not-prose my-4">
|
|
<lite-youtube videoid="{{ _ytId }}" style="background-image: url('https://i.ytimg.com/vi/{{ _ytId }}/hqdefault.jpg');"><div class="lty-playbtn"></div></lite-youtube>
|
|
</div>
|
|
{% else %}
|
|
{{ likedUrl | unfurlCard | safe }}
|
|
{% endif %}
|
|
<a class="u-like-of text-xs text-surface-600 dark:text-surface-400 hover:underline break-all mt-1 inline-block" href="{{ likedUrl }}">
|
|
{{ likedUrl }}
|
|
</a>
|
|
{% if post.templateContent %}
|
|
<div class="e-content prose dark:prose-invert prose-sm mt-2 max-w-none line-clamp-3">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-xs text-accent-600 dark:text-accent-400 hover:underline mt-2 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or (post.date | dateDisplay) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif bookmarkedUrl %}
|
|
{# ── Bookmark card ── #}
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0 mt-1">
|
|
<svg class="w-5 h-5 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"/>
|
|
</svg>
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-3 text-xs text-surface-600 dark:text-surface-400">
|
|
<span class="font-medium text-amber-800 dark:text-amber-400">Bookmarked</span>
|
|
<time class="dt-published font-mono" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
</div>
|
|
{% if post.data.title %}
|
|
<h3 class="p-name font-semibold mt-1">
|
|
<a class="text-surface-900 dark:text-surface-100 hover:text-accent-600 dark:hover:text-accent-400 hover:underline" href="{{ post.url }}">{{ post.data.title }}</a>
|
|
</h3>
|
|
{% endif %}
|
|
{% set _ytId = post.data.youtubeVideoId or (bookmarkedUrl | youtubeId) %}
|
|
{% if _ytId %}
|
|
<div class="video-embed eleventy-plugin-youtube-embed not-prose my-4">
|
|
<lite-youtube videoid="{{ _ytId }}" style="background-image: url('https://i.ytimg.com/vi/{{ _ytId }}/hqdefault.jpg');"><div class="lty-playbtn"></div></lite-youtube>
|
|
</div>
|
|
{% else %}
|
|
{{ bookmarkedUrl | unfurlCard | safe }}
|
|
{% endif %}
|
|
<a class="u-bookmark-of text-xs text-surface-600 dark:text-surface-400 hover:underline break-all mt-1 inline-block" href="{{ bookmarkedUrl }}">
|
|
{{ bookmarkedUrl }}
|
|
</a>
|
|
{% if post.templateContent %}
|
|
<div class="e-content prose dark:prose-invert prose-sm mt-2 max-w-none line-clamp-3">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-xs text-accent-600 dark:text-accent-400 hover:underline mt-2 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or (post.date | dateDisplay) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif repostedUrl %}
|
|
{# ── Repost card ── #}
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0 mt-1">
|
|
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
|
</svg>
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-3 text-xs text-surface-600 dark:text-surface-400">
|
|
<span class="font-medium text-green-800 dark:text-green-400">Reposted</span>
|
|
<time class="dt-published font-mono" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
</div>
|
|
{% set _ytId = post.data.youtubeVideoId or (repostedUrl | youtubeId) %}
|
|
{% if _ytId %}
|
|
<div class="video-embed eleventy-plugin-youtube-embed not-prose my-4">
|
|
<lite-youtube videoid="{{ _ytId }}" style="background-image: url('https://i.ytimg.com/vi/{{ _ytId }}/hqdefault.jpg');"><div class="lty-playbtn"></div></lite-youtube>
|
|
</div>
|
|
{% else %}
|
|
{{ repostedUrl | unfurlCard | safe }}
|
|
{% endif %}
|
|
<a class="u-repost-of text-xs text-surface-600 dark:text-surface-400 hover:underline break-all mt-1 inline-block" href="{{ repostedUrl }}">
|
|
{{ repostedUrl }}
|
|
</a>
|
|
{% if post.templateContent %}
|
|
<div class="e-content prose dark:prose-invert prose-sm mt-2 max-w-none line-clamp-3">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-xs text-accent-600 dark:text-accent-400 hover:underline mt-2 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or (post.date | dateDisplay) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif replyToUrl %}
|
|
{# ── Reply card ── #}
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0 mt-1">
|
|
<svg class="w-5 h-5 text-sky-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6"/>
|
|
</svg>
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-3 text-xs text-surface-600 dark:text-surface-400">
|
|
<span class="font-medium text-sky-700 dark:text-sky-400">In reply to</span>
|
|
<time class="dt-published font-mono" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
</div>
|
|
{% set _ytId = post.data.youtubeVideoId or (replyToUrl | youtubeId) %}
|
|
{% if _ytId %}
|
|
<div class="video-embed eleventy-plugin-youtube-embed not-prose my-4">
|
|
<lite-youtube videoid="{{ _ytId }}" style="background-image: url('https://i.ytimg.com/vi/{{ _ytId }}/hqdefault.jpg');"><div class="lty-playbtn"></div></lite-youtube>
|
|
</div>
|
|
{% else %}
|
|
{{ replyToUrl | unfurlCard | safe }}
|
|
{% endif %}
|
|
<a class="u-in-reply-to text-xs text-surface-600 dark:text-surface-400 hover:underline break-all mt-1 inline-block" href="{{ replyToUrl }}">
|
|
{{ replyToUrl }}
|
|
</a>
|
|
{% if post.templateContent %}
|
|
<div class="e-content prose dark:prose-invert prose-sm mt-2 max-w-none line-clamp-3">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-xs text-accent-600 dark:text-accent-400 hover:underline mt-2 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or (post.date | dateDisplay) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif hasPhotos %}
|
|
{# ── Photo card ── #}
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0 mt-1">
|
|
<svg class="w-5 h-5 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"/>
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"/>
|
|
</svg>
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-3 text-xs text-surface-600 dark:text-surface-400">
|
|
<span class="font-medium text-purple-600 dark:text-purple-400">Photo</span>
|
|
<time class="dt-published font-mono" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
</div>
|
|
<div class="photo-gallery mt-2">
|
|
{% for img in post.data.photo | head(2) %}
|
|
{% set photoUrl = img.url %}
|
|
{% if photoUrl and photoUrl[0] != '/' and 'http' not in photoUrl %}
|
|
{% set photoUrl = '/' + photoUrl %}
|
|
{% endif %}
|
|
<a href="{{ post.url }}" class="photo-link">
|
|
<img src="{{ photoUrl }}" alt="{{ img.alt | default('Photo from: ' + post.data.title) }}" class="u-photo rounded max-h-48 object-cover" loading="lazy" eleventy:ignore>
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
{% if post.templateContent %}
|
|
<div class="e-content prose dark:prose-invert prose-sm mt-2 max-w-none line-clamp-2">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-xs text-accent-600 dark:text-accent-400 hover:underline mt-2 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or (post.date | dateDisplay) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif post.data.title %}
|
|
{# ── Article/Page card ── #}
|
|
<h3 class="p-name font-semibold mb-1">
|
|
<a href="{{ post.url }}" class="u-url text-surface-900 dark:text-surface-100 hover:text-accent-600 dark:hover:text-accent-400 hover:underline">
|
|
{{ post.data.title }}
|
|
</a>
|
|
</h3>
|
|
{% if showSummary and post.templateContent %}
|
|
<p class="text-sm text-surface-600 dark:text-surface-400 mb-2 line-clamp-2">
|
|
{{ post.templateContent | striptags | truncate(250) }}
|
|
</p>
|
|
{% endif %}
|
|
<div class="flex items-center gap-3 text-xs text-surface-600 dark:text-surface-400">
|
|
<time class="dt-published font-mono" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
{% if post.data.postType %}
|
|
<span class="px-2 py-0.5 bg-surface-100 dark:bg-surface-700 rounded-full">
|
|
{{ post.data.postType }}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% else %}
|
|
{# ── Note card ── #}
|
|
<div class="flex items-center gap-3 text-xs text-surface-600 dark:text-surface-400 mb-2">
|
|
<a class="u-url" href="{{ post.url }}">
|
|
<time class="dt-published font-medium font-mono text-surface-600 dark:text-surface-400" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
</a>
|
|
{% if post.data.postType %}
|
|
<span class="px-2 py-0.5 bg-surface-100 dark:bg-surface-700 rounded-full">
|
|
{{ post.data.postType }}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
{% if post.templateContent %}
|
|
<div class="e-content prose dark:prose-invert prose-sm max-w-none line-clamp-3">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a href="{{ post.url }}" class="text-xs text-accent-600 dark:text-accent-400 hover:underline mt-2 inline-block" aria-label="Permalink: {{ post.data.title or (post.date | dateDisplay) }}">
|
|
Permalink
|
|
</a>
|
|
{% endif %}
|
|
|
|
</article>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
{% if collections.featuredPosts.length > maxItems %}
|
|
<div class="mt-4 text-center">
|
|
<a href="/featured/" class="inline-flex items-center gap-1 text-sm text-accent-600 dark:text-accent-400 hover:underline font-medium">
|
|
View all {{ collections.featuredPosts.length }} featured posts →
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</section>
|
|
{% endif %}
|