Such-Oberfläche (Next.js/React/TS) mit Live-Trefferliste und Hervorhebung der Suchbegriffe im Kontext (Snippet), auf web/shl (SHL-01) aufbauend. - app/api/search/route.ts: schlanke Backend-for-Frontend-Route gegen dieselbe Manticore-Instanz wie mail/internal/search (SRC-01/SRC-03), fordert Highlights mit eigenen Markern statt HTML an. - lib/highlight.ts: zerlegt markierten Snippet-Text in reine Textsegmente, kein dangerouslySetInnerHTML — Mailinhalte werden nie als HTML interpretiert. - app/page.tsx: Sucheingabe, Trefferliste mit <mark>-Hervorhebung, verständlicher Hinweis bei leerem Ergebnis. - app/mail/[messageId]/page.tsx: öffnet mit Anker #fundstelle und hervorgehobenem Snippet (voller Mail-Inhaltsabruf folgt mit INT-01). - lib/contrast.ts: reale WCAG-2.1-Kontrastberechnung. Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-04-PRUEFPROTOKOLL.md): 1. Manueller Test gegen echten next start + live Manticore auf 192.168.1.131: Hervorhebung real bestätigt. 2. lib/highlightColors.test.ts: echte WCAG-Berechnung, Hell 14,29:1, Dunkel 6,43:1 (>= 4.5:1 AA). 3. Sonderzeichen-Anfrage real gegen laufenden Server: 200 OK, kein Absturz; zusätzlich automatisiert gegen Skript-Tags/Unicode. Kein Umbau: mail/internal/*, web/shl, web/retention-admin unverändert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
26 lines
1.0 KiB
TypeScript
26 lines
1.0 KiB
TypeScript
// SRC-04 Prüfung 2 (Barrierefreiheits-Kontrastprüfung der Hervorhebung):
|
|
// echte WCAG-2.1-Kontrastberechnung statt einer rein manuellen Behauptung.
|
|
|
|
function srgbToLinear(channel: number): number {
|
|
const c = channel / 255;
|
|
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
}
|
|
|
|
function relativeLuminance(hex: string): number {
|
|
const clean = hex.replace("#", "");
|
|
const r = parseInt(clean.slice(0, 2), 16);
|
|
const g = parseInt(clean.slice(2, 4), 16);
|
|
const b = parseInt(clean.slice(4, 6), 16);
|
|
return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
|
|
}
|
|
|
|
// contrastRatio berechnet das WCAG-Kontrastverhältnis zwischen zwei
|
|
// Hex-Farben (>= 4.5:1 gilt als AA-konform für Fließtext).
|
|
export function contrastRatio(colorA: string, colorB: string): number {
|
|
const lumA = relativeLuminance(colorA);
|
|
const lumB = relativeLuminance(colorB);
|
|
const lighter = Math.max(lumA, lumB);
|
|
const darker = Math.min(lumA, lumB);
|
|
return (lighter + 0.05) / (darker + 0.05);
|
|
}
|