From a41dce511b52ce1e7459e61f6e44dc063d5889b9 Mon Sep 17 00:00:00 2001 From: AnRil Date: Fri, 22 May 2026 01:13:01 +0700 Subject: [PATCH] =?UTF-8?q?chore:=20sprint=20A=20=E2=80=94=20=D0=BC=D0=B5?= =?UTF-8?q?=D0=BB=D0=BA=D0=B0=D1=8F=20=D0=BF=D0=BE=D0=BB=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #15 a11y: синхронизируется с settings.language через ThemeProvider — screen-readers больше не читают EN-текст с русским акцентом и наоборот. #14 dev:simulateMatchEnd channel вынесен в IPC enum (IPC.devSimulateMatchEnd) — main/preload не разойдутся в hardcoded строках. #34 ChallengeEditor: multiplier клампится к [0.5, 1000] (max="1000", Math.min(1000, ...)). Совпадает с validate.ts — раньше save с 9999 молча отклонялся IPC, теперь UI не даёт ввести. #28 package.json: добавлен `test:coverage` script. --- package.json | 1 + src/main/ipc.ts | 2 +- src/preload/index.ts | 2 +- src/renderer/src/pages/Challenges.tsx | 9 ++++++++- src/renderer/src/providers/ThemeProvider.tsx | 10 ++++++++++ src/shared/ipc.ts | 4 ++++ 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 91f7dec..041f343 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "typecheck": "npm run typecheck:node && npm run typecheck:web", "test": "vitest", "test:run": "vitest run", + "test:coverage": "vitest run --coverage", "format": "prettier --write \"src/**/*.{ts,tsx,css}\" \"*.{json,md}\" \".github/**/*.yml\"", "format:check": "prettier --check \"src/**/*.{ts,tsx,css}\" \"*.{json,md}\"", "lint": "eslint src --ext .ts,.tsx --max-warnings 0", diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 99fbfc1..7fb3190 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -275,7 +275,7 @@ export function registerIpc(): void { // otherwise fabricate arbitrary match-end events at will. if (!app.isPackaged) { ipcMain.handle( - 'dev:simulateMatchEnd', + IPC.devSimulateMatchEnd, (_e, id: GameId, stats: Record) => { simulateMatchEnd(id, stats) } diff --git a/src/preload/index.ts b/src/preload/index.ts index 7e13505..1c4f95d 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -96,7 +96,7 @@ const api = { id: GameId, stats: Record ): Promise => - ipcRenderer.invoke('dev:simulateMatchEnd', id, stats) + ipcRenderer.invoke(IPC.devSimulateMatchEnd, id, stats) } : {}), diff --git a/src/renderer/src/pages/Challenges.tsx b/src/renderer/src/pages/Challenges.tsx index f544198..c4c5acb 100644 --- a/src/renderer/src/pages/Challenges.tsx +++ b/src/renderer/src/pages/Challenges.tsx @@ -264,11 +264,18 @@ function ChallengeEditor({ type="number" step="0.5" min="0.5" + max="1000" value={draft.multiplier} onChange={(e) => setDraft({ ...draft, - multiplier: Math.max(0.5, Number(e.target.value) || 1) + // Клампим к диапазону [0.5, 1000] — совпадает с validate.ts + // (multiplier ∈ [0, 1000]). Без max=1000 пользователь мог + // ввести 9999 и save молча отклонялся IPC-валидатором. + multiplier: Math.max( + 0.5, + Math.min(1000, Number(e.target.value) || 1) + ) }) } className="ios-input font-mono-num" diff --git a/src/renderer/src/providers/ThemeProvider.tsx b/src/renderer/src/providers/ThemeProvider.tsx index 8c90a29..e130439 100644 --- a/src/renderer/src/providers/ThemeProvider.tsx +++ b/src/renderer/src/providers/ThemeProvider.tsx @@ -25,5 +25,15 @@ export function ThemeProvider({ else document.documentElement.classList.remove('dark') }, [settings?.theme, osTheme]) + // Синхронизируем с языком приложения. Без этого screen-readers + // продолжают читать английский текст как кириллицу (или ломаются) при + // переключении на EN, и наоборот — это a11y-баг. + useEffect(() => { + const lang = settings?.language ?? 'ru' + if (document.documentElement.lang !== lang) { + document.documentElement.lang = lang + } + }, [settings?.language]) + return <>{children} } diff --git a/src/shared/ipc.ts b/src/shared/ipc.ts index be62ee5..434bf2e 100644 --- a/src/shared/ipc.ts +++ b/src/shared/ipc.ts @@ -38,6 +38,10 @@ export const IPC = { markChallengeDone: 'challenge:markDone', closeMatchSummary: 'matchSummary:close', + // Dev-only IPC (handler ungated в prod, см. ipc.ts). Держим в enum чтобы + // main/preload/renderer не разошлись в hardcoded-строках. + devSimulateMatchEnd: 'dev:simulateMatchEnd', + // Auto-updater updaterStatus: 'updater:status', updaterCheck: 'updater:check',