Files
study-bible-project/src/components/reader/readerSelectionColors.test.js
T
nmemmertandClaude Sonnet 5.5 a0971eab29
Build and Push Docker Image / build-and-push (push) Failing after 19s
Reader: visible text selection in every theme; highlights follow across translations
Selection
- Selected text uses a per-theme colour (it was nearly invisible on Dark)
- The colour picker also appears on touch screens after dragging the selection
  handles, and sits below the selection there so the system menu doesn't cover it

Highlights
- Each highlight remembers its translation and whether it covers the whole verse
- In another translation the same words are found again (ignoring case and
  punctuation); whole-verse highlights cover the whole verse; when the wording
  differs, the verse gets a small colour dot instead of marking the wrong words
- Older highlights are checked against their saved words instead of trusted
- Server keeps the new fields

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 09:55:09 -04:00

24 lines
1.3 KiB
JavaScript

import { test, expect } from 'vitest';
import { READER_THEMES } from './readerThemes.js';
// Contrast of two #rrggbb colours (WCAG ratio), used to make sure selected text can be seen on every theme.
const lum = (hex) => {
const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255).map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4));
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
};
const mix = (bg, rgba) => {
const [r, g, b, a] = rgba.match(/[\d.]+/g).map(Number);
return `#${[r, g, b].map((c, i) => Math.round(c * a + parseInt(bg.slice(1 + i * 2, 3 + i * 2), 16) * (1 - a)).toString(16).padStart(2, '0')).join('')}`;
};
const ratio = (a, b) => { const [x, y] = [lum(a), lum(b)].sort((p, q) => q - p); return (x + 0.05) / (y + 0.05); };
test('every theme sets a selection colour that is different from the page and keeps text readable', () => {
for (const [id, theme] of Object.entries(READER_THEMES)) {
const v = theme.vars;
expect(v['--r-sel'], id).toBeTruthy();
const selected = mix(v['--r-bg'], v['--r-sel']);
expect(ratio(selected, v['--r-bg']), `${id}: selection stands out from the page`).toBeGreaterThan(1.25);
expect(ratio(selected, v['--r-text']), `${id}: text stays readable on the selection`).toBeGreaterThan(4);
}
});