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>
375 lines
19 KiB
Plaintext
375 lines
19 KiB
Plaintext
{#
|
|
Recent Posts Section - displays latest posts from any collection
|
|
Rendered by homepage-builder when recent-posts section is configured
|
|
Redesigned to match the visual language used on /blog/
|
|
#}
|
|
|
|
{% set sectionConfig = section.config or {} %}
|
|
{% set maxItems = sectionConfig.maxItems or 5 %}
|
|
{% set showSummary = sectionConfig.showSummary if sectionConfig.showSummary is defined else true %}
|
|
{% set excludeTypes = sectionConfig.excludeTypes or [] %}
|
|
{% set primaryPosts = collections.posts if (collections and collections.posts) else [] %}
|
|
{% set fallbackRecentPosts = collections.recentPosts if (collections and collections.recentPosts) else [] %}
|
|
{% set listedPosts = primaryPosts | excludeUnlistedPosts | excludePostTypes(excludeTypes) %}
|
|
{% if not (listedPosts and listedPosts.length) %}
|
|
{% set listedPosts = fallbackRecentPosts | excludeUnlistedPosts | excludePostTypes(excludeTypes) %}
|
|
{% endif %}
|
|
|
|
{% if listedPosts and listedPosts.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">
|
|
{{ sectionConfig.title or "Recent Posts" }}
|
|
</h2>
|
|
|
|
<ul class="post-list">
|
|
{% for post in listedPosts | 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 %}
|
|
|
|
{% 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" %}
|
|
{% elif post.data.title %}
|
|
{% set borderClass = "border-l-[3px] border-l-indigo-400 dark:border-l-indigo-500" %}
|
|
{% else %}
|
|
{% set borderClass = "border-l-[3px] border-l-teal-400 dark:border-l-teal-500" %}
|
|
{% endif %}
|
|
|
|
<li class="h-entry post-card {{ borderClass }}">
|
|
{% if likedUrl %}
|
|
{# Like #}
|
|
<div class="post-header 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="post-meta">
|
|
<span class="font-medium text-red-600 dark:text-red-400">Liked</span>
|
|
<time-difference><time class="dt-published font-mono text-sm" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time></time-difference>
|
|
{% if post.data.category | withoutGardenTags %}
|
|
<span class="post-categories">
|
|
{% if post.data.category is string %}
|
|
<a href="/categories/{{ post.data.category | nestedSlugify }}/" class="p-category">{{ post.data.category }}</a>
|
|
{% else %}
|
|
{% for cat in (post.data.category | withoutGardenTags) %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category">{{ cat }}</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</span>
|
|
{% endif %}
|
|
{% include "components/garden-badge.njk" %}
|
|
</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-3 max-w-none">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-sm text-red-600 dark:text-red-400 hover:underline mt-3 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or ('Like from ' + (post.date | dateDisplay)) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif bookmarkedUrl %}
|
|
{# Bookmark #}
|
|
<div class="post-header 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="post-meta">
|
|
<span class="font-medium text-amber-800 dark:text-amber-400">Bookmarked</span>
|
|
<time-difference><time class="dt-published font-mono text-sm" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time></time-difference>
|
|
{% if post.data.category | withoutGardenTags %}
|
|
<span class="post-categories">
|
|
{% if post.data.category is string %}
|
|
<a href="/categories/{{ post.data.category | nestedSlugify }}/" class="p-category">{{ post.data.category }}</a>
|
|
{% else %}
|
|
{% for cat in (post.data.category | withoutGardenTags) %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category">{{ cat }}</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</span>
|
|
{% endif %}
|
|
{% include "components/garden-badge.njk" %}
|
|
</div>
|
|
{% if post.data.title %}
|
|
<h3 class="p-name text-lg font-semibold text-surface-900 dark:text-surface-100 mt-2">
|
|
<a class="hover:text-amber-800 dark:hover:text-amber-400" 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-3 max-w-none">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-sm text-amber-800 dark:text-amber-400 hover:underline mt-3 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or ('Bookmark from ' + (post.date | dateDisplay)) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif repostedUrl %}
|
|
{# Repost #}
|
|
<div class="post-header 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="post-meta">
|
|
<span class="font-medium text-green-800 dark:text-green-400">Reposted</span>
|
|
<time-difference><time class="dt-published font-mono text-sm" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time></time-difference>
|
|
{% if post.data.category | withoutGardenTags %}
|
|
<span class="post-categories">
|
|
{% if post.data.category is string %}
|
|
<a href="/categories/{{ post.data.category | nestedSlugify }}/" class="p-category">{{ post.data.category }}</a>
|
|
{% else %}
|
|
{% for cat in (post.data.category | withoutGardenTags) %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category">{{ cat }}</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</span>
|
|
{% endif %}
|
|
{% include "components/garden-badge.njk" %}
|
|
</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-3 max-w-none">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-sm text-green-800 dark:text-green-400 hover:underline mt-3 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or ('Repost from ' + (post.date | dateDisplay)) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif replyToUrl %}
|
|
{# Reply #}
|
|
<div class="post-header 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="post-meta">
|
|
<span class="font-medium text-sky-700 dark:text-sky-400">In reply to</span>
|
|
<time-difference><time class="dt-published font-mono text-sm" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time></time-difference>
|
|
{% if post.data.category | withoutGardenTags %}
|
|
<span class="post-categories">
|
|
{% if post.data.category is string %}
|
|
<a href="/categories/{{ post.data.category | nestedSlugify }}/" class="p-category">{{ post.data.category }}</a>
|
|
{% else %}
|
|
{% for cat in (post.data.category | withoutGardenTags) %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category">{{ cat }}</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</span>
|
|
{% endif %}
|
|
{% include "components/garden-badge.njk" %}
|
|
</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-3 max-w-none">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-sm text-sky-700 dark:text-sky-400 hover:underline mt-3 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or ('Reply from ' + (post.date | dateDisplay)) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif hasPhotos %}
|
|
{# Photo #}
|
|
<div class="post-header 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="post-meta">
|
|
<span class="font-medium text-purple-600 dark:text-purple-400">Photo</span>
|
|
<time-difference><time class="dt-published font-mono text-sm" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time></time-difference>
|
|
{% if post.data.category | withoutGardenTags %}
|
|
<span class="post-categories">
|
|
{% if post.data.category is string %}
|
|
<a href="/categories/{{ post.data.category | nestedSlugify }}/" class="p-category">{{ post.data.category }}</a>
|
|
{% else %}
|
|
{% for cat in (post.data.category | withoutGardenTags) %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category">{{ cat }}</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</span>
|
|
{% endif %}
|
|
{% include "components/garden-badge.njk" %}
|
|
</div>
|
|
<div class="photo-gallery mt-3">
|
|
{% 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') }}" class="u-photo" loading="lazy" eleventy:ignore>
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
{% if post.templateContent %}
|
|
<div class="e-content photo-caption prose dark:prose-invert prose-sm mt-3 max-w-none">
|
|
{{ post.templateContent | safe }}
|
|
</div>
|
|
{% endif %}
|
|
<a class="u-url text-sm text-purple-600 dark:text-purple-400 hover:underline mt-3 inline-block" href="{{ post.url }}" aria-label="Permalink: {{ post.data.title or ('Photo from ' + (post.date | dateDisplay)) }}">Permalink</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% elif post.data.title and (post.data.title | trim) %}
|
|
{# Article #}
|
|
<div class="post-header">
|
|
<h3 class="text-xl font-semibold mb-1">
|
|
<a class="p-name u-url text-surface-900 dark:text-surface-100 hover:text-indigo-600 dark:hover:text-indigo-400" href="{{ post.url }}">
|
|
{{ post.data.title }}
|
|
</a>
|
|
</h3>
|
|
<div class="post-meta">
|
|
<time class="dt-published font-mono text-sm" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time>
|
|
{% if post.data.category | withoutGardenTags %}
|
|
<span class="post-categories">
|
|
{% if post.data.category is string %}
|
|
<a href="/categories/{{ post.data.category | nestedSlugify }}/" class="p-category">{{ post.data.category }}</a>
|
|
{% else %}
|
|
{% for cat in (post.data.category | withoutGardenTags) %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category">{{ cat }}</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</span>
|
|
{% endif %}
|
|
{% include "components/garden-badge.njk" %}
|
|
</div>
|
|
</div>
|
|
{% if showSummary and post.templateContent %}
|
|
<p class="p-summary text-surface-700 dark:text-surface-300 mt-3">
|
|
{{ post.templateContent | striptags | truncate(250) }}
|
|
</p>
|
|
{% endif %}
|
|
<a href="{{ post.url }}" class="text-sm text-indigo-600 dark:text-indigo-400 hover:underline mt-3 inline-block" aria-label="Read more: {{ post.data.title }}">
|
|
Read more →
|
|
</a>
|
|
|
|
{% else %}
|
|
{# Note #}
|
|
<div class="post-header">
|
|
<a class="u-url" href="{{ post.url }}">
|
|
<time-difference><time class="dt-published text-sm text-surface-600 dark:text-surface-400 font-medium font-mono" datetime="{{ post.date | isoDate }}">
|
|
{{ post.date | dateDisplay }}
|
|
</time></time-difference>
|
|
</a>
|
|
{% if post.data.category | withoutGardenTags %}
|
|
<span class="post-categories ml-2">
|
|
{% if post.data.category is string %}
|
|
<a href="/categories/{{ post.data.category | nestedSlugify }}/" class="p-category">{{ post.data.category }}</a>
|
|
{% else %}
|
|
{% for cat in (post.data.category | withoutGardenTags) %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category">{{ cat }}</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</span>
|
|
{% endif %}
|
|
{% include "components/garden-badge.njk" %}
|
|
</div>
|
|
<div class="e-content prose dark:prose-invert prose-sm mt-3 max-w-none">
|
|
{% if post.content and post.content.html %}
|
|
{{ post.content.html | safe }}
|
|
{% else %}
|
|
{{ post.templateContent | safe }}
|
|
{% endif %}
|
|
</div>
|
|
<div class="post-footer mt-3">
|
|
<a href="{{ post.url }}" class="text-sm text-teal-600 dark:text-teal-400 hover:underline" aria-label="Permalink: {{ post.data.title or ('Note from ' + (post.date | dateDisplay)) }}">
|
|
Permalink
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
|
|
{% if sectionConfig.showViewAll != false %}
|
|
<a href="{{ sectionConfig.viewAllUrl or '/blog/' }}" class="text-sm text-accent-700 dark:text-accent-300 hover:underline mt-4 inline-flex items-center gap-1">
|
|
{{ sectionConfig.viewAllText or "View all posts" }}
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
|
</svg>
|
|
</a>
|
|
{% endif %}
|
|
</section>
|
|
{% endif %}
|