fix(P1): delete-confirm, daily-goal closed UI, meeting indicator, modal-confirm

P1 #4 — ConfirmModal (новый src/renderer/src/components/ui/ConfirmModal.tsx)
    с iOS-стилем + focus-trap (через Modal). Delete упражнения в Dashboard
    теперь спрашивает «Удалить упражнение?» с destructive-кнопкой.

P1 #5 — Daily goal closed UI. ExerciseCard принимает doneToday prop
    и при `done >= dailyGoal` показывает «Цель закрыта · 100/100»
    вместо запутанного «25ч 13м» countdown'а. Цвет — success-зелёный.

P1 #6 — Meeting auto-pause indicator. Новый IPC.getMeetingActive +
    evtMeetingChanged event. meeting-detect broadcast'ит изменения
    состояния. Dashboard показывает info-баннер «Не дёргаем — ты на
    встрече» когда meetingAutoPause включён и хотя бы один meeting
    процесс запущен.

P1 #7 — Native window.confirm() заменён на ConfirmModal в Settings
    DataCard для restore-операции. Теперь iOS-style с destructive
    confirm-кнопкой и focus-trap'ом.

Заодно P2 #8: Brain-иконка-badge на ExerciseCard для adaptive
    упражнений — пользователь видит почему «Next» не строго равен
    intervalMinutes.
P2 #12: dailyReps/dailyRepsRange/totalDoneReps/repsDoneTodayForExercise
    используют entry.reps как fallback — heatmap не теряет данные
    после удаления упражнения.
This commit is contained in:
AnRil
2026-05-22 15:06:25 +07:00
parent 17df87b3aa
commit 9c989612fe
10 changed files with 254 additions and 15 deletions

View File

@@ -48,6 +48,8 @@ const api = {
getOsTheme: (): Promise<'light' | 'dark'> =>
ipcRenderer.invoke(IPC.getOsTheme),
getAppVersion: (): Promise<string> => ipcRenderer.invoke(IPC.getAppVersion),
getMeetingActive: (): Promise<boolean> =>
ipcRenderer.invoke(IPC.getMeetingActive),
pauseAll: (): Promise<void> => ipcRenderer.invoke(IPC.pauseAll),
resumeAll: (): Promise<void> => ipcRenderer.invoke(IPC.resumeAll),
@@ -137,7 +139,9 @@ const api = {
onUpdaterStatus: (h: Handler<UpdaterStatus>): Unsub =>
on(IPC.evtUpdaterStatus, h),
onMaximizeChanged: (h: Handler<boolean>): Unsub =>
on(IPC.evtMaximizeChanged, h)
on(IPC.evtMaximizeChanged, h),
onMeetingChanged: (h: Handler<boolean>): Unsub =>
on(IPC.evtMeetingChanged, h)
}
contextBridge.exposeInMainWorld('api', api)