feat: режим индикаторов без цветовой кодировки + переустройство /setup
Новая настройка app_settings.indicator_mode (color | accessible), переключается на /setup. В режиме accessible сигналы, которые раньше держались только на цвете, переходят на форму/текст: - качество цены (0-9) — 5-ступенчатый signal-meter вместо градиентной точки/числа; единый модуль web/static/price-quality.js, ветвление по window.QF_INDICATOR_MODE; - вкладка «Ценообразование»: ведущая колонка-meter вместо заливки строк, пометка W вместо амбер-подсветки world-цен, ⚠ вместо красного «загрязнённого» итога. - GET/PUT /api/settings/ui (без рестарта), регистрируется в обоих наборах роутов. /setup переустроен: две колонки одной высоты, кнопка «Вернуться в приложение», исправлен <title>. Документация: bible-local 02/03/04 + decisions/2026-08-31-accessible-indicator-mode.md Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LbRvQgPZpM4SJTaX3iLrXk
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d97ac447ca
commit
681ec15e2b
@@ -0,0 +1,63 @@
|
||||
# Decision: `indicator_mode` — a colour-optional rendering mode for UI signals
|
||||
|
||||
**Date:** 2026-08-31
|
||||
**Status:** active
|
||||
|
||||
## Context
|
||||
|
||||
Several UI signals were encoded by hue alone and unreadable with a colour-vision deficiency:
|
||||
|
||||
- `price_quality` (0–9) as a red→yellow→green gradient — a dot in the configurator search
|
||||
dropdown and inline before `lot_name`, a coloured number in the pricelist "Качество" column,
|
||||
a full-row background tint on the "Ценообразование" tab;
|
||||
- the amber `world`-fallback price cell tint
|
||||
([2026-07-10-world-pricelist-fallback.md](2026-07-10-world-pricelist-fallback.md));
|
||||
- the red "contaminated total" in the pricing footer
|
||||
([2026-07-24-pricing-total-world-share.md](2026-07-24-pricing-total-world-share.md)).
|
||||
|
||||
The bible has no dedicated accessibility contract, but `table-management` §Icon Semantics,
|
||||
`controls-selection` §Buttons, `go-code-style` §Business Logic Placement and `build-version-display`
|
||||
say the same thing: meaning is never carried by one ambiguous channel — back it with
|
||||
shape / number / explicit `title`+`aria-label`, and keep the indicator visually subordinate.
|
||||
|
||||
## Decision
|
||||
|
||||
One per-client preference, **`app_settings.indicator_mode`** = `color` (default) | `accessible`,
|
||||
set on `/setup` ("Настройки") via `GET`/`PUT /api/settings/ui` (`internal/handlers/settings.go`)
|
||||
— no restart. Deliberately named for the concern (how indicators are rendered), not for the
|
||||
current widget, so future colour-only signals attach to the same switch.
|
||||
|
||||
`internal/handlers/web.go` `render()` and `internal/handlers/setup.go` inject the mode for every
|
||||
page; `base.html` publishes it as `window.QF_INDICATOR_MODE`. `web/static/price-quality.js` is
|
||||
still the single source of the price-quality scale and branches on the mode internally, so its
|
||||
call sites do not change.
|
||||
|
||||
In `accessible` mode:
|
||||
|
||||
- `price_quality` renders as a **5-step signal-strength meter** (`priceQualityLevel` =
|
||||
`min(4, floor(score/2))` → `0-1 / 2-3 / 4-5 / 6-7 / 8-9`), five bars in one neutral hue, each
|
||||
instance carrying `title`/`aria-label` = `Качество цены: N/9`. `qualityDotHtml` and
|
||||
`qualityBadgeHtml` return the meter;
|
||||
- `qualityRowStyle` returns `''` — the pricing tab instead shows the meter in a narrow leading
|
||||
column (conditional `<th>` / `colspan` in `index.html`, per-sub-row `<td>`);
|
||||
- the `world`-fallback amber class is dropped for a `W` superscript text marker on the price
|
||||
(text, not a colour class — `applyCustomPrice`'s colour-stripping regex is a non-issue);
|
||||
- `_setPricingTotal` drops `text-red-600` for a leading `⚠` glyph, on the same trigger as the
|
||||
red (`worldShare > 0`). The hover popup — including the "prices for N of M positions" coverage
|
||||
line — is unchanged in both modes; per 2026-07-24 there is still no colour-coded coverage-only
|
||||
signal, and `accessible` mode does not add one.
|
||||
|
||||
`color` mode is byte-for-byte the previous behaviour.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Default unchanged; nothing moves until a user opts in on `/setup`.
|
||||
- `web/static/price-quality.js` stays the only place that knows the 0–9 scale. Any new
|
||||
colour-coded quality/price signal adds a branch there keyed on `isAccessible()`, never a local
|
||||
reimplementation, and its `accessible` form must be shape/text, not another hue.
|
||||
- The pricing-tab tables have a mode-dependent column count (8 / 9). `index.html` guards the
|
||||
`<th>`, the empty-state `colspan`, the `tfoot` "Итого:" `colspan` and the JS row template on
|
||||
`ACCESSIBLE_MODE` / `{{ eq .IndicatorMode "accessible" }}`. CSV export is untouched — it reads
|
||||
`data-*` row attributes, not cell positions.
|
||||
- New routes `GET`/`PUT /api/settings/ui`, registered in both the normal and setup-mode route
|
||||
sets in `cmd/qfs/main.go`. `render()` nil-guards `localDB` for tests.
|
||||
Reference in New Issue
Block a user