From 4e2d978eb5fc9457d5b913bc10faf1266e6dcda4 Mon Sep 17 00:00:00 2001
From: Solstice <solstice@local>
Date: Tue, 9 Jun 2026 01:02:30 -0700
Subject: chore: final polish and preparation for release

---
 src/components/SettingsPanel.tsx | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

(limited to 'src/components/SettingsPanel.tsx')

diff --git a/src/components/SettingsPanel.tsx b/src/components/SettingsPanel.tsx
index 0d3cbf9..71bc7b8 100644
--- a/src/components/SettingsPanel.tsx
+++ b/src/components/SettingsPanel.tsx
@@ -1,6 +1,8 @@
 import { useState, useEffect } from 'react';
 import { useSettingsStore, Settings } from '../store/settingsStore';
 
+const clampValue = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));
+
 interface SettingsPanelProps {
   open: boolean;
   onClose: () => void;
@@ -22,21 +24,31 @@ export function SettingsPanel({ open, onClose }: SettingsPanelProps) {
 
   useEffect(() => {
     if (settings) {
-      setWorkMins(Math.round(settings.work_duration_secs / 60));
-      setShortBreakMins(Math.round(settings.short_break_secs / 60));
-      setLongBreakMins(Math.round(settings.long_break_secs / 60));
-      setSessionsBeforeLong(settings.sessions_before_long_break);
+      setWorkMins(clampValue(Math.round(settings.work_duration_secs / 60), 1, 120));
+      setShortBreakMins(clampValue(Math.round(settings.short_break_secs / 60), 1, 60));
+      setLongBreakMins(clampValue(Math.round(settings.long_break_secs / 60), 1, 60));
+      setSessionsBeforeLong(clampValue(settings.sessions_before_long_break, 1, 10));
     }
   }, [settings]);
 
   if (!open) return null;
 
   const handleSave = async () => {
+    const nextWorkMins = clampValue(workMins, 1, 120);
+    const nextShortBreakMins = clampValue(shortBreakMins, 1, 60);
+    const nextLongBreakMins = clampValue(longBreakMins, 1, 60);
+    const nextSessionsBeforeLong = clampValue(sessionsBeforeLong, 1, 10);
+
+    setWorkMins(nextWorkMins);
+    setShortBreakMins(nextShortBreakMins);
+    setLongBreakMins(nextLongBreakMins);
+    setSessionsBeforeLong(nextSessionsBeforeLong);
+
     const s: Settings = {
-      work_duration_secs: workMins * 60,
-      short_break_secs: shortBreakMins * 60,
-      long_break_secs: longBreakMins * 60,
-      sessions_before_long_break: sessionsBeforeLong,
+      work_duration_secs: nextWorkMins * 60,
+      short_break_secs: nextShortBreakMins * 60,
+      long_break_secs: nextLongBreakMins * 60,
+      sessions_before_long_break: nextSessionsBeforeLong,
     };
     await updateSettings(s);
     onClose();
@@ -64,7 +76,9 @@ export function SettingsPanel({ open, onClose }: SettingsPanelProps) {
           borderRadius: 'var(--r-3)',
           boxShadow: 'var(--shadow-3)',
           padding: '32px',
-          width: '360px',
+          width: 'min(360px, calc(100vw - 32px))',
+          maxHeight: 'calc(100vh - 32px)',
+          overflowY: 'auto',
           display: 'flex',
           flexDirection: 'column',
           gap: '24px',
@@ -109,6 +123,10 @@ export function SettingsPanel({ open, onClose }: SettingsPanelProps) {
           />
         </div>
 
+        <span style={{ fontFamily: 'var(--font-sans)', fontSize: '12px', color: 'var(--fg-4)', lineHeight: 1.4 }}>
+          Values are clamped to sensible minimums before saving.
+        </span>
+
         <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end' }}>
           <button
             onClick={onClose}
@@ -203,7 +221,7 @@ function NumberField({ label, unit, value, min, max, onChange }: NumberFieldProp
           min={min}
           max={max}
           value={value}
-          onChange={(e) => onChange(Math.min(max, Math.max(min, parseInt(e.target.value) || min)))}
+          onChange={(e) => onChange(clampValue(parseInt(e.target.value, 10) || min, min, max))}
           style={{
             fontFamily: 'var(--font-mono)',
             fontSize: '14px',
-- 
cgit v1.3-2-g0d8e

