polish(ux): AA-contrast chip inks, 14-tone palette, calendar month auto-scroll
Blind-build polish pass over the recent sales/chips/calendar work: - Chip label contrast: 7 palette inks (terracotta, ochre, rose, seedling, plant, bulb, cutting) sat below WCAG AA on their own fill; darkened (hue preserved) to ≥4.8:1. New category_palette_contrast_test locks it. - Palette expanded 8 → 14 earthy tones (hues spread around the wheel) so family colours rarely collide for a typical 6–10 family inventory, keeping the stable-by-name, cross-screen-consistent scheme. Every new ink meets AA on its fill. - Calendar month strip now actually scrolls the selected month into view (the comment promised it but it was never wired) — late-year months are no longer left off-screen when the screen opens. - Minor: dead code removed from the month chip. dart analyze clean; palette/contrast/calendar/quantity/overflow/inventory suites green.
This commit is contained in:
parent
a476f17cdf
commit
62ed4f79b3
3 changed files with 97 additions and 16 deletions
38
apps/app_seeds/test/ui/category_palette_contrast_test.dart
Normal file
38
apps/app_seeds/test/ui/category_palette_contrast_test.dart
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tane/db/enums.dart';
|
||||
import 'package:tane/ui/category_palette.dart';
|
||||
|
||||
/// Chip labels are drawn in [Swatch.ink] over [Swatch.fill]; that pairing must
|
||||
/// clear WCAG AA for normal text (≥4.5:1), like the rest of the palette
|
||||
/// (see theme_contrast_test.dart). Locks the tuned inks against regressions.
|
||||
void main() {
|
||||
double lin(double c) =>
|
||||
c <= 0.03928 ? c / 12.92 : math.pow((c + 0.055) / 1.055, 2.4).toDouble();
|
||||
double luminance(Color c) =>
|
||||
0.2126 * lin(c.r) + 0.7152 * lin(c.g) + 0.0722 * lin(c.b);
|
||||
double contrast(Color a, Color b) {
|
||||
final la = luminance(a), lb = luminance(b);
|
||||
final hi = math.max(la, lb), lo = math.min(la, lb);
|
||||
return (hi + 0.05) / (lo + 0.05);
|
||||
}
|
||||
|
||||
test('every category swatch label meets AA on its fill', () {
|
||||
// Cover the whole palette by probing many distinct category names.
|
||||
for (var i = 0; i < 60; i++) {
|
||||
final s = categorySwatch('family-$i');
|
||||
expect(contrast(s.ink, s.fill), greaterThanOrEqualTo(4.5),
|
||||
reason: 'category-$i ink on fill');
|
||||
}
|
||||
});
|
||||
|
||||
test('every lot-form swatch label meets AA on its fill', () {
|
||||
for (final type in LotType.values) {
|
||||
final s = lotTypeSwatch(type);
|
||||
expect(contrast(s.ink, s.fill), greaterThanOrEqualTo(4.5),
|
||||
reason: '$type ink on fill');
|
||||
}
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue