"use client"; // Where FiltersPanel lives, which depends on how much room there is. // // • from xl — inline under the search bar, collapsible, exactly as it has // always been on a desktop. The group-chip row is designed to pack uniform // chips across the full width, so a narrow rail would be a downgrade there. // • below xl — a sheet behind the "Filters" chip, with an Apply button that // commits and closes. That is what gets the two screens of filter stack out // from between a phone visitor and their results. // // Both readers ask the same media query, and `useMediaQuery` re-reads `matches` // synchronously, so the trigger and the inline block can never both be showing // the same single-mount panel. import { useState } from "react"; import { ListFilterIcon } from "lucide-react"; import { Button } from "./ui/button"; import { Sheet, SheetContent, SheetTitle, SheetTrigger, } from "./ui/sheet"; import FiltersPanel from "./FiltersPanel"; import { useMediaQuery } from "../lib/useMediaQuery"; export function FiltersTrigger({ activeCount, onApply, applyDisabled = false, }: { activeCount: number; onApply: () => void; // Refused exactly when Search is ("Search in" has nothing ticked); the // panel above it says which row to fix. applyDisabled?: boolean; }) { const [open, setOpen] = useState(false); // From sm the sheet comes in from the right like the menu; on a phone it // rises from the bottom, where a thumb is. const fromSide = useMediaQuery("(min-width: 640px)"); return ( Filters
{/* Sticky so a long filter list never buries the one button that applies it. Deliberately NOT `search-submit`: there is exactly one of those, and it is in the bar. */}
); } // The inline placement. Renders nothing below xl, where FiltersTrigger owns the // panel — one mount, never two. export function FiltersSection() { const inline = useMediaQuery("(min-width: 1280px)"); if (!inline) return null; return ; }