fix(web): restore CutList brand contrast
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
.brand-mark i { transform: rotate(8deg); }
|
||||
.navbar-brand { color: #f7f3eb; font-family: Georgia, 'Times New Roman', serif; font-size: 1.45rem; font-weight: 700; letter-spacing: -.06em; line-height: .9; text-decoration: none; }
|
||||
.navbar-brand .brand-cut { color: #f26b38; }
|
||||
.navbar-brand .brand-list { color: #fffaf0; }
|
||||
.navbar-brand .brand-list { color: #20231f; }
|
||||
.navbar-brand small { color: #8f968d; display: block; font-family: Arial, sans-serif; font-size: .48rem; font-weight: 700; letter-spacing: .14em; margin-top: .45rem; }
|
||||
.nav-section-label { color: #737a73; font-size: .62rem; font-weight: 700; letter-spacing: .13em; margin: 1.35rem 1.5rem .5rem; text-transform: uppercase; }
|
||||
.nav-item { padding: .1rem .75rem; }
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
"""Regression checks for the CutList navigation brand on its light header."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
NAV_MENU = REPO_ROOT / "CutList.Web/Components/Layout/NavMenu.razor"
|
||||
NAV_MENU_CSS = REPO_ROOT / "CutList.Web/Components/Layout/NavMenu.razor.css"
|
||||
APP_CSS = REPO_ROOT / "CutList.Web/wwwroot/css/app.css"
|
||||
|
||||
|
||||
def selector_color(css: str, selector: str) -> str:
|
||||
match = re.search(rf"{re.escape(selector)}\s*\{{([^}}]*)\}}", css)
|
||||
if match is None:
|
||||
raise AssertionError(f"Missing CSS selector: {selector}")
|
||||
|
||||
color = re.search(r"\bcolor:\s*(#[0-9a-fA-F]{6})", match.group(1))
|
||||
if color is None:
|
||||
raise AssertionError(f"Missing hex color for selector: {selector}")
|
||||
return color.group(1)
|
||||
|
||||
|
||||
def contrast_ratio(foreground: str, background: str) -> float:
|
||||
def luminance(color: str) -> float:
|
||||
channels = [int(color[index:index + 2], 16) / 255 for index in (1, 3, 5)]
|
||||
linear = [value / 12.92 if value <= 0.04045 else ((value + 0.055) / 1.055) ** 2.4 for value in channels]
|
||||
return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2]
|
||||
|
||||
lighter, darker = sorted((luminance(foreground), luminance(background)), reverse=True)
|
||||
return (lighter + 0.05) / (darker + 0.05)
|
||||
|
||||
|
||||
class NavMenuBrandContrastTests(unittest.TestCase):
|
||||
def test_list_word_has_accessible_contrast_against_light_top_row(self) -> None:
|
||||
list_color = selector_color(NAV_MENU_CSS.read_text(), ".navbar-brand .brand-list")
|
||||
top_row_color = selector_color(APP_CSS.read_text(), ".top-row")
|
||||
|
||||
self.assertGreaterEqual(contrast_ratio(list_color, top_row_color), 4.5)
|
||||
|
||||
def test_brand_keeps_cut_and_list_as_adjacent_words(self) -> None:
|
||||
markup = NAV_MENU.read_text()
|
||||
self.assertIn('<span class="brand-cut">Cut</span><span class="brand-list">List</span>', markup)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user