@@ -57,13 +57,14 @@ import {
5757 type BridgeChain ,
5858} from "@/lib/api/firewall-bridge" ;
5959import { cn } from "@/lib/utils" ;
60+ import { LoadingState } from "@/components/ui/loading-state" ;
6061import { CreateBridgeRuleModal } from "@/components/firewall/CreateBridgeRuleModal" ;
6162import { EditBridgeRuleModal } from "@/components/firewall/EditBridgeRuleModal" ;
6263import { DeleteBridgeRuleModal } from "@/components/firewall/DeleteBridgeRuleModal" ;
6364import { CreateCustomBridgeChainModal } from "@/components/firewall/CreateCustomBridgeChainModal" ;
6465import { DeleteCustomBridgeChainModal } from "@/components/firewall/DeleteCustomBridgeChainModal" ;
6566import { BridgeRuleRow } from "@/components/firewall/BridgeRuleRow" ;
66- import { BridgeReorderBanner } from "@/components/firewall/BridgeReorderBanner " ;
67+ import { ReorderBanner } from "@/components/ui/reorder-banner " ;
6768
6869export default function BridgeFirewallPage ( ) {
6970 const [ config , setConfig ] = useState < BridgeConfigResponse | null > ( null ) ;
@@ -331,18 +332,90 @@ export default function BridgeFirewallPage() {
331332 if ( loading && ! config ) {
332333 return (
333334 < AppLayout >
334- < div className = "flex items-center justify-center h-96" >
335- < RefreshCw className = "h-8 w-8 animate-spin text-muted-foreground" />
336- </ div >
335+ < LoadingState message = "Loading bridge firewall configuration..." />
337336 </ AppLayout >
338337 ) ;
339338 }
340339
341340 return (
342341 < AppLayout >
343- < div className = "flex h-full" >
342+ < div className = "flex flex-col lg:flex-row h-full" >
343+ { /* Mobile Chain Selector */ }
344+ < div className = "lg:hidden border-b border-border bg-card px-4 py-3" >
345+ < div className = "flex items-center gap-2 mb-2" >
346+ < Network className = "h-5 w-5 text-primary" />
347+ < h2 className = "text-sm font-semibold text-foreground" > Bridge Firewall</ h2 >
348+ </ div >
349+ < div className = "flex gap-2 overflow-x-auto pb-1" >
350+ { /* Base chain pills */ }
351+ < button
352+ onClick = { ( ) => handleChainSelect ( "forward" , false ) }
353+ className = { cn (
354+ "flex-shrink-0 px-3 py-1.5 rounded-full text-xs font-medium transition-all" ,
355+ selectedChain === "forward" && ! isCustomChain
356+ ? "bg-primary text-primary-foreground"
357+ : "bg-muted text-muted-foreground hover:bg-accent"
358+ ) }
359+ >
360+ Forward
361+ </ button >
362+ { isV15 && (
363+ < >
364+ < button
365+ onClick = { ( ) => handleChainSelect ( "input" , false ) }
366+ className = { cn (
367+ "flex-shrink-0 px-3 py-1.5 rounded-full text-xs font-medium transition-all" ,
368+ selectedChain === "input" && ! isCustomChain
369+ ? "bg-primary text-primary-foreground"
370+ : "bg-muted text-muted-foreground hover:bg-accent"
371+ ) }
372+ >
373+ Input
374+ </ button >
375+ < button
376+ onClick = { ( ) => handleChainSelect ( "output" , false ) }
377+ className = { cn (
378+ "flex-shrink-0 px-3 py-1.5 rounded-full text-xs font-medium transition-all" ,
379+ selectedChain === "output" && ! isCustomChain
380+ ? "bg-primary text-primary-foreground"
381+ : "bg-muted text-muted-foreground hover:bg-accent"
382+ ) }
383+ >
384+ Output
385+ </ button >
386+ < button
387+ onClick = { ( ) => handleChainSelect ( "prerouting" , false ) }
388+ className = { cn (
389+ "flex-shrink-0 px-3 py-1.5 rounded-full text-xs font-medium transition-all" ,
390+ selectedChain === "prerouting" && ! isCustomChain
391+ ? "bg-primary text-primary-foreground"
392+ : "bg-muted text-muted-foreground hover:bg-accent"
393+ ) }
394+ >
395+ Prerouting
396+ </ button >
397+ </ >
398+ ) }
399+ { /* Custom chain pills */ }
400+ { customChains . map ( ( chain ) => (
401+ < button
402+ key = { chain . name }
403+ onClick = { ( ) => handleChainSelect ( chain . name , true ) }
404+ className = { cn (
405+ "flex-shrink-0 px-3 py-1.5 rounded-full text-xs font-medium transition-all" ,
406+ selectedChain === chain . name && isCustomChain
407+ ? "bg-primary text-primary-foreground"
408+ : "bg-muted text-muted-foreground hover:bg-accent"
409+ ) }
410+ >
411+ { chain . name }
412+ </ button >
413+ ) ) }
414+ </ div >
415+ </ div >
416+
344417 { /* Sidebar */ }
345- < div className = "w-72 border-r border-border bg-card/50 flex flex-col h-full" >
418+ < div className = "w-72 border-r border-border bg-card/50 hidden lg: flex flex-col h-full" >
346419 < div className = "p-6 pb-4" >
347420 < div className = "flex items-center gap-3 mb-6" >
348421 < div className = "h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center" >
@@ -571,7 +644,7 @@ export default function BridgeFirewallPage() {
571644 < div className = "flex-1 flex flex-col overflow-hidden" >
572645 { /* Reorder Banner */ }
573646 { hasChanges && (
574- < BridgeReorderBanner
647+ < ReorderBanner
575648 onSave = { handleSaveReorder }
576649 onCancel = { handleCancelReorder }
577650 saving = { savingReorder }
0 commit comments