diff --git a/app/games/games-page-client.tsx b/app/games/games-page-client.tsx index abfbb6b..3dc8736 100644 --- a/app/games/games-page-client.tsx +++ b/app/games/games-page-client.tsx @@ -16,6 +16,7 @@ import { useGamepadNavigation } from "@/lib/hooks/use-gamepad-navigation" import { AntiCheatBadge } from "@/components/anti-cheat-badge" import { PlayabilityBadge } from "@/components/playability-badge" import { SavedFilters } from "@/components/saved-filters" +import { FilterDrawer } from "@/components/filter-drawer" interface GamesListItem { id: string @@ -268,125 +269,9 @@ export function GamesPageClient({ ) } - return ( -
- {/* Header */} - -
-

Games

-

- Browse {total.toLocaleString()} games with benchmarks, settings, and performance data -

-
-
- - {/* Search & Filter Bar */} - -
- {/* Search + Sort Row */} -
- - - - -
- - {/* Filter Panel (collapsible) */} - {showFilters && ( - + function FilterPanelContent() { + return ( + <> {/* Device filter */}
@@ -604,6 +489,138 @@ export function GamesPageClient({ Clear all filters )} + + + ) + } + + return ( +
+ {/* Header */} + +
+

Games

+

+ Browse {total.toLocaleString()} games with benchmarks, settings, and performance data +

+
+
+ + {/* Search & Filter Bar */} + +
+ {/* Search + Sort Row */} +
+ + + + +
+ + {/* Mobile drawer */} + setShowFilters(false)}> +
+ +
+
+ + {/* Desktop inline panel */} + {showFilters && ( + + )}
diff --git a/components/filter-drawer.tsx b/components/filter-drawer.tsx new file mode 100644 index 0000000..b17e200 --- /dev/null +++ b/components/filter-drawer.tsx @@ -0,0 +1,88 @@ +"use client" + +import { useEffect, useRef } from "react" +import { XIcon } from "lucide-react" +import { motion, AnimatePresence } from "motion/react" + +interface FilterDrawerProps { + isOpen: boolean + onClose: () => void + children: React.ReactNode +} + +export function FilterDrawer({ isOpen, onClose, children }: FilterDrawerProps) { + const drawerRef = useRef(null) + + // Close on Escape + useEffect(() => { + if (!isOpen) return + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") onClose() + } + document.addEventListener("keydown", handleKeyDown) + return () => document.removeEventListener("keydown", handleKeyDown) + }, [isOpen, onClose]) + + // Prevent body scroll when open + useEffect(() => { + if (isOpen) { + document.body.style.overflow = "hidden" + } else { + document.body.style.overflow = "" + } + return () => { + document.body.style.overflow = "" + } + }, [isOpen]) + + // Focus trap + useEffect(() => { + if (isOpen && drawerRef.current) { + const firstFocusable = drawerRef.current.querySelector( + 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])', + ) + firstFocusable?.focus() + } + }, [isOpen]) + + return ( + + {isOpen && ( + <> + {/* Backdrop */} + + + {/* Drawer */} + +
+

Filters

+ +
+
+ {children} +
+
+ + )} +
+ ) +}