(null);
- // Close menus when clicking outside
+ // Close menus when clicking outside (desktop)
useEffect(() => {
function handleClickOutside(e: MouseEvent) {
- if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
- setMenuOpen(false);
- }
- if (popoverRef.current && !popoverRef.current.contains(e.target as Node)) {
- const target = e.target as HTMLElement;
- if (!target.closest(".filter-rule-chip-main")) {
- setOpenChipId(null);
+ if (window.innerWidth > 980) {
+ if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
+ setMenuOpen(false);
+ }
+ if (popoverRef.current && !popoverRef.current.contains(e.target as Node)) {
+ const target = e.target as HTMLElement;
+ if (!target.closest(".filter-rule-chip-main")) {
+ setOpenChipId(null);
+ }
}
}
}
@@ -92,6 +100,15 @@ export default function WorkspaceFilterBar({
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
+ const handleToggleMenu = () => {
+ if (!menuOpen && menuRef.current) {
+ const rect = menuRef.current.getBoundingClientRect();
+ setMenuAlignRight(rect.left + 280 > window.innerWidth - 16);
+ }
+ setActiveMobileCatId(null);
+ setMenuOpen(!menuOpen);
+ };
+
// Parse active filter parameters
const isRecipe = type === "recipe";
const isIngredient = type === "ingredient";
@@ -175,7 +192,7 @@ export default function WorkspaceFilterBar({
const categoriesWithActiveSelections = categories.filter(c => hasActiveOptions(c));
const totalActiveCount = categoriesWithActiveSelections.length;
- // The chips visible on screen: categories with active selections + the currently open chip (if user just opened one from the menu)
+ // The chips visible on screen
const visibleCategoryIds = Array.from(
new Set([
...categoriesWithActiveSelections.map(c => c.id),
@@ -188,13 +205,18 @@ export default function WorkspaceFilterBar({
};
const handleAddCategory = (catId: string) => {
- setOpenChipId(catId);
- setMenuOpen(false);
+ if (window.innerWidth <= 980) {
+ setActiveMobileCatId(catId);
+ } else {
+ setOpenChipId(catId);
+ setMenuOpen(false);
+ }
setSearchTerm("");
};
const handleRemoveCategory = (catId: string) => {
if (openChipId === catId) setOpenChipId(null);
+ if (activeMobileCatId === catId) setActiveMobileCatId(null);
const params = new URLSearchParams(window.location.search);
const cat = categories.find(c => c.id === catId);
@@ -216,6 +238,7 @@ export default function WorkspaceFilterBar({
const handleClearAll = () => {
setOpenChipId(null);
setMenuOpen(false);
+ setActiveMobileCatId(null);
const params = new URLSearchParams();
if (type) params.set("type", type);
if (query) params.set("q", query);
@@ -258,6 +281,29 @@ export default function WorkspaceFilterBar({
navigateWithParams(params);
};
+ const handleOpenChip = (catId: string, e?: MouseEvent) => {
+ if (window.innerWidth <= 980) {
+ setActiveMobileCatId(catId);
+ setMenuOpen(true);
+ } else {
+ const isOpening = openChipId !== catId;
+ if (isOpening) {
+ const target = (e?.currentTarget as HTMLElement)?.closest(".filter-rule-item-group");
+ if (target) {
+ const rect = target.getBoundingClientRect();
+ setChipAlignRight(rect.left + 270 > window.innerWidth - 16);
+ }
+ }
+ setOpenChipId(openChipId === catId ? null : catId);
+ }
+ setSearchTerm("");
+ };
+
+ const activeMobileCat = activeMobileCatId ? categories.find(c => c.id === activeMobileCatId) : null;
+ const activeMobileFilteredOptions = activeMobileCat
+ ? activeMobileCat.options.filter(opt => opt.name.toLowerCase().includes(searchTerm.toLowerCase()))
+ : [];
+
return (
{/* 1. Main Filter Button Trigger in Pills Row */}
@@ -265,7 +311,7 @@ export default function WorkspaceFilterBar({
- {/* Filter Categories Menu */}
+ {/* Desktop Filter Categories Menu */}
{menuOpen && (
-