Put icons in the login fields and drop their labels
The entrance forms lose their visible field labels and gain an icon inside each field (mail, lock), and allauth's "Forgot your password?" link -- which is the password field's help_text -- is spaced away from the input instead of sitting flush against it. Three things this depends on: - allauth already passes `unlabeled=True` on the entrance forms and already sets a placeholder on every field there, so the visible label was redundant. The label is still emitted sr-only: a placeholder is not a label, and it vanishes as soon as you type. - daisyUI's icon-in-field layout puts the `input` class on the *wrapping label*, so the input itself must carry only `grow` -- hence the optional css override on the daisy filter. `input` on both draws a box inside a box, and the error state belongs on the wrapper for the same reason. - The help text now carries id="<auto_id>_helptext". Django points the input's aria-describedby at exactly that id, so without it the reference dangled and a screen reader never announced the password-reset link. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ from teams.models import Position, Team, TeamMembership
|
||||
from .services.admins import grant_club_admin
|
||||
from .services.platform_admins import PlatformAdminError, is_last_superuser, set_platform_access
|
||||
from .services.statistics import club_statistics, clubs_with_totals, platform_totals
|
||||
from .templatetags.ui import as_alert, daisy
|
||||
from .templatetags.ui import as_alert, daisy, field_icon
|
||||
|
||||
User = get_user_model()
|
||||
Flag = get_waffle_flag_model()
|
||||
@@ -455,3 +455,61 @@ class MessageRenderingTests(ControlPanelTestBase):
|
||||
self.assertContains(response, "alert alert-soft alert-warning")
|
||||
self.assertContains(response, '<div class="font-bold">Careful</div>', html=False)
|
||||
self.assertContains(response, "<svg") # the lucide icon
|
||||
|
||||
|
||||
class FieldRenderingTests(TestCase):
|
||||
def field(self, form_field, name="email", errors=False):
|
||||
class Form(forms.Form):
|
||||
pass
|
||||
|
||||
Form.base_fields[name] = form_field
|
||||
form = Form(data={} if errors else None)
|
||||
if errors:
|
||||
form.full_clean()
|
||||
return form[name]
|
||||
|
||||
def test_known_fields_get_an_icon_and_others_do_not(self):
|
||||
self.assertEqual(field_icon(self.field(forms.EmailField(), "email")), "mail")
|
||||
self.assertEqual(field_icon(self.field(forms.CharField(), "password")), "lock-keyhole")
|
||||
self.assertEqual(field_icon(self.field(forms.CharField(), "note")), "")
|
||||
|
||||
def test_the_default_rendering_styles_the_input_itself(self):
|
||||
self.assertIn('class="input input-bordered w-full"', str(daisy(self.field(forms.CharField()))))
|
||||
|
||||
def test_an_override_replaces_the_daisy_classes(self):
|
||||
# The icon layout puts `input` on the wrapping label, so the input must not
|
||||
# carry it too — that would draw a box inside a box.
|
||||
rendered = str(daisy(self.field(forms.CharField()), "grow"))
|
||||
|
||||
self.assertIn('class="grow"', rendered)
|
||||
self.assertNotIn("input-bordered", rendered)
|
||||
|
||||
def test_an_override_leaves_the_error_state_to_the_wrapper(self):
|
||||
rendered = str(daisy(self.field(forms.CharField(required=True), errors=True), "grow"))
|
||||
|
||||
self.assertNotIn("grow-error", rendered)
|
||||
|
||||
def test_the_default_rendering_marks_errors_on_the_input(self):
|
||||
rendered = str(daisy(self.field(forms.CharField(required=True), errors=True)))
|
||||
|
||||
self.assertIn("input-error", rendered)
|
||||
|
||||
|
||||
class LoginFormRenderingTests(TestCase):
|
||||
def setUp(self):
|
||||
self.response = self.client.get(reverse("account_login"))
|
||||
|
||||
def test_the_fields_carry_an_icon_and_no_visible_label(self):
|
||||
self.assertContains(self.response, 'class="sr-only">Email</span>')
|
||||
self.assertContains(self.response, 'class="sr-only">Password</span>')
|
||||
self.assertNotContains(self.response, '<span class="label-text">Email</span>')
|
||||
self.assertContains(self.response, 'placeholder="Email address"')
|
||||
|
||||
def test_the_checkbox_keeps_its_visible_label(self):
|
||||
self.assertContains(self.response, '<span class="label-text">Remember Me</span>')
|
||||
|
||||
def test_the_password_reset_link_is_spaced_and_addressable(self):
|
||||
# The input's aria-describedby points here; without the id it dangles.
|
||||
self.assertContains(self.response, 'id="id_password_helptext"')
|
||||
self.assertContains(self.response, "mt-3")
|
||||
self.assertContains(self.response, "Forgot your password?")
|
||||
|
||||
Reference in New Issue
Block a user