{% set header_actions %} {% endset %} {% call page_header(_("Photo Library"), actions=header_actions) %} {% if media_items|length == 0 %} {{ _("No photos found") }} {% elif view == 'timeline' %} {# Infinite scroll makes "showing N" stale the moment it loads; the timeline reports the total and streams the rest in. #} {% trans trimmed count=media_count, total=media_count|format_integer %} {{ total }} photo {% pluralize %} {{ total }} photos {% endtrans %} {% else %} {% trans trimmed count=media_items|length, shown=media_items|length|format_integer, total=media_count|format_integer %} Showing {{ shown }} of {{ total }} photo {% pluralize %} Showing {{ shown }} of {{ total }} photos {% endtrans %} {% endif %} {% endcall %} {% if media_items|length > 0 %} {% if view == 'timeline' %}
{% include "_timeline_sections.html" %}
{% if timeline_year_marks %} {# The date scrubber: a time-proportional rail (newest at the top) with one density bar per month — bar length shows how many photos that month holds. Year marks are plain links (the no-JS fallback); timeline_scrubber.js turns the rail into a draggable jump-to-month control using the month index below. #} {% endif %} {% else %}
{% for media_item in media_items %} {{ photo_card(media_item) }} {% endfor %}
{% endif %} {# The timeline streams batches through its sentinel instead of paginating — a page bar under an endless scroll (and beside the scrubber) would fight both. #} {% if view == 'grid' %} {{ render_pagination( pagination.current_page, pagination.total_items, pagination.page_size, pagination.page_sizes, url_for('index'), filter_params ) }} {% endif %} {% else %}

{{ _("No photos found") }}

{{ _("Try adjusting your filters or check back later.") }}

{% endif %}