{% extends 'base.html' %} {% block scripts %} {% endblock %} {% block heading %}{{ title }}{% if letter %}: "{{ letter.upper() }}"{% endif %}{% endblock %} {% block heading_action %} {% if admin %} {# MSG: Button to open the batch song renamer page. #} {% trans %}Bulk rename{% endtrans %} {% endif %} {% endblock %} {% block header %} {# MSG: Subtitle under the Songs heading, explaining that this page lists songs already downloaded. #}

{% trans %}Available in the library{% endtrans %}

{% endblock %} {% block content %} {# A folder holding only subfolders is navigation, not a result set: no singer field, no filter box, no A-Z bar, no sort toggle and no empty table -- just the folders. An active filter keeps them all, so a query matching nothing can still be cleared. #} {% set folder_landing = view and not songs and not q and not letter %} {# The route reports the sort as a display string; the view toggle needs the param back so that switching between flat and folder view keeps the chosen order. #} {% set sort_param = 'date' if sort_order == 'Date' else None %} {% if breadcrumbs %} {% endif %} {% if not folder_landing %} {% include 'partials/singer_field.html' %} {# Filtering is server-side: the page is paginated, so a client-side filter over the ~100 rows in the DOM would silently miss songs on every other page. #}
{# MSG: Button which empties the filter box and shows every song again. #} {% trans %}Clear{% endtrans %}
{# A folder listing only subfolders has no songs for the bar to narrow, so every letter would be a dead end. Everywhere else it renders, scoped to what is on screen -- the letters that would return nothing are greyed rather than dropped, so the strip does not change shape as the user moves between folders. #} {% if not view or letters %}
{% if 'numeric' in letters %} # {% else %} # {% endif %} {# Not named `letter`: the sort links below read the page's own `letter` variable, and shadowing it here would be one Jinja scoping rule away from a bug. #} {% for alpha in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] %} {% if alpha in letters %} {{alpha.upper()}} {% else %} {# A span, not a disabled link: an anchor with no href is still focusable, so a keyboard would tab through two dozen dead stops to reach the list. #} {{alpha.upper()}} {% endif %} {% endfor %}
{% endif %} {% endif %} {% if subfolders %} {# Entering a folder deliberately drops q, letter and page: a folder is a new listing, not a filtered continuation of the one being left. #}
{% for name in subfolders %} {{ name }} {% endfor %}
{% endif %} {# Both toggles sit with the results they describe rather than above the search box, and each shows its options at once so the active one is visible without reading a sentence. Sorting and the view are orthogonal to filtering, so both carry the active query through -- the alpha bar above is the one control that clears it. #}
{% if has_subfolders %} {# MSG: Button which lists every song at once, ignoring the folders they are stored in. #} {% trans %}All songs{% endtrans %} {# MSG: Button which groups the songs by the folder they are stored in. #} {% trans %}Folders{% endtrans %} {% endif %}
{% if not folder_landing %} {# Labels stay on one line: `trans` does not collapse whitespace, so a wrapped label bakes the newline and tabs into the msgid and any reindent breaks it. #} {# MSG: Button which changes how the songs are sorted so they become sorted by name. #} {% trans %}Sort Alphabetically{% endtrans %} {# MSG: Button which changes how the songs are sorted so they become sorted by date. #} {% trans %}Sort by Date{% endtrans %} {% endif %}
{% if not folder_landing %} {# The filter input sits outside this div, so a keystroke swap never takes the caret with it. #}
{% include 'partials/browse_results.html' %}
{% endif %} {% endblock %}