Fix mismatched fallback text colour on the initials badge/button
The initials badge and reset button hardcoded two independent fallback literals -- a background (#ec4899 / #0ea5e9) and a text colour (#ffffff) -- that were only ever chosen together for a club's own colour via Club._content_color_for. #ffffff on #ec4899 or #0ea5e9 actually contrasts worse than black by the same WCAG formula the app already uses elsewhere (verified: 6.4:1 vs 3.3:1, and 7.6:1 vs 2.8:1). Added a contrast_color filter so the text colour is always derived from whatever background hex is actually in play -- real club colour or fallback alike -- instead of a second, independently guessed literal that can silently drift out of sync with the first. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,9 +9,27 @@ is relative.
|
||||
|
||||
from django import template
|
||||
|
||||
from club.models import Club
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def contrast_color(hex_color):
|
||||
"""Black or white, whichever reads on ``hex_color`` -- for a literal
|
||||
fallback background (e.g. ``club.secondary_color|default:"#ec4899"``)
|
||||
rather than a club's own colour, which already has a matching
|
||||
``primary_content_color``/``secondary_content_color`` computed for it.
|
||||
|
||||
Chaining this onto the *same* expression used for the background --
|
||||
``club.secondary_color|default:"#ec4899"|contrast_color`` -- rather than
|
||||
hardcoding a second, independently-guessed text colour is what keeps the
|
||||
two from drifting apart: a pale fallback and a dark one both get the
|
||||
contrast Club._content_color_for would compute for them either way.
|
||||
"""
|
||||
return Club._content_color_for(hex_color)
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def absolute_media_url(context, file_field):
|
||||
"""An absolute URL for ``file_field`` (e.g. ``club.logo``), for use in an
|
||||
|
||||
@@ -1258,6 +1258,17 @@ class ClubBrandingModelTests(TestCase):
|
||||
def test_no_colour_means_no_contrast_colour(self):
|
||||
self.assertEqual(Club(primary_color="").primary_content_color, "")
|
||||
|
||||
def test_contrast_color_filter_matches_the_same_algorithm(self):
|
||||
# HTML emails apply this to a literal fallback background (e.g.
|
||||
# club.secondary_color|default:"#ec4899") rather than a club's own
|
||||
# colour, so it can't be exercised through primary_content_color --
|
||||
# but it must still agree with it for a colour a club actually set.
|
||||
from club.templatetags.club_email import contrast_color
|
||||
|
||||
self.assertEqual(contrast_color("#ec4899"), Club(secondary_color="#ec4899").secondary_content_color)
|
||||
self.assertEqual(contrast_color("#fef08a"), "#000000")
|
||||
self.assertEqual(contrast_color("#1e40af"), "#ffffff")
|
||||
|
||||
def test_a_colour_must_be_a_hex_value(self):
|
||||
club = Club(name="Ajax United", primary_color="blue")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user