diff --git a/apps/frontend/src/renderer/components/settings/DisplaySettings.tsx b/apps/frontend/src/renderer/components/settings/DisplaySettings.tsx index 5eb05573..1b2f1393 100644 --- a/apps/frontend/src/renderer/components/settings/DisplaySettings.tsx +++ b/apps/frontend/src/renderer/components/settings/DisplaySettings.tsx @@ -1,4 +1,5 @@ -import { Monitor, ZoomIn, ZoomOut, RotateCcw } from 'lucide-react'; +import { useState } from 'react'; +import { Monitor, ZoomIn, ZoomOut, RotateCcw, Check } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { cn } from '../../lib/utils'; import { Label } from '../ui/label'; @@ -30,19 +31,63 @@ export function DisplaySettings({ settings, onSettingsChange }: DisplaySettingsP const currentScale = settings.uiScale ?? UI_SCALE_DEFAULT; - const handleScaleChange = (newScale: number) => { - // Clamp to valid range + // Local state for pending scale changes - prevents view reload until user applies + const [pendingScale, setPendingScale] = useState(null); + + // Track the last scale that was committed to the store (triggers view reload) + // This is different from currentScale which updates on every onSettingsChange call + const [committedScale, setCommittedScale] = useState(currentScale); + + // Display value: use pending scale if set, otherwise use current applied scale + const displayScale = pendingScale ?? currentScale; + + // Check if there are pending changes to apply + // Compare against committedScale (store-applied value), not currentScale (display value) + const hasPendingChanges = pendingScale !== null && pendingScale !== committedScale; + + // Update pending scale (for slider and +/- buttons) - doesn't trigger view reload + const updatePendingScale = (newScale: number) => { const clampedScale = Math.max(UI_SCALE_MIN, Math.min(UI_SCALE_MAX, newScale)); - - // Update local draft state + setPendingScale(clampedScale); + // Update settings for display but don't trigger store update (no view reload) onSettingsChange({ ...settings, uiScale: clampedScale }); + }; - // Apply immediately to store for live preview (triggers App.tsx useEffect) + // Apply pending changes to store (triggers view reload) + const handleApplyChanges = () => { + if (pendingScale !== null) { + updateStoreSettings({ uiScale: pendingScale }); + setCommittedScale(pendingScale); + setPendingScale(null); + } + }; + + // Handle preset button clicks - apply immediately (presets are intentional selections) + const handlePresetChange = (newScale: number) => { + const clampedScale = Math.max(UI_SCALE_MIN, Math.min(UI_SCALE_MAX, newScale)); + onSettingsChange({ ...settings, uiScale: clampedScale }); updateStoreSettings({ uiScale: clampedScale }); + setCommittedScale(clampedScale); + setPendingScale(null); + }; + + // Handle slider drag - only update pending state + const handleSliderChange = (newScale: number) => { + if (Number.isNaN(newScale)) return; + updatePendingScale(newScale); + }; + + // Handle zoom button clicks - increment/decrement by step (updates pending state) + const handleZoomOut = () => { + updatePendingScale(displayScale - UI_SCALE_STEP); + }; + + const handleZoomIn = () => { + updatePendingScale(displayScale + UI_SCALE_STEP); }; const handleReset = () => { - handleScaleChange(UI_SCALE_DEFAULT); + handlePresetChange(UI_SCALE_DEFAULT); }; return ( @@ -62,8 +107,9 @@ export function DisplaySettings({ settings, onSettingsChange }: DisplaySettingsP const isSelected = currentScale === preset.value; return ( handleScaleChange(parseInt(e.target.value, 10))} + value={displayScale} + onChange={(e) => handleSliderChange(parseInt(e.target.value, 10))} className={cn( 'flex-1 h-2 bg-muted rounded-lg appearance-none cursor-pointer', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', @@ -143,7 +203,35 @@ export function DisplaySettings({ settings, onSettingsChange }: DisplaySettingsP '[&::-moz-range-thumb]:hover:scale-110' )} /> - + + {/* Scale markers */} @@ -152,13 +240,6 @@ export function DisplaySettings({ settings, onSettingsChange }: DisplaySettingsP {UI_SCALE_MAX}% - - {/* Preview hint */} -
-

- {t('scale.preview')} -

-
); diff --git a/apps/frontend/src/shared/i18n/locales/en/settings.json b/apps/frontend/src/shared/i18n/locales/en/settings.json index da7a34fa..0ad3a67d 100644 --- a/apps/frontend/src/shared/i18n/locales/en/settings.json +++ b/apps/frontend/src/shared/i18n/locales/en/settings.json @@ -49,8 +49,7 @@ "fineTuneDescription": "Adjust from 75% to 200% in 5% increments", "default": "Default", "comfortable": "Comfortable", - "large": "Large", - "preview": "Changes preview immediately. Click Save Settings to persist." + "large": "Large" }, "general": { "otherAgentSettings": "Other Agent Settings", diff --git a/apps/frontend/src/shared/i18n/locales/fr/settings.json b/apps/frontend/src/shared/i18n/locales/fr/settings.json index 76486585..04477a42 100644 --- a/apps/frontend/src/shared/i18n/locales/fr/settings.json +++ b/apps/frontend/src/shared/i18n/locales/fr/settings.json @@ -49,8 +49,7 @@ "fineTuneDescription": "Ajustez de 75% à 200% par incréments de 5%", "default": "Par défaut", "comfortable": "Confortable", - "large": "Grand", - "preview": "Les changements sont prévisualisés immédiatement. Cliquez sur Enregistrer pour les conserver." + "large": "Grand" }, "general": { "otherAgentSettings": "Autres paramètres de l'agent", diff --git a/implementation_plan.json b/implementation_plan.json new file mode 100644 index 00000000..d44f4f68 --- /dev/null +++ b/implementation_plan.json @@ -0,0 +1,26 @@ +{ + "spec_id": "011-fix-scale-adjustment-and-view-reload-issues", + "subtasks": [ + { + "id": "1", + "title": "Fix slider to defer view reload until drag ends and add zoom button functionality", + "status": "completed" + } + ], + "qa_signoff": { + "status": "fixes_applied", + "timestamp": "2025-12-27T02:20:00Z", + "fix_session": 0, + "issues_fixed": [ + { + "title": "Remove preview hint textbox", + "fix_commit": "2653019" + }, + { + "title": "Remove unused preview translation keys", + "fix_commit": "e17536c" + } + ], + "ready_for_qa_revalidation": true + } +}