+
+ {
+ const v = e.target.value
+ if (v === '') setDraft({ ...draft, dailyGoal: undefined })
+ else
+ setDraft({
+ ...draft,
+ dailyGoal: Math.max(1, Number(v) || 1)
+ })
+ }}
+ className="ios-input font-mono-num flex-1"
+ />
+ {draft.dailyGoal !== undefined && (
+
+ )}
+
+
+ {t('editor.field.daily_goal.hint')}
+
+
+
{ICON_CHOICES.map((name) => (
diff --git a/src/renderer/src/i18n/dict.ts b/src/renderer/src/i18n/dict.ts
index cd35dc3..d279747 100644
--- a/src/renderer/src/i18n/dict.ts
+++ b/src/renderer/src/i18n/dict.ts
@@ -250,6 +250,11 @@ export const ru: Dict = {
'category.eyes.cta': 'Дай глазам отдохнуть',
'category.posture.cta': 'Проверь осанку',
'editor.field.category': 'Категория',
+ 'editor.field.daily_goal': 'Дневная цель',
+ 'editor.field.daily_goal.placeholder': 'без ограничения',
+ 'editor.field.daily_goal.clear': 'Снять',
+ 'editor.field.daily_goal.hint':
+ 'Когда наберёшь столько повторений за день, напоминания этого упражнения умолкнут до завтра.',
// Reminder window
'reminder.kicker': 'Время тренировки',
@@ -547,6 +552,11 @@ export const en: Dict = {
'category.eyes.cta': 'Rest your eyes',
'category.posture.cta': 'Check your posture',
'editor.field.category': 'Category',
+ 'editor.field.daily_goal': 'Daily goal',
+ 'editor.field.daily_goal.placeholder': 'no limit',
+ 'editor.field.daily_goal.clear': 'Clear',
+ 'editor.field.daily_goal.hint':
+ 'Once you hit this many reps in a day, this reminder goes quiet until tomorrow.',
// Reminder window
'reminder.kicker': 'Workout time',
diff --git a/src/renderer/src/pages/Dashboard.tsx b/src/renderer/src/pages/Dashboard.tsx
index e3ece5a..b981e8a 100644
--- a/src/renderer/src/pages/Dashboard.tsx
+++ b/src/renderer/src/pages/Dashboard.tsx
@@ -74,6 +74,7 @@ export default function Dashboard(): JSX.Element {
intervalMinutes: number
enabled: boolean
category: import('@shared/types').ReminderCategory
+ dailyGoal?: number
}): Promise {
if (editing) await window.api.updateExercise(editing.id, draft)
else await window.api.addExercise(draft)
diff --git a/src/shared/types.ts b/src/shared/types.ts
index 8852ade..a14c3d0 100644
--- a/src/shared/types.ts
+++ b/src/shared/types.ts
@@ -26,6 +26,14 @@ export type Exercise = {
lastDoneAt?: number
/** Default 'exercise' если undefined — обратная совместимость. */
category?: ReminderCategory
+ /**
+ * Опциональная дневная цель в reps. Если задана, scheduler перестаёт
+ * fire'ить упражнение в течение дня, когда total reps за сегодня
+ * (учитывая actualReps в истории) достигают `dailyGoal`. Это «soft cap»
+ * поверх обычного interval'а: не меняет схему таймера, просто блокирует
+ * fires когда цель закрыта. Завтра счётчик обнуляется (по local day).
+ */
+ dailyGoal?: number
}
export type NotificationMode = 'toast' | 'modal' | 'both'