Все UI-строки приложения переведены и переключаются на лету через
Settings → Язык интерфейса.
== i18n архитектура ==
- src/renderer/src/i18n/dict.ts — плоский словарь ru/en с ~190 ключами,
поддержка интерполяции {var} и плюрализации
- src/renderer/src/i18n/index.ts — useT() React hook + чистые
translate/translateN функции (для ReminderApp вне store context)
- Settings.language: 'ru' | 'en', default 'ru'
- Изменение языка применяется немедленно через Zustand reactive update
== Что переведено ==
- Sidebar nav + slogan + status
- Titlebar window controls (aria-labels)
- Dashboard: hero, 3 stat-карточки (Активных / До следующего /
Трекинг матчей), Paused banner, empty state
- Exercises: hero, секции (активные / выключенные), row meta, empty
- Challenges: hero, formula subtitle, warning, row format
«{stat} × {mult} → {exercise}», empty
- Games: hero, status badges (Live/Ready/Queued/Installed/Not found),
queued/no_user banners, dev panel
- Settings: все секции + новый Language selector
- UpdaterCard: все состояния (checking/available/downloading/
downloaded/error/idle) с интерполяцией версии и MB/s
- ReminderApp: kicker «Время тренировки», reps подпись, snooze label
с динамическими минутами, кнопки done/skip
- Match summary: победа/поражение, плюрализация «N челлендж/-а/-ей»
vs «N challenge/-s»
- Format helpers (formatCountdown, formatInterval) — теперь принимают
Language параметр
== Локалезависимая дата ==
Dashboard hero показывает today в текущей локали:
ru-RU → "воскресенье, 17 мая"
en-US → "Sunday, May 17"
== STAT_LABELS bilingual ==
- shared/types.ts: STAT_LABELS_EN + statLabel(stat, lang) helper
- ChallengeResult получил поле stat?: GameStat (для resolve на стороне
renderer'а с актуальным языком, вместо baked-in label)
- main/games/registry.ts кладёт stat в результат
== Тесты ==
- src/renderer/src/i18n/i18n.test.ts: 10 кейсов
* translate: lookup, fallback, interpolation, multi-var, lang fallback
* translateN: ru plural rules (1/21/101 → one; 2-4 → few; 0/5-20 → many)
и en (1 → one, else → many)
- Всего 33 теста зелёные
== Известное ограничение ==
SAMPLE_EXERCISES (5-6 русских "Приседания / Отжимания / ...") остаются
русскими — это seed данных на первый запуск. Английский юзер сразу
переключит язык и сможет переименовать вручную. Делать seed-per-locale
оверкилл — слишком много кода ради малого.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6 часов было выбрано произвольно как "вежливо для сервера". На
практике слишком долго для backgound-приложения: новый релиз
доезжает до пользователя только через полдня.
Меняем на 1 час — все сравнимые приложения (Discord 30 мин,
Slack 30 мин, VS Code 1 ч) используют похожие интервалы.
Стартовая проверка (5 сек после запуска) остаётся.
Нагрузка минимальна: запрос на latest.yml = 362 байта.
UI текст «Авто-проверка раз в 6 часов» → «раз в час».
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
После того как репозиторий стал публичным, токен в Authorization
header больше не нужен. Убираю __UPDATE_TOKEN__ define из
electron.vite.config.ts и весь связанный код в updater.ts.
Преимущества:
- Никаких секретов в распространяемом .exe
- Билд не требует UPDATE_TOKEN env переменной
- Любой может склонировать и собрать без доп. конфига
== Действие пользователя ==
Если v0.3.5 .exe был скачан кем-то с публичного репо (был доступен
~30 минут до того как мы это поняли) — токен из него можно
извлечь и использовать для записи в репо. Рекомендую ротировать:
1. Gitea → Settings → Applications → удалить старый токен
2. Создать новый, скопировать
3. PowerShell:
[Environment]::SetEnvironmentVariable('GITEA_TOKEN', '<новый>', 'User')
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Эта папка содержит Claude Code workspace-конфиг (skills, agent
definitions, локальные permissions). Уже в .gitignore, но была
залита в Initial commit до того как gitignore обновился.
Перед публикацией репозитория убираем из текущего HEAD. Файлы
остаются на локальном диске (только --cached). История
по-прежнему содержит .claude/ — это не секреты (Anthropic skills
публичны, settings.local.json содержит только permission allowlist),
но для полной чистки можно переписать историю через git filter-repo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Корень проблемы 404: репо приватный, Gitea требует Authorization
header для release assets даже на browser_download_url. Без токена
запрос возвращает 404 (не 401), поэтому electron-updater сообщал
"Cannot find channel latest.yml update info".
Решение — embed read-only токена в build:
- electron.vite.config.ts: vite `define` для __UPDATE_TOKEN__
читает process.env.UPDATE_TOKEN на этапе сборки
- src/main/updater.ts: если __UPDATE_TOKEN__ непустой, выставляет
autoUpdater.requestHeaders = { Authorization: 'token ...' }
- Декларация declare const локально в модуле, vite заменяет литерал
Сборка теперь требует:
$env:UPDATE_TOKEN = '<gitea-token>'; npm run dist
Если переменная не задана — токен пустой, auto-update тихо отключается
(статус 'unsupported' не показывается, просто запросы будут падать).
Альтернатива на будущее (без токена в .exe):
1. Сделать репо публичным в Gitea Settings
2. Или сделать только Releases публичными если в этой версии Gitea
есть такая опция
Тогда токен в коде не нужен.
== Важно для существующих пользователей ==
Установленные v0.2.x / v0.3.0-0.3.4 не могут получить апдейт
автоматически — у них в бинаре старый updater без токена и они
продолжат получать 404. Им нужно скачать v0.3.5 .exe вручную
и переустановить. После 0.3.5 auto-update заработает.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Manrope воспринимался слишком строгим и корпоративным. Замена даёт
больше характера и тёплый "попсовый" feel:
- Body/UI: Manrope → Plus Jakarta Sans (мягкие округлые формы 'a' 'g',
очень распространён в современных трендовых приложениях)
- Display/hero: Fraunces → Bricolage Grotesque (variable шрифт с opsz
axis: 24 для нормальных заголовков, 96 для hero — гротеск с
характерными слегка сжатыми формами и большим контрастом штрихов)
- Mono: JetBrains Mono без изменений
Все hero-заголовки пробампаны до 34→40px и font-bold (700), Bricolage
лучше всего смотрится в полужирном/жирном. Sidebar логотип «Laude»
тоже font-bold.
Также:
- body line-height: 1.45 → 1.5 для лучшей читаемости
- Reminder exercise name: 28→30, semibold→bold
- Match summary title: 24→26, semibold→bold
- Sidebar slogan: 12→13/medium, контраст 45→55
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Включает полный реворк UI в стиле Apple iOS/macOS:
- Geist + Instrument Serif шрифты вместо Rajdhani
- Apple HIG палитра (systemOrange, systemGreen, systemRed, true black dark)
- macOS vibrancy sidebar, iOS grouped lists, UISwitch, action sheets
- Spring анимации, active:scale press feedback
Установщик ведёт себя как install-or-update — обновляет существующую
0.2.x/0.3.0 копию с сохранением настроек.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ветка для нового интерфейса; main с предыдущим Strava-дизайном
не тронут — можно вернуться через checkout main.
== Design system (foundation) ==
- Шрифты: Geist (sans, display) + Geist Mono (HUD числа) +
Instrument Serif (hero titles) — все через Google Fonts. Близки
к SF Pro / SF Mono.
- Палитра: Apple Human Interface Guidelines
* accent: 255 107 53 (Apple Fitness Move orange)
* success: 52 199 89 (systemGreen — для switch)
* destructive: 255 59 48 (systemRed)
* info: 0 122 255 (systemBlue)
* warning: 255 159 10
* Light bg: 242 242 247 (iOS systemGroupedBackground)
* Dark bg: true black 0 0 0 (OLED-friendly), elevation через
28/44/56 grey steps как в iOS Settings
- Утилиты: .vibrancy (macOS Big Sur sidebar), .hairline-b/-t (0.5px
iOS-стиль), .shadow-card (soft layered), .font-display/-serif/-mono-num
== UI primitives ==
- Button: filled / tinted / plain / destructive / success (iOS UIButton);
active:scale-[0.97] press feedback. Старые имена primary/secondary/
ghost/danger/victory маппятся через legacyMap для совместимости.
- Switch: настоящий iOS UISwitch 51x31, spring физика knob, success
цвет on.
- Modal: центрированный sheet с rounded-3xl (22px), backdrop blur,
spring scale-in. Header с font-display, X в circle.
- Card + Row + SectionHeader: iOS grouped list — белая поверхность,
hairline-b dividers между rows, last={true} убирает последний.
== App frame ==
- Sidebar: vibrancy (semi-transparent + backdrop-blur saturate 180%),
font-serif лого, tinted icon-plaques на каждом пункте (как в iOS
Settings), плавный hover. Drawer на mobile со spring slide.
- Titlebar: центрированный title, window controls без glow, hamburger
только на <md.
- App.tsx: AnimatePresence cross-fade между маршрутами.
== Pages ==
- Dashboard: hero с font-serif Large Title + датой. 3-card Hero panel
(Apple Fitness style) с tinted icon squares. ExerciseCard теперь с
progress-ring вокруг иконки + появляющейся "Готово" pill только при
due. Three-dot menu (iOS-style popover).
- Exercises: групированный список iOS, разделение Активные/Выключенные,
chevron-right на каждом row.
- Challenges: тот же групированный паттерн + warning banner если игр
нет, formula preview карточка в редакторе с big number в accent.
- Games: cards в новом стиле, статус-чипы pulse-dot для LIVE, dev
кнопки в pill-стиле.
- Settings: классические iOS Settings секции с ToggleRow и SelectRow
inside Card. UpdaterCard полностью переработан под Cell pattern.
== Reminder window ==
- iOS action sheet: большая иконка в accent-circle сверху, font-serif
название упражнения, гигантское моноширинное число reps. Кнопки
стопкой: primary Готово full-width, потом snooze + skip в grid.
Хоткеи Enter/Space/Esc сохранены.
- Match summary: tone-цветной icon plaque (success/destructive/accent),
ChallengeRow с pill-shaped check button.
== Анимации ==
- Spring физика везде где layout (Switch knob, Modal, Sidebar drawer,
карточки)
- active:scale-[0.97] на всех интерактивных элементах (iOS touch feel)
- Cross-fade между страницами через AnimatePresence
- Никаких glow / pulse-ring — apple style это сдержанность
Verified: typecheck OK, 23 tests pass, build 36.35 KB CSS (на 6 KB
меньше предыдущего HUD-стиля), 1.56 MB JS.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Скрипт догружает уже собранные NSIS-артефакты (.exe, .blockmap,
latest.yml) в существующий Gitea release. Создаёт release если его
нет, удаляет одноимённые активы перед перезаписью.
Используется когда:
- release.ps1 успел запушить тег, но упал на загрузке
- релиз делался руками без артефактов
- нужно перезалить артефакты после пересборки
Большие файлы (>50MB) грузятся через curl.exe, потому что
Invoke-RestMethod в PS 5.1 разрывает соединение на multipart upload
80+MB. Прогресс печатается отдельно для каждого файла.
Использован для загрузки v0.3.0 артефактов.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Релиз новой спортивной палитры и адаптивной вёрстки.
- Strava orange + rose цветовая гамма
- Полная адаптивность: collapsible sidebar, drawer на mobile
- 23 unit-теста, typecheck чистый
- Установщик Exercise-Reminder-Setup-0.3.0.exe собран
Установщик ведёт себя как install-or-update: ставится на чистую
систему, обновляет существующую 0.2.x с сохранением настроек.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Полная автоматизация релизного цикла.
== Auto-update (electron-updater) ==
- src/main/updater.ts — обёртка над autoUpdater с дискриминированным
UpdaterStatus union и broadcast через IPC. autoDownload=false,
пользователь сам жмёт «Скачать». allowDowngrade=false. Проверка
каждые 6 часов, первая через 5с после старта.
- В dev-режиме (app.isPackaged=false) статус сразу становится
'unsupported' с пояснением — никаких exceptions из updater'а.
- build.publish в package.json: provider=generic, url указывает на
Gitea release assets конкретной версии.
- src/main/ipc.ts: 4 новых канала — status/check/download/install.
- src/preload: API window.api.updater* + onUpdaterStatus.
- src/renderer/src/components/UpdaterCard.tsx: HUD-карточка в Settings
с состояниями idle/checking/available/downloading/downloaded/error,
прогресс-бар с скоростью в МБ/с.
== Тесты (vitest) ==
- vitest.config.ts с алиасами @shared / @renderer
- 23 теста, все зелёные:
* format.test.ts — formatCountdown, formatInterval (8 cases)
* vdf.test.ts — parseVdf / stringifyVdf / round-trip (11 cases)
* types.test.ts — DEFAULT_SETTINGS, SAMPLE_EXERCISES sanity (4)
- npm scripts: test (watch), test:run (CI)
== CI/CD (Gitea Actions) ==
- .gitea/workflows/ci.yml — на push/PR: typecheck + тесты + smoke-сборка
- .gitea/workflows/release.yml — на тег v*.*.*: сборка NSIS + Gitea release
== Локальный релизный скрипт ==
- scripts/release.ps1 — один скрипт от бампа версии до публикации
через Gitea API (params: -Bump patch/minor/major, -Version, -DryRun)
- npm run release — обёртка
- RELEASING.md — полная инструкция
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Подготовка к auto-update и тестам.
- electron-updater для in-app апдейтов через generic provider
- vitest для unit-тестов
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Маркируем новый билд установщика после полного UI-редизайна
(phase 1 + phase 2 esports HUD).
Установщик Exercise-Reminder-Setup-0.2.0.exe уже корректно ведёт
себя как install-or-update:
- appId com.anril.exercise-reminder неизменен → NSIS находит
предыдущую инсталляцию 0.1.x и обновляет её
- deleteAppDataOnUninstall=false → настройки и история юзера
сохраняются при апдейте
- perMachine=false → апдейт без прав админа
- differentialPackage=true → готовность к дифф-апдейтам через
electron-updater (если позже подключим)
Сам .exe не коммитится — release/ в .gitignore (бинарь 85 МБ).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Распространили esports-HUD язык на оставшиеся экраны и общие UI:
- Modal: neon border accent/25 с двойным glow (cyan + violet),
gradient-divider, gradient-stripe слева от заголовка, defeat hover
на закрытие
- Switch: bg-gradient-brand с shadow-glow в on-состоянии
- Exercises: hero с gradient-text, статистика в моноширинном шрифте
(active count, total reps за цикл), HUD-список с анимированным
появлением, hover-row с accent tint
- Games: game cards с gradient orb-иконкой + glow на интегрированных,
shadow-glow-victory + анимированная LIVE точка для активной
интеграции, новые status badges (LIVE / READY / QUEUED / INSTALLED /
NOT FOUND) в display-шрифте, ошибки в защитных цветах (xp/defeat)
- Challenges: hero + formula-row "stat × N → reps" в моноширинном
шрифте, gradient-preview карточка в редакторе с большим итоговым
числом в text-gradient-brand
- Settings: hero, секции с иконкой в accent-плашке, заголовки секций
в display-шрифте uppercase tracking-wide
- ExerciseEditor: preview-карточка с gradient-orb иконкой в шапке
модала, моноширинные input для чисел, scale-up на выбранной иконке
Все правки используют существующие токены из phase 1 — никаких новых
CSS-переменных или конфигов.
Откат phase 2 один: git revert HEAD
Откат до начала редизайна: git reset --hard 688a86b
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Сменили визуальную ДНК на dark-first гейминг-эстетику: cyan→violet
неоновая палитра, спортивный display-шрифт Rajdhani, моноширинный
HUD для всех счётчиков, градиентные CTA с glow.
Дизайн-система (globals.css + tailwind.config.js):
- Brand-токены accent (cyan), accent-2 (violet), victory (lime),
defeat (rose), xp (amber); --bg-deep слой
- Утилиты .neon-border (анимированный обводный градиент),
.hud-pulse, .hud-scanlines, .dot-grid, .text-gradient-brand,
.bg-gradient-brand/-victory/-defeat
- Радиальные градиенты на body (cyan/violet glow по углам)
- Шрифты Rajdhani (display) и JetBrains Mono подключены через CDN
Компоненты:
- Sidebar: gradient-логотип, активный пункт с вертикальной gradient-
полосой и shadow-glow, статус-чип GSI tracking
- Titlebar: glass + scanlines, моноширинный лейбл, defeat hover на X
- Button: primary = bg-gradient-brand + shadow-glow; новый variant
victory (lime-gradient)
- ExerciseCard: SVG cooldown-ring как у способностей в MOBA,
градиентный stroke с drop-shadow, .neon-border на due, hover lift
- Dashboard: hero с gradient-text заголовком, HUD-полоса из 4 stat-
карточек (Cooldown / Active / Avg / Game tracking LIVE/OFF)
- ReminderApp: вращающийся conic-gradient вокруг иконки, HUD-блок
reps в моноширинном шрифте, кнопки с подписями хоткеев,
Match summary с heroGradient по результату (victory/defeat/brand)
ThemeProvider больше не перезаписывает --accent системным —
у laude теперь стабильная brand-идентичность.
Бонус: хоткеи на reminder-окне (Enter=done, Space=snooze, Esc=skip).
Откат: git revert HEAD или git reset --hard 688a86b
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>