{# ================================================================================ Post Card Component (Shared) ================================================================================ Single shared component for blog post cards with variants: featured, default, compact. Uses PostView for normalized access. All links use p.href (includes baseurl for GitHub Pages / subpath deployment). Usage: {{ post_card(post, variant='default', show_image=true, show_excerpt=true) }} Variants: - featured: larger Chirp UI resource card with full date format - default: standard Chirp UI resource card with time_ago - compact: minimal (title, date, optional excerpt) ================================================================================ #} {% from 'partials/components/tags.html' import tag_list %} {% from 'chirpui/card.html' import resource_card %} {% def post_card(post, variant='default', show_image=true, show_excerpt=true) %} {% let p = post | post_view %} {% if p %} {% let theme_features = theme?.features ?? [] %} {% let show_author = p.author and 'content.author' in theme_features %} {% let show_reading_time = p.reading_time > 0 and 'content.reading_time' in theme_features %} {% let show_full_date = variant == 'featured' %} {% let meta_parts = [] %} {% if show_author %} {% set _ = meta_parts.append(p.author) %} {% end %} {% if p.date %} {% set _ = meta_parts.append(p.date | dateformat('%B %d, %Y') if show_full_date else p.date | time_ago) %} {% end %} {% if show_reading_time %} {% set _ = meta_parts.append(p.reading_time ~ ' min read') %} {% end %} {% let top_meta = meta_parts | join(' ยท ') if meta_parts | length > 0 else none %} {% let excerpt_words = (p.excerpt_words ?? config.content.excerpt_words ?? 150) | coerce_int(150) %} {% let excerpt_html = '' %} {% if show_excerpt and p.excerpt and 'content.excerpts' in theme_features %} {% let excerpt_html = p.excerpt | card_excerpt_html(excerpt_words, p.title, p.description, halve_words=(variant == 'compact')) %} {% end %} {% let tag_limit = 3 if variant == 'featured' else 2 if variant == 'compact' else 4 %} {# card_excerpt_html dedupes the leading title/description and truncates on a word boundary; strip the surviving inline tags so the text rides the purpose-built resource_card description slot. Passing it via description= (not as a bare default-slot child) is what keeps it INSIDE the card: kida misroutes loose call-body content that coexists with a named {% slot %}, which previously stranded the excerpt as a sibling of the
. #} {% let excerpt_text = (excerpt_html | strip_html | trim) if excerpt_html else none %} {% call resource_card( p.href, p.title, description=(excerpt_text or none), top_meta=top_meta, cls='chirp-theme-post-card chirp-theme-post-card--' ~ variant, link_mode='main' ) %} {# Keep {% slot footer %} a DIRECT, unconditional child of the call: kida only hoists slot-fills it sees at the top level of the call body. Wrapping the slot in {% if %} made kida treat its tags as default-slot content, so they rendered inside the card's main (nested anchors) instead of the footer. Guard on the tag count INSIDE the slot instead. #} {% slot footer %} {% if p.tags | length > 0 %}{{ tag_list(p.tags[:tag_limit], small=true) }}{% end %} {% end %} {% end %} {% end %} {% end %}