{# Login page, ported from shadcn/ui's login-04 block. The one page that does not extend base.html, and the reason a bare layout exists: base.html wraps a nav built from what the current principal may see, and here there is no principal yet. It still includes admin/theme.html, so signing in does not flash a light page at someone who chose dark. Deliberately absent from the port: the social buttons, "Sign up" and "Forgot your password?" -- the framework has no route behind any of them. #} {% from "admin/components/csrf-field.html" import csrf_field %} {% from "admin/components/ui/locale-switcher.html" import locale_switcher_menu %} {# No hx-* on this page, so the token travels as a hidden field only -- but the meta tag stays for consistency with base.html. #} {{ _("Sign in") }} · {{ _(site_title) }} {% include "admin/theme.html" %} {% if locale_switcher %}
{{ locale_switcher_menu(locale_switcher, base_path, csrf_token) }}
{% endif %}
{# method="post" with no action: the form posts back to the same URL, which carries ?next= through a failed attempt without needing a second hidden field. #}

{{ _("Welcome back") }}

{{ _("Sign in to %(site)s", site=_(site_title)) }}

{# One message for a bad password and for no such user alike -- see core/login.py's LoginBackend on why the backend must not distinguish them either. #} {% if error %} {% endif %} {# Not an error: what logout redirects back with. #} {% if notice %}

{{ notice }}

{% endif %}
{# The submitted value is echoed back so a typo in the password does not cost the identifier as well. type="text", not "email": a plain username must not be rejected by HTML5 validation before it reaches the backend, which is the one that actually knows what identifiers it accepts. #}
{{ csrf_field(csrf_token) }}
{# login-04's photograph column. A framework has no photo to ship, so this is the site's own identity instead -- which is more use to someone who administers several. #}
{% if site_logo_url %} {% endif %} {{ _(site_title) }}