@@ -7,11 +7,11 @@ import { QRCodeSVG } from 'qrcode.react'
77import { cn , isPS5 } from '../../utils/helpers'
88
99const ManageSourcesView = ( { onBack, ip, addToast, showConfirm } ) => {
10- const [ sources , setSources ] = useState ( [ ] )
11- const [ loading , setLoading ] = useState ( true )
12- const [ newUrl , setNewUrl ] = useState ( '' )
13- const [ adding , setAdding ] = useState ( false )
14- const [ addError , setAddError ] = useState ( '' )
10+ const [ sources , setSources ] = useState ( [ ] )
11+ const [ loading , setLoading ] = useState ( true )
12+ const [ newUrl , setNewUrl ] = useState ( '' )
13+ const [ adding , setAdding ] = useState ( false )
14+ const [ addError , setAddError ] = useState ( '' )
1515 const [ showAddForm , setShowAddForm ] = useState ( false )
1616
1717 useEffect ( ( ) => {
@@ -20,7 +20,7 @@ const ManageSourcesView = ({ onBack, ip, addToast, showConfirm }) => {
2020 . then ( d => {
2121 if ( d ?. sources ) setSources ( d . sources )
2222 } )
23- . catch ( ( ) => { } )
23+ . catch ( ( ) => { } )
2424 . finally ( ( ) => setLoading ( false ) )
2525 } , [ ] )
2626
@@ -44,7 +44,7 @@ const ManageSourcesView = ({ onBack, ip, addToast, showConfirm }) => {
4444 const move = ( idx , dir ) => {
4545 if ( idx + dir < 1 || idx + dir >= sources . length ) return
4646 const updated = [ ...sources ]
47- ; [ updated [ idx ] , updated [ idx + dir ] ] = [ updated [ idx + dir ] , updated [ idx ] ]
47+ ; [ updated [ idx ] , updated [ idx + dir ] ] = [ updated [ idx + dir ] , updated [ idx ] ]
4848 setSources ( updated )
4949 saveSources ( updated )
5050 }
@@ -121,7 +121,7 @@ const ManageSourcesView = ({ onBack, ip, addToast, showConfirm }) => {
121121
122122 /* ---- Desktop Mode: full CRUD ---- */
123123 return (
124- < div className = "max-w-3xl mx-auto space-y-10 pb-20" >
124+ < div className = "w-full max-w-3xl mx-auto space-y-10 pb-20 min-w-0 " >
125125 { /* Header */ }
126126 < div className = "flex items-center space-x-6" >
127127 < button
@@ -140,41 +140,97 @@ const ManageSourcesView = ({ onBack, ip, addToast, showConfirm }) => {
140140 < Loader2 className = "w-10 h-10 text-ps-blue animate-spin" />
141141 </ div >
142142 ) : (
143- < div className = "space-y-3" >
143+ < div className = "space-y-3 w-full " >
144144 { sources . map ( ( src , idx ) => (
145145 < div
146146 key = { src . id }
147147 className = { cn (
148- 'group flex items-center gap-4 p-5 glass-card rounded-2xl border transition-all' ,
148+ 'group flex flex-col md:flex-row md: items-center gap-4 md:gap-6 p-5 md:p-6 glass-card rounded-2xl border transition-all w-full min-w-0 max-w-full overflow-hidden ' ,
149149 src . removable
150150 ? 'border-white/10 hover:border-ps-blue/30'
151151 : 'border-white/5 bg-white/[0.015]'
152152 ) }
153153 >
154- { /* Priority index */ }
155- < div className = { cn (
156- 'w-9 h-9 rounded-xl flex items-center justify-center text-sm font-black shrink-0' ,
157- idx === 0 ? 'bg-ps-blue/20 text-ps-blue' : 'bg-white/5 text-zinc-500'
158- ) } >
159- { idx + 1 }
160- </ div >
154+ { /* Header row on mobile / Left group on desktop */ }
155+ < div className = "flex items-center justify-between md:!justify-start flex-1 min-w-0 gap-4 w-full md:w-auto" >
156+ < div className = "flex items-center gap-3 min-w-0" >
157+ { /* Priority index */ }
158+ < div className = { cn (
159+ 'w-9 h-9 rounded-xl flex items-center justify-center text-sm font-black shrink-0' ,
160+ idx === 0 ? 'bg-ps-blue/20 text-ps-blue' : 'bg-white/5 text-zinc-500'
161+ ) } >
162+ { idx + 1 }
163+ </ div >
164+
165+ { /* Icon */ }
166+ < div className = "p-2 bg-white/5 rounded-xl shrink-0" >
167+ { src . removable
168+ ? < Globe className = "w-5 h-5 text-zinc-400 group-hover:text-ps-blue transition-colors" />
169+ : < Lock className = "w-5 h-5 text-ps-blue" />
170+ }
171+ </ div >
172+
173+ { /* Name (mobile only, inline header) */ }
174+ < div className = "min-w-0 md:hidden" >
175+ < p className = "font-bold text-white text-base leading-tight truncate" > { src . name } </ p >
176+ </ div >
177+ </ div >
178+
179+ { /* Mobile-only controls */ }
180+ < div className = "flex items-center space-x-2 shrink-0 md:hidden" >
181+ { src . removable && (
182+ < >
183+ < button
184+ onClick = { ( ) => move ( idx , - 1 ) }
185+ disabled = { idx <= 1 }
186+ className = "p-2 rounded-xl bg-white/5 hover:bg-white/10 disabled:opacity-20 disabled:cursor-not-allowed transition-all"
187+ title = "Move up"
188+ >
189+ < ChevronUp className = "w-4 h-4" />
190+ </ button >
191+ < button
192+ onClick = { ( ) => move ( idx , 1 ) }
193+ disabled = { idx === sources . length - 1 }
194+ className = "p-2 rounded-xl bg-white/5 hover:bg-white/10 disabled:opacity-20 disabled:cursor-not-allowed transition-all"
195+ title = "Move down"
196+ >
197+ < ChevronDown className = "w-4 h-4" />
198+ </ button >
199+ < button
200+ onClick = { ( ) => remove ( idx ) }
201+ className = "p-2 rounded-xl bg-red-950/20 text-red-500 border border-red-500/10 hover:bg-red-500 hover:text-white transition-all"
202+ title = "Remove source"
203+ >
204+ < Trash2 className = "w-4 h-4" />
205+ </ button >
206+ </ >
207+ ) }
208+ { ! src . removable && (
209+ < span className = "px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-widest text-ps-blue border border-ps-blue/20 bg-ps-blue/5" >
210+ Default
211+ </ span >
212+ ) }
213+ </ div >
161214
162- { /* Icon */ }
163- < div className = "p-2 bg-white/5 rounded-xl shrink-0" >
164- { src . removable
165- ? < Globe className = "w-5 h-5 text-zinc-400 group-hover:text-ps-blue transition-colors" />
166- : < Lock className = "w-5 h-5 text-ps-blue" />
167- }
215+ { /* Desktop-only Name + URL container */ }
216+ < div className = "hidden md:flex md:flex-col flex-1 min-w-0" >
217+ < p className = "font-bold text-white text-base leading-tight" > { src . name } </ p >
218+ < p className = "text-xs text-zinc-500 truncate mt-0.5 font-mono" > { src . url } </ p >
219+ </ div >
168220 </ div >
169221
170- { /* Name + URL */ }
171- < div className = "flex-1 min-w-0" >
172- < p className = "font-bold text-white text-base leading-tight" > { src . name } </ p >
173- < p className = "text-xs text-zinc-500 truncate mt-0.5 font-mono" > { src . url } </ p >
222+ { /* Mobile-only URL row (separated for more vertical height and scrollable view) */ }
223+ < div className = "md:hidden w-full min-w-0 max-w-full overflow-hidden" >
224+ < div className = "bg-white/[0.02] border border-white/5 rounded-xl p-3.5 flex flex-col gap-1 min-w-0 max-w-full overflow-hidden" >
225+ < span className = "text-[10px] text-zinc-500 font-bold uppercase tracking-wider" > Source URL</ span >
226+ < div className = "overflow-x-auto py-0.5 custom-scrollbar min-w-0 w-full max-w-full" >
227+ < p className = "text-xs text-zinc-400 font-mono whitespace-nowrap min-w-0" > { src . url } </ p >
228+ </ div >
229+ </ div >
174230 </ div >
175231
176- { /* Controls */ }
177- < div className = "flex items-center space-x-2 shrink-0" >
232+ { /* Desktop-only Controls */ }
233+ < div className = "hidden md: flex items-center space-x-2 shrink-0" >
178234 { src . removable && (
179235 < >
180236 < button
@@ -193,7 +249,6 @@ const ManageSourcesView = ({ onBack, ip, addToast, showConfirm }) => {
193249 >
194250 < ChevronDown className = "w-4 h-4" />
195251 </ button >
196- { /* Remove button */ }
197252 < button
198253 onClick = { ( ) => remove ( idx ) }
199254 className = "p-2 rounded-xl bg-red-950/20 text-red-500 border border-red-500/10 hover:bg-red-500 hover:text-white transition-all"
@@ -227,34 +282,36 @@ const ManageSourcesView = ({ onBack, ip, addToast, showConfirm }) => {
227282 < form onSubmit = { handleAdd } className = "p-6 glass-card rounded-2xl border border-white/10 space-y-4" >
228283 < p className = "font-bold text-white text-lg" > Add a New Source</ p >
229284 < p className = "text-sm text-zinc-500" >
230- Paste the URL to a JSON file. The source name will be read automatically from the JSON.
285+ Paste the URL to a JSON file.
231286 </ p >
232- < div className = "flex gap-3" >
287+ < div className = "flex flex-col md:flex-row gap-3" >
233288 < input
234289 type = "url"
235290 value = { newUrl }
236291 onChange = { e => setNewUrl ( e . target . value ) }
237292 placeholder = "https://example.com/payloads.json"
238- className = "flex-1 bg-white/5 border border-white/10 rounded-xl px-5 py-3 text-white text-sm placeholder-zinc-600 focus:outline-none focus:border-ps-blue/50 transition-colors"
293+ className = "flex-1 bg-white/5 border border-white/10 rounded-xl px-5 py-3 text-white text-sm placeholder-zinc-600 focus:outline-none focus:border-ps-blue/50 transition-colors w-full "
239294 autoFocus
240295 disabled = { adding }
241296 />
242- < button
243- type = "submit"
244- disabled = { adding || ! newUrl . trim ( ) }
245- className = "flex items-center space-x-2 px-6 py-3 bg-ps-blue hover:bg-ps-blue/80 disabled:opacity-50 text-white rounded-xl font-bold transition-all"
246- >
247- { adding ? < Loader2 className = "w-4 h-4 animate-spin" /> : < Plus className = "w-4 h-4" /> }
248- < span > { adding ? 'Validating...' : 'Add' } </ span >
249- </ button >
250- < button
251- type = "button"
252- onClick = { ( ) => { setShowAddForm ( false ) ; setNewUrl ( '' ) ; setAddError ( '' ) } }
253- disabled = { adding }
254- className = "px-5 py-3 bg-white/5 hover:bg-white/10 text-white rounded-xl font-bold transition-all"
255- >
256- Cancel
257- </ button >
297+ < div className = "flex gap-3 w-full md:w-auto" >
298+ < button
299+ type = "submit"
300+ disabled = { adding || ! newUrl . trim ( ) }
301+ className = "flex-1 md:flex-initial flex items-center justify-center space-x-2 px-6 py-3 bg-ps-blue hover:bg-ps-blue/80 disabled:opacity-50 text-white rounded-xl font-bold transition-all whitespace-nowrap"
302+ >
303+ { adding ? < Loader2 className = "w-4 h-4 animate-spin" /> : < Plus className = "w-4 h-4" /> }
304+ < span > { adding ? 'Validating...' : 'Add' } </ span >
305+ </ button >
306+ < button
307+ type = "button"
308+ onClick = { ( ) => { setShowAddForm ( false ) ; setNewUrl ( '' ) ; setAddError ( '' ) } }
309+ disabled = { adding }
310+ className = "flex-1 md:flex-initial px-5 py-3 bg-white/5 hover:bg-white/10 text-white rounded-xl font-bold transition-all text-center whitespace-nowrap"
311+ >
312+ Cancel
313+ </ button >
314+ </ div >
258315 </ div >
259316 { addError && (
260317 < div className = "flex items-center space-x-3 text-red-400 text-sm" >
0 commit comments