diff --git a/save_results.py b/save_results.py index f4fba2f..da04478 100644 --- a/save_results.py +++ b/save_results.py @@ -186,23 +186,17 @@ def _highlight_context_html(context: str, terms: Iterable[str]) -> str: if not terms_list: return html.escape(raw) - # Paleta de cores para cada termo (cores distintas e acessíveis) + # Soft pastel palette (light, readable; distinct per term). Dark text is applied + # via the .highlight CSS class so these backgrounds stay legible in both themes. color_palette = [ - "#fff59d", # Pale yellow - "#ffcc80", # Orange - "#f48fb1", # Pink - "#90caf9", # Light blue - "#a5d6a7", # Light green - "#ce93d8", # Light purple - "#ffab91", # Light red-orange - "#b0bec5", # Light blue-gray - "#ffe082", # Amber - "#c5e1a5", # Light lime - "#b39ddb", # Light indigo - "#ef9a9a", # Light red - "#81c784", # Green - "#64b5f6", # Blue - "#ffb74d", # Deep orange + "#fff3b0", # pale yellow + "#d8f3dc", # pale green + "#dbeafe", # pale blue + "#fde2e4", # pale pink + "#f3e8ff", # pale lavender + "#ffe5d9", # pale peach + "#e0f2fe", # pale cyan + "#fef9c3", # light cream ] # Mapear cada termo para uma cor @@ -513,12 +507,12 @@ def save_results( *{box-sizing:border-box} :root{ --bg:#ffffff; --panel:#f7f7f9; --text:#111827; --muted:#58606b; - --border:#e5e7eb; --accent:#16a34a; --hi:#fff59d; + --border:#e5e7eb; --accent:#16a34a; --hi:#fff3b0; --hi-text:#111827; } @media (prefers-color-scheme: dark){ :root{ --bg:#0b0c10; --panel:#111827; --text:#e5e7eb; --muted:#9aa4b2; - --border:#2a2f3a; --accent:#22c55e; --hi:#4b5563; + --border:#2a2f3a; --accent:#22c55e; --hi:#fef9c3; --hi-text:#111827; } } html,body{height:100%} @@ -552,8 +546,9 @@ def save_results( } .highlight{ - padding:0 2px; border-radius:3px; font-weight:600; - text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 2px; + padding:0 2px; border-radius:3px; + color:var(--hi-text); /* dark text keeps pastels readable */ + border-bottom:1px solid rgba(0,0,0,0.15); /* subtle, not aggressive */ } /* Cor padrão (fallback) - será sobrescrita por inline styles quando especificado */ .highlight:not([style*="background-color"]) { diff --git a/tests/test_html_highlight.py b/tests/test_html_highlight.py new file mode 100644 index 0000000..e9ca490 --- /dev/null +++ b/tests/test_html_highlight.py @@ -0,0 +1,64 @@ +"""Tests for the HTML search-term highlight styling (soft pastel palette). + +These verify presentation only: markup is still produced, term text is preserved, +and the colours come from the soft pastel palette (no saturated legacy colours). +They do not touch match-finding, counts, or ranking. +""" + +from __future__ import annotations + +import re +import sys +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +import save_results # noqa: E402 + +# Soft pastel palette (must match save_results._highlight_context_html). +PASTEL = { + "#fff3b0", "#d8f3dc", "#dbeafe", "#fde2e4", + "#f3e8ff", "#ffe5d9", "#e0f2fe", "#fef9c3", +} +# Saturated colours that must no longer appear anywhere in the output styling. +LEGACY_SATURATED = { + "#fff59d", "#ffcc80", "#f48fb1", "#90caf9", "#a5d6a7", "#ce93d8", + "#ffab91", "#b0bec5", "#ffe082", "#c5e1a5", "#b39ddb", "#ef9a9a", + "#81c784", "#64b5f6", "#ffb74d", +} + +_HEX = re.compile(r"background-color:\s*(#[0-9a-fA-F]{6})") + + +class TestHtmlHighlight(unittest.TestCase): + def test_highlight_markup_present_and_term_preserved(self): + out = save_results._highlight_context_html("the quick brown fox", ["quick"]) + self.assertIn('class="highlight"', out) + # The matched term text is preserved verbatim. + self.assertIn("quick", out) + self.assertIn("brown fox", out) # non-matched text intact + + def test_highlight_colours_are_soft_pastels(self): + out = save_results._highlight_context_html("alpha beta gamma", ["beta"]) + colours = set(m.lower() for m in _HEX.findall(out)) + self.assertTrue(colours, "expected at least one highlight background colour") + self.assertTrue(colours <= PASTEL, f"non-pastel colours used: {colours - PASTEL}") + self.assertFalse(colours & LEGACY_SATURATED, "legacy saturated colour present") + + def test_multiple_terms_keep_distinct_colours(self): + out = save_results._highlight_context_html("one two three four", ["one", "two"]) + colours = [c.lower() for c in _HEX.findall(out)] + self.assertGreaterEqual(len(set(colours)), 2, "terms should be visually distinct") + self.assertTrue(set(colours) <= PASTEL) + + def test_no_legacy_saturated_colours_in_source(self): + src = (ROOT / "save_results.py").read_text(encoding="utf-8") + lower = src.lower() + for colour in LEGACY_SATURATED: + self.assertNotIn(colour, lower, f"legacy saturated colour still in source: {colour}") + + +if __name__ == "__main__": + unittest.main()