{# Content Components Reusable macro-based content display components for the Bengal default theme. Components: - article_card(article, show_excerpt=True, show_image=False): Rich article preview card - child_page_tiles(posts=None, subsections=None): Subsections and child pages as compact tiles - tag_list(tags, small=False, linkable=True): Styled tag badges - popular_tags(limit=10): Tag cloud widget with popular tags - random_posts(count=3): Random post discovery widget Usage: {% from 'partials/content-components.html' import article_card, tag_list %} {{ article_card(post, show_image=True) }} {{ tag_list(page.tags, small=True) }} #} {# Article Card Component Displays a rich card preview of an article with metadata, tags, and optional image. Args: article: Page object to display (required) show_excerpt: Boolean (default: True) - show description/excerpt show_image: Boolean (default: False) - show featured image Example: {{ article_card(post, show_image=True, show_excerpt=True) }} #} {% macro article_card(article, show_excerpt=True, show_image=False) %}
{% if show_image and article.metadata.get('image') %} {# Responsive image with srcset - dogfooding image_srcset() #} {{ article.metadata.get('image') | image_alt }} {% endif %}
{# Tag badges - dogfooding has_tag() #}
{% if article | has_tag('featured') %} ⭐ Featured {% endif %} {% if article | has_tag('tutorial') %} 📚 Tutorial {% endif %} {% if article | has_tag('new') %} ✨ New {% endif %}

{{ article.title }}

{% if article.date %} {% endif %} {% if article.metadata.get('author') %} {{ article.metadata.get('author') }} {% endif %} {% if article.content %} {{ article.content | reading_time }} min read {% endif %}
{% if show_excerpt %}

{% if article.metadata.get('description') %} {{ article.metadata.get('description') }} {% elif article.content %} {{ article.content | strip_html | excerpt(150) }} {% endif %}

{% endif %} {% if article.tags %}
{{ tag_list(article.tags, small=True) }}
{% endif %}
{% endmacro %} {# Child Page Tiles Component Displays subsections and child pages as compact row-based items with icons. Args: posts: List of child pages to display (optional, defaults to None) subsections: List of child sections to display (optional, defaults to None) Example: {{ child_page_tiles(posts=page.regular_pages, subsections=page.sections) }} #} {% macro child_page_tiles(posts=None, subsections=None) %} {% if posts or subsections %} {# Merge subsections and pages into unified list #} {% set all_items = [] %} {# Add subsections with metadata #} {% if subsections %} {% for subsection in subsections %} {% set _ = all_items.append({ 'type': 'section', 'obj': subsection, 'title': subsection.title, 'url': url_for(subsection), 'description': subsection.metadata.get('description', '') if subsection.metadata and subsection.metadata.get('description', '') else '', 'weight': subsection.metadata.get('weight', 999999) if subsection.metadata else 999999, 'page_count': subsection.pages | length if subsection.pages else 0 }) %} {% endfor %} {% endif %} {# Add pages with metadata #} {% if posts %} {% for post in posts %} {% set _ = all_items.append({ 'type': 'page', 'obj': post, 'title': post.title, 'url': url_for(post), 'description': post.metadata.get('description', '') if post.metadata and post.metadata.get('description', '') else (post.content | strip_html | excerpt(120) if post.content else ''), 'weight': post.metadata.get('weight', 999999) if post.metadata else 999999, 'date': post.date if post.date else none }) %} {% endfor %} {% endif %} {# Sort by weight (ascending), then title #} {% set sorted_items = all_items | sort(attribute='weight,title') %}
{% for item in sorted_items %}
{% if item.type == 'section' %} {% else %} {% endif %}
{{ item.title }} {% if item.description %} {{ item.description }} {% endif %} {% if item.type == 'section' and item.page_count > 0 %} {{ item.page_count }} page{{ 's' if item.page_count != 1 }} {% elif item.type == 'page' and item.date %} {{ item.date | time_ago }} {% endif %}
{% endfor %}
{% endif %} {% endmacro %} {# Tag List Component Displays tags as styled badges, optionally linkable to tag archive pages. Args: tags: List of tag strings (required) small: Boolean (default: False) - use smaller size linkable: Boolean (default: True) - make tags clickable Example: {{ tag_list(page.tags) }} {{ tag_list(article.tags, small=True, linkable=False) }} #} {% macro tag_list(tags, small=False, linkable=True) %}
{% for tag in tags %} {% if linkable %} {# Locale-aware tag link: if prefix strategy and non-default or default_in_subdir, prefix with language #} {% set _i18n = site.config.get('i18n', {}) %} {% set _lang = current_lang() %} {% set _default = _i18n.get('default_language', 'en') if _i18n else 'en' %} {% set _in_subdir = _i18n.get('default_in_subdir', False) if _i18n else False %} {% set _prefix = '' %} {% if _i18n and _i18n.get('strategy') == 'prefix' and _lang and (_in_subdir or _lang != _default) %} {% set _prefix = '/' ~ _lang %} {% endif %} {{ tag }} {% else %} {{ tag }} {% endif %} {% endfor %}
{% endmacro %} {# Popular Tags Component Displays a tag cloud widget showing the most frequently used tags across the site. Args: limit: Number of tags to show (default: 10) Example: {{ popular_tags(limit=20) }} #} {% macro popular_tags_widget(limit=10) %} {% set top_tags = popular_tags(limit=limit) %} {% if top_tags %} {% endif %} {% endmacro %} {# Random Posts Component Displays a widget with randomly selected posts from the site. Args: count: Number of random posts to show (default: 3) Example: {{ random_posts(count=5) }} #} {% macro random_posts(count=3) %} {% set random_posts = site.regular_pages | sample(count) %} {% if random_posts %} {% endif %} {% endmacro %}