@@ -12,6 +12,7 @@ import {
1212 ModalContent ,
1313 ModalFooter ,
1414 ModalHeader ,
15+ Slider ,
1516 Switch ,
1617} from '@/components/emcn'
1718import { Input , Skeleton } from '@/components/ui'
@@ -76,6 +77,9 @@ export function General({ onOpenChange }: GeneralProps) {
7677
7778 const [ uploadError , setUploadError ] = useState < string | null > ( null )
7879
80+ const [ localSnapValue , setLocalSnapValue ] = useState < number | null > ( null )
81+ const snapToGridValue = localSnapValue ?? settings ?. snapToGridSize ?? 0
82+
7983 useEffect ( ( ) => {
8084 if ( profile ?. name ) {
8185 setName ( profile . name )
@@ -234,6 +238,18 @@ export function General({ onOpenChange }: GeneralProps) {
234238 }
235239 }
236240
241+ const handleSnapToGridChange = ( value : number [ ] ) => {
242+ setLocalSnapValue ( value [ 0 ] )
243+ }
244+
245+ const handleSnapToGridCommit = async ( value : number [ ] ) => {
246+ const newValue = value [ 0 ]
247+ if ( newValue !== settings ?. snapToGridSize && ! updateSetting . isPending ) {
248+ await updateSetting . mutateAsync ( { key : 'snapToGridSize' , value : newValue } )
249+ }
250+ setLocalSnapValue ( null )
251+ }
252+
237253 const handleTrainingControlsChange = async ( checked : boolean ) => {
238254 if ( checked !== settings ?. showTrainingControls && ! updateSetting . isPending ) {
239255 await updateSetting . mutateAsync ( { key : 'showTrainingControls' , value : checked } )
@@ -393,7 +409,6 @@ export function General({ onOpenChange }: GeneralProps) {
393409 dropdownWidth={140}
394410 value={settings?.theme}
395411 onChange={handleThemeChange}
396- disabled={updateSetting.isPending}
397412 placeholder='Select theme'
398413 options={[
399414 { label: 'System', value: 'system' },
@@ -410,17 +425,34 @@ export function General({ onOpenChange }: GeneralProps) {
410425 id = 'auto-connect'
411426 checked = { settings ?. autoConnect ?? true }
412427 onCheckedChange = { handleAutoConnectChange }
413- disabled = { updateSetting . isPending }
414428 />
415429 </ div >
416430
431+ < div className = 'flex items-center justify-between' >
432+ < Label htmlFor = 'snap-to-grid' > Snap to grid</ Label >
433+ < div className = 'flex items-center gap-[12px]' >
434+ < span className = 'w-[32px] text-right text-[12px] text-[var(--text-tertiary)]' >
435+ { snapToGridValue === 0 ? 'Off' : `${ snapToGridValue } px` }
436+ </ span >
437+ < Slider
438+ id = 'snap-to-grid'
439+ value = { [ snapToGridValue ] }
440+ onValueChange = { handleSnapToGridChange }
441+ onValueCommit = { handleSnapToGridCommit }
442+ min = { 0 }
443+ max = { 50 }
444+ step = { 1 }
445+ className = 'w-[100px]'
446+ />
447+ </ div >
448+ </ div >
449+
417450 < div className = 'flex items-center justify-between' >
418451 < Label htmlFor = 'error-notifications' > Run error notifications</ Label >
419452 < Switch
420453 id = 'error-notifications'
421454 checked = { settings ?. errorNotificationsEnabled ?? true }
422455 onCheckedChange = { handleErrorNotificationsChange }
423- disabled = { updateSetting . isPending }
424456 />
425457 </ div >
426458
@@ -430,7 +462,6 @@ export function General({ onOpenChange }: GeneralProps) {
430462 id = 'telemetry'
431463 checked = { settings ?. telemetryEnabled ?? true }
432464 onCheckedChange = { handleTelemetryToggle }
433- disabled = { updateSetting . isPending }
434465 />
435466 </ div >
436467
@@ -446,7 +477,6 @@ export function General({ onOpenChange }: GeneralProps) {
446477 id = 'training-controls'
447478 checked = { settings ?. showTrainingControls ?? false }
448479 onCheckedChange = { handleTrainingControlsChange }
449- disabled = { updateSetting . isPending }
450480 />
451481 </ div >
452482 ) }
@@ -458,7 +488,6 @@ export function General({ onOpenChange }: GeneralProps) {
458488 id = 'super-user-mode'
459489 checked = { settings ?. superUserModeEnabled ?? true }
460490 onCheckedChange = { handleSuperUserModeToggle }
461- disabled = { updateSetting . isPending }
462491 />
463492 </ div >
464493 ) }
@@ -534,6 +563,15 @@ function GeneralSkeleton() {
534563 < Skeleton className = 'h-[17px] w-[30px] rounded-full' />
535564 </ div >
536565
566+ { /* Snap to grid row */ }
567+ < div className = 'flex items-center justify-between' >
568+ < Skeleton className = 'h-4 w-24' />
569+ < div className = 'flex items-center gap-[12px]' >
570+ < Skeleton className = 'h-3 w-[32px]' />
571+ < Skeleton className = 'h-[6px] w-[100px] rounded-[20px]' />
572+ </ div >
573+ </ div >
574+
537575 { /* Error notifications row */ }
538576 < div className = 'flex items-center justify-between' >
539577 < Skeleton className = 'h-4 w-40' />
0 commit comments