@@ -185,6 +185,7 @@ export default function Resources() {
185185 const [ savingFile , setSavingFile ] = useState ( false )
186186 const [ refreshingResources , setRefreshingResources ] = useState ( false )
187187 const [ resourceAction , setResourceAction ] = useState < ResourceAction | null > ( null )
188+ const [ actingResource , setActingResource ] = useState ( '' )
188189 const [ message , setMessage ] = useState < FlashMessage > ( null )
189190 const [ createKind , setCreateKind ] = useState < 'file' | 'folder' > ( 'file' )
190191 const [ createName , setCreateName ] = useState ( '' )
@@ -481,13 +482,14 @@ export default function Resources() {
481482 }
482483 }
483484
484- const handleResourceAction = async ( action : ResourceAction ) => {
485- if ( ! selectedResource || ! canChangeResource ) return
485+ const handleResourceAction = async ( action : ResourceAction , resourceName : string = selectedResource ) => {
486+ if ( ! resourceName || ! canChangeResource || actingResource ) return
486487
487- setResourceAction ( action )
488+ setActingResource ( resourceName )
489+ if ( resourceName === selectedResource ) setResourceAction ( action )
488490
489491 try {
490- const response = await sendNui < ResourceItem [ ] > ( 'setResourceState' , { name : selectedResource , state : action } )
492+ const response = await sendNui < ResourceItem [ ] > ( 'setResourceState' , { name : resourceName , state : action } )
491493 if ( response ) {
492494 setGameData ( ( previous : any ) => ( { ...previous , resources : response } ) )
493495 }
@@ -496,6 +498,7 @@ export default function Resources() {
496498 } catch ( error : any ) {
497499 showMessage ( 'error' , error ?. message || 'Falha ao alterar o estado do recurso.' )
498500 } finally {
501+ setActingResource ( '' )
499502 setResourceAction ( null )
500503 }
501504 }
@@ -729,17 +732,27 @@ export default function Resources() {
729732 { filteredResources . map ( ( resource ) => {
730733 const active = selectedResource === resource . name
731734 const tone = getResourceTone ( resource . resourceState )
735+ const acting = actingResource === resource . name
736+ const isStarted = resource . resourceState === 'started'
732737
733738 return (
734- < button
739+ < div
735740 key = { resource . name }
741+ role = "button"
742+ tabIndex = { 0 }
736743 className = { cn (
737- 'w-full rounded-2xl border p-3 text-left transition-all' ,
744+ 'w-full cursor-pointer rounded-2xl border p-3 text-left transition-all' ,
738745 active
739746 ? 'border-primary/50 bg-primary/10 shadow-[inset_0_0_0_1px_rgba(59,130,246,0.15)]'
740747 : 'border-border bg-muted/20 hover:border-border/80 hover:bg-muted/40'
741748 ) }
742749 onClick = { ( ) => void handleResourceSelect ( resource . name ) }
750+ onKeyDown = { ( event ) => {
751+ if ( event . key === 'Enter' || event . key === ' ' ) {
752+ event . preventDefault ( )
753+ void handleResourceSelect ( resource . name )
754+ }
755+ } }
743756 >
744757 < div className = "flex items-start justify-between gap-3" >
745758 < div className = "min-w-0" >
@@ -760,7 +773,50 @@ export default function Resources() {
760773 < p className = "mt-2 line-clamp-2 text-[11px] leading-relaxed text-muted-foreground" >
761774 { resource . description || 'Sem descricao no fxmanifest.' }
762775 </ p >
763- </ button >
776+
777+ { canChangeResource && (
778+ < div
779+ className = "mt-2.5 flex items-center gap-1.5 border-t border-border/60 pt-2.5"
780+ onClick = { ( event ) => event . stopPropagation ( ) }
781+ >
782+ { isStarted ? (
783+ < >
784+ < button
785+ type = "button"
786+ title = "Reiniciar"
787+ disabled = { acting }
788+ onClick = { ( ) => void handleResourceAction ( 'restart' , resource . name ) }
789+ className = "inline-flex items-center gap-1 rounded-lg border border-border bg-muted/30 px-2 py-1 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50"
790+ >
791+ < RotateCw className = { cn ( 'h-3.5 w-3.5' , acting && 'animate-spin' ) } />
792+ Reiniciar
793+ </ button >
794+ < button
795+ type = "button"
796+ title = "Parar"
797+ disabled = { acting }
798+ onClick = { ( ) => void handleResourceAction ( 'stop' , resource . name ) }
799+ className = "inline-flex items-center gap-1 rounded-lg border border-rose-500/30 bg-rose-500/10 px-2 py-1 text-[11px] font-medium text-rose-300 transition-colors hover:bg-rose-500/20 disabled:opacity-50"
800+ >
801+ < Square className = "h-3.5 w-3.5" />
802+ Parar
803+ </ button >
804+ </ >
805+ ) : (
806+ < button
807+ type = "button"
808+ title = "Iniciar"
809+ disabled = { acting }
810+ onClick = { ( ) => void handleResourceAction ( 'start' , resource . name ) }
811+ className = "inline-flex items-center gap-1 rounded-lg border border-emerald-500/30 bg-emerald-500/10 px-2 py-1 text-[11px] font-medium text-emerald-300 transition-colors hover:bg-emerald-500/20 disabled:opacity-50"
812+ >
813+ < Play className = { cn ( 'h-3.5 w-3.5' , acting && 'animate-spin' ) } />
814+ Iniciar
815+ </ button >
816+ ) }
817+ </ div >
818+ ) }
819+ </ div >
764820 )
765821 } ) }
766822
0 commit comments