feat(catalog filter): add filtering with complex patterns, including regex, help modal
|
Before Width: | Height: | Size: 150 B After Width: | Height: | Size: 150 B |
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 147 B After Width: | Height: | Size: 147 B |
|
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 157 B |
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "تمت إزالة هذه الرد من قبل مشرفي المنتدى",
|
||||
"not_mod_of_any_board": "أنت لست مشرفًا في أي لوحة.",
|
||||
"filters_and_highlights": "الفلاتر والإبرازات",
|
||||
"search_results_for": "نتائج البحث عن"
|
||||
"search_results_for": "نتائج البحث عن",
|
||||
"help": "مساعدة",
|
||||
"filter_and_highlights_help": "مساعدة الفلاتر والإبرازات",
|
||||
"filter_and_highlights": "التصفية والتسليط الضوء"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "এই প্রতিক্রিয়া বোর্ড পরিচালকদের দ্বারা সরানো হয়েছে",
|
||||
"not_mod_of_any_board": "আপনি কোনও বোর্ডের মড নন।",
|
||||
"filters_and_highlights": "ফিল্টার এবং হাইলাইট",
|
||||
"search_results_for": "অনুসন্ধান ফলাফল"
|
||||
"search_results_for": "অনুসন্ধান ফলাফল",
|
||||
"help": "সাহায্য",
|
||||
"filter_and_highlights_help": "ফিল্টার এবং হাইলাইট সাহায্য",
|
||||
"filter_and_highlights": "ফিল্টার এবং হাইলাইট"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Tato odpověď byla odstraněna moderátory fóra",
|
||||
"not_mod_of_any_board": "Nejste moderátor žádné desky.",
|
||||
"filters_and_highlights": "Filtry a zvýraznění",
|
||||
"search_results_for": "Výsledky hledání pro"
|
||||
"search_results_for": "Výsledky hledání pro",
|
||||
"help": "Pomoc",
|
||||
"filter_and_highlights_help": "Pomoc s filtry a zvýrazněním",
|
||||
"filter_and_highlights": "Filtry a zvýraznění"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Dette svar blev fjernet af forummoderatorer",
|
||||
"not_mod_of_any_board": "Du er ikke moderator for nogen tavler.",
|
||||
"filters_and_highlights": "Filtre og fremhævninger",
|
||||
"search_results_for": "Søgeresultater for"
|
||||
"search_results_for": "Søgeresultater for",
|
||||
"help": "Hjælp",
|
||||
"filter_and_highlights_help": "Filtre og fremhævelser Hjælp",
|
||||
"filter_and_highlights": "Filtre og fremhævninger"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Diese Antwort wurde von den Forenmoderatoren entfernt",
|
||||
"not_mod_of_any_board": "Du bist kein Moderator eines Boards.",
|
||||
"filters_and_highlights": "Filter & Highlights",
|
||||
"search_results_for": "Suchergebnisse für"
|
||||
"search_results_for": "Suchergebnisse für",
|
||||
"help": "Hilfe",
|
||||
"filter_and_highlights_help": "Filter- und Markierungs-Hilfe",
|
||||
"filter_and_highlights": "Filter und Hervorhebungen"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Η απάντηση αυτή αφαιρέθηκε από τους διαχειριστές του φόρουμ",
|
||||
"not_mod_of_any_board": "Δεν είστε διαχειριστής σε καμία κοινότητα.",
|
||||
"filters_and_highlights": "Φίλτρα και επισημάνσεις",
|
||||
"search_results_for": "Αποτελέσματα αναζήτησης για"
|
||||
"search_results_for": "Αποτελέσματα αναζήτησης για",
|
||||
"help": "Βοήθεια",
|
||||
"filter_and_highlights_help": "Βοήθεια φίλτρων και επισήμανσης",
|
||||
"filter_and_highlights": "Φίλτρα και Επισημάνσεις"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "This reply was removed by board moderators",
|
||||
"not_mod_of_any_board": "You are not a mod of any board.",
|
||||
"filters_and_highlights": "Filters & Highlights",
|
||||
"search_results_for": "Search results for"
|
||||
"search_results_for": "Search results for",
|
||||
"help": "Help",
|
||||
"filter_and_highlights_help": "Filters & Highlights Help",
|
||||
"filter_and_highlights": "Filters & Highlights"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Esta respuesta fue eliminada por los moderadores del foro",
|
||||
"not_mod_of_any_board": "No eres moderador de ningún tablero.",
|
||||
"filters_and_highlights": "Filtros y resaltar",
|
||||
"search_results_for": "Resultados de búsqueda para"
|
||||
"search_results_for": "Resultados de búsqueda para",
|
||||
"help": "Ayuda",
|
||||
"filter_and_highlights_help": "Ayuda de filtros y resaltes",
|
||||
"filter_and_highlights": "Filtros y resaltados"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "این پاسخ توسط مدیران انجمن حذف شد",
|
||||
"not_mod_of_any_board": "شما هیچ تابلو مدیر نیستید.",
|
||||
"filters_and_highlights": "فیلترها و هایلایتها",
|
||||
"search_results_for": "نتایج جستجو برای"
|
||||
"search_results_for": "نتایج جستجو برای",
|
||||
"help": "کمک",
|
||||
"filter_and_highlights_help": "کمک فیلترها و برجستهها",
|
||||
"filter_and_highlights": "فیلترها و برجستهها"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Tämä vastaus poistettiin foorumin moderaattoreiden toimesta",
|
||||
"not_mod_of_any_board": "Et ole moderaattori missään taulussa.",
|
||||
"filters_and_highlights": "Suodattimet ja korostukset",
|
||||
"search_results_for": "Hakutulokset hakusanalle"
|
||||
"search_results_for": "Hakutulokset hakusanalle",
|
||||
"help": "Apua",
|
||||
"filter_and_highlights_help": "Suodattimet ja korostukset -apu",
|
||||
"filter_and_highlights": "Suodattimet ja korostukset"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Ang sagot na ito ay tinanggal ng mga moderator ng board",
|
||||
"not_mod_of_any_board": "Hindi ka mod ng anumang board.",
|
||||
"filters_and_highlights": "Mga filter at highlight",
|
||||
"search_results_for": "Mga resulta ng paghahanap para sa"
|
||||
"search_results_for": "Mga resulta ng paghahanap para sa",
|
||||
"help": "Tulong",
|
||||
"filter_and_highlights_help": "Tulong sa mga filter at highlight",
|
||||
"filter_and_highlights": "Mga filter at highlight"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Cette réponse a été supprimée par les modérateurs du forum",
|
||||
"not_mod_of_any_board": "Vous n'êtes pas modérateur de n'aucun forum.",
|
||||
"filters_and_highlights": "Filtres et mises en évidence",
|
||||
"search_results_for": "Résultats de recherche pour"
|
||||
"search_results_for": "Résultats de recherche pour",
|
||||
"help": "Aide",
|
||||
"filter_and_highlights_help": "Aide sur les filtres et surlignages",
|
||||
"filter_and_highlights": "Filtres et surlignages"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "תשובה זו הוסרה על ידי מנהלי הפורום",
|
||||
"not_mod_of_any_board": "אתה לא מוד בכל לוח.",
|
||||
"filters_and_highlights": "סינונים והדגשות",
|
||||
"search_results_for": "תוצאות חיפוש עבור"
|
||||
"search_results_for": "תוצאות חיפוש עבור",
|
||||
"help": "עזרה",
|
||||
"filter_and_highlights_help": "עזרה במסננים והדגשות",
|
||||
"filter_and_highlights": "מסננים והדגשות"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "यह उत्तर बोर्ड मॉडरेटर द्वारा हटा दिया गया था",
|
||||
"not_mod_of_any_board": "आप किसी बोर्ड के मॉड नहीं हैं।",
|
||||
"filters_and_highlights": "फ़िल्टर और हाइलाइट्स",
|
||||
"search_results_for": "के लिए खोज परिणाम"
|
||||
"search_results_for": "के लिए खोज परिणाम",
|
||||
"help": "मदद",
|
||||
"filter_and_highlights_help": "फ़िल्टर और हाइलाइट्स सहायता",
|
||||
"filter_and_highlights": "फ़िल्टर और हाइलाइट्स"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Ez a válasz törlésre került a fórum moderátorai által",
|
||||
"not_mod_of_any_board": "Nem vagy moderátor egyetlen táblán sem.",
|
||||
"filters_and_highlights": "Szűrők és kiemelések",
|
||||
"search_results_for": "Keresési eredmények"
|
||||
"search_results_for": "Keresési eredmények",
|
||||
"help": "Segítség",
|
||||
"filter_and_highlights_help": "Szűrők és kiemelések súgó",
|
||||
"filter_and_highlights": "Szűrők és kiemelések"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Balasan ini dihapus oleh moderator papan",
|
||||
"not_mod_of_any_board": "Anda bukan mod di papan manapun.",
|
||||
"filters_and_highlights": "Filter dan Sorotan",
|
||||
"search_results_for": "Hasil pencarian untuk"
|
||||
"search_results_for": "Hasil pencarian untuk",
|
||||
"help": "Bantuan",
|
||||
"filter_and_highlights_help": "Bantuan Filter dan Sorotan",
|
||||
"filter_and_highlights": "Filter dan Sorotan"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Questa risposta è stata rimossa dai moderatori del forum",
|
||||
"not_mod_of_any_board": "Non sei un mod di nessuna board.",
|
||||
"filters_and_highlights": "Filtri e Evidenziazioni",
|
||||
"search_results_for": "Risultati di ricerca per"
|
||||
"search_results_for": "Risultati di ricerca per",
|
||||
"help": "Aiuto",
|
||||
"filter_and_highlights_help": "Aiuto su Filtri e Evidenziazioni",
|
||||
"filter_and_highlights": "Filtri e Evidenziazioni"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "この返信は掲示板のモデレーターによって削除されました",
|
||||
"not_mod_of_any_board": "あなたはどのボードのモデレーターでもありません。",
|
||||
"filters_and_highlights": "フィルターとハイライト",
|
||||
"search_results_for": "検索結果"
|
||||
"search_results_for": "検索結果",
|
||||
"help": "ヘルプ",
|
||||
"filter_and_highlights_help": "フィルターとハイライトのヘルプ",
|
||||
"filter_and_highlights": "フィルターとハイライト"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "이 답글은 게시판 관리자에 의해 삭제되었습니다",
|
||||
"not_mod_of_any_board": "당신은 어떤 게시판의 관리자도 아닙니다.",
|
||||
"filters_and_highlights": "필터 및 하이라이트",
|
||||
"search_results_for": "검색 결과"
|
||||
"search_results_for": "검색 결과",
|
||||
"help": "도움말",
|
||||
"filter_and_highlights_help": "필터 및 하이라이트 도움말",
|
||||
"filter_and_highlights": "필터 및 하이라이트"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "या उत्तराला बोर्ड मॉडरेटरने काढले आहे",
|
||||
"not_mod_of_any_board": "तुम्ही कोणत्याही बोर्डचे मॉड नाहीत.",
|
||||
"filters_and_highlights": "फिल्टर आणि हायलाइट्स",
|
||||
"search_results_for": "सर्च परिणाम"
|
||||
"search_results_for": "सर्च परिणाम",
|
||||
"help": "मदत",
|
||||
"filter_and_highlights_help": "फिल्टर आणि हायलाइट्स सहाय्य",
|
||||
"filter_and_highlights": "फिल्टर आणि हायलाइट्स"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Dit antwoord is verwijderd door de forum moderators",
|
||||
"not_mod_of_any_board": "Je bent geen mod van een bord.",
|
||||
"filters_and_highlights": "Filters en markeringen",
|
||||
"search_results_for": "Zoekresultaten voor"
|
||||
"search_results_for": "Zoekresultaten voor",
|
||||
"help": "Help",
|
||||
"filter_and_highlights_help": "Filters en Markeringen Help",
|
||||
"filter_and_highlights": "Filters en markeringen"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Dette svaret ble fjernet av forummoderatorer",
|
||||
"not_mod_of_any_board": "Du er ikke moderator på noen brett.",
|
||||
"filters_and_highlights": "Filtre og fremhevinger",
|
||||
"search_results_for": "Søkeresultater for"
|
||||
"search_results_for": "Søkeresultater for",
|
||||
"help": "Hjelp",
|
||||
"filter_and_highlights_help": "Filtre og fremhevinger Hjelp",
|
||||
"filter_and_highlights": "Filtre og uthevinger"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Ta odpowiedź została usunięta przez moderatorów forum",
|
||||
"not_mod_of_any_board": "Nie jesteś moderatorem żadnej tablicy.",
|
||||
"filters_and_highlights": "Filtry i wyróżnienia",
|
||||
"search_results_for": "Wyniki wyszukiwania dla"
|
||||
"search_results_for": "Wyniki wyszukiwania dla",
|
||||
"help": "Pomoc",
|
||||
"filter_and_highlights_help": "Pomoc dotycząca filtrów i wyróżnień",
|
||||
"filter_and_highlights": "Filtry i wyróżnienia"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Esta resposta foi removida pelos moderadores do fórum",
|
||||
"not_mod_of_any_board": "Você não é um moderador de nenhum quadro.",
|
||||
"filters_and_highlights": "Filtros e Destaques",
|
||||
"search_results_for": "Resultados de pesquisa para"
|
||||
"search_results_for": "Resultados de pesquisa para",
|
||||
"help": "Ajuda",
|
||||
"filter_and_highlights_help": "Ajuda de Filtros e Realces",
|
||||
"filter_and_highlights": "Filtros e Destaques"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Acest răspuns a fost eliminat de moderatorii forumului",
|
||||
"not_mod_of_any_board": "Nu ești moderator pe niciun tablou.",
|
||||
"filters_and_highlights": "Filtre și evidențiere",
|
||||
"search_results_for": "Rezultatele căutării pentru"
|
||||
"search_results_for": "Rezultatele căutării pentru",
|
||||
"help": "Ajutor",
|
||||
"filter_and_highlights_help": "Ajutor pentru filtre și evidențieri",
|
||||
"filter_and_highlights": "Filtre și evidențieri"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Этот ответ был удален модераторами форума",
|
||||
"not_mod_of_any_board": "Вы не модератор ни одной доски.",
|
||||
"filters_and_highlights": "Фильтры и выделения",
|
||||
"search_results_for": "Результаты поиска для"
|
||||
"search_results_for": "Результаты поиска для",
|
||||
"help": "Помощь",
|
||||
"filter_and_highlights_help": "Помощь с фильтрами и выделениями",
|
||||
"filter_and_highlights": "Фильтры и выделения"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Ky përgjigje u hoq nga moderatorët e forumit",
|
||||
"not_mod_of_any_board": "Nuk jeni mod në asnjë bord.",
|
||||
"filters_and_highlights": "Filtra dhe theksime",
|
||||
"search_results_for": "Rezultatet e kërkimit për"
|
||||
"search_results_for": "Rezultatet e kërkimit për",
|
||||
"help": "Ndihmë",
|
||||
"filter_and_highlights_help": "Ndihma për Filtro & Thekso",
|
||||
"filter_and_highlights": "Filtra dhe thekson"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Detta svar togs bort av forumets moderatorer",
|
||||
"not_mod_of_any_board": "Du är inte moderator på någon tavla.",
|
||||
"filters_and_highlights": "Filter och markeringar",
|
||||
"search_results_for": "Sökresultat för"
|
||||
"search_results_for": "Sökresultat för",
|
||||
"help": "Hjälp",
|
||||
"filter_and_highlights_help": "Filter och markeringar Hjälp",
|
||||
"filter_and_highlights": "Filter och markeringar"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "ఈ స్పందన బోర్డ్ మోడరేటర్లచే తొలగించబడింది",
|
||||
"not_mod_of_any_board": "మీరు ఎటువంటి బోర్డుకు మోడ్ కంటే లేరు.",
|
||||
"filters_and_highlights": "ఫిల్టర్లు మరియు హైలైట్లు",
|
||||
"search_results_for": "శోధన ఫలితాలు"
|
||||
"search_results_for": "శోధన ఫలితాలు",
|
||||
"help": "సహాయం",
|
||||
"filter_and_highlights_help": "ఫిల్టర్లు మరియు హైలైట్ సహాయం",
|
||||
"filter_and_highlights": "ఫిల్టర్లు మరియు హైలైట్స్"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "คำตอบนี้ถูกลบโดยผู้ดูแลบอร์ด",
|
||||
"not_mod_of_any_board": "คุณไม่ใช่ผู้ดูแลบอร์ดใดๆ",
|
||||
"filters_and_highlights": "ตัวกรองและไฮไลท์",
|
||||
"search_results_for": "ผลการค้นหาสำหรับ"
|
||||
"search_results_for": "ผลการค้นหาสำหรับ",
|
||||
"help": "ช่วยเหลือ",
|
||||
"filter_and_highlights_help": "ตัวกรองและการเน้นความช่วยเหลือ",
|
||||
"filter_and_highlights": "ตัวกรองและไฮไลท์"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Bu yanıt, forum moderatörleri tarafından kaldırıldı",
|
||||
"not_mod_of_any_board": "Hiçbir tahtanın moderatörü değilsiniz.",
|
||||
"filters_and_highlights": "Filtreler ve Vurgular",
|
||||
"search_results_for": "Arama sonuçları için"
|
||||
"search_results_for": "Arama sonuçları için",
|
||||
"help": "Yardım",
|
||||
"filter_and_highlights_help": "Filtreler ve Vurgular Yardımı",
|
||||
"filter_and_highlights": "Filtreler ve Vurgular"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Цю відповідь було видалено модераторами форуму",
|
||||
"not_mod_of_any_board": "Ви не модератор жодної дошки.",
|
||||
"filters_and_highlights": "Фільтри та виділення",
|
||||
"search_results_for": "Результати пошуку для"
|
||||
"search_results_for": "Результати пошуку для",
|
||||
"help": "Допомога",
|
||||
"filter_and_highlights_help": "Допомога з фільтрами та підсвічуваннями",
|
||||
"filter_and_highlights": "Фільтри та виділення"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "اس جواب کو بورڈ کے منتظمین نے حذف کر دیا ہے",
|
||||
"not_mod_of_any_board": "آپ کسی بورڈ کے موڈ نہیں ہیں۔",
|
||||
"filters_and_highlights": "فلٹرز اور ہائیلائٹس",
|
||||
"search_results_for": "تلاش کے نتائج"
|
||||
"search_results_for": "تلاش کے نتائج",
|
||||
"help": "مدد",
|
||||
"filter_and_highlights_help": "فلٹرز اور ہائی لائٹس کی مدد",
|
||||
"filter_and_highlights": "فلٹرز اور ہائلाइटس"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "Phản hồi này đã bị xóa bởi các quản trị viên diễn đàn",
|
||||
"not_mod_of_any_board": "Bạn không phải là quản trị viên của bất kỳ bảng nào.",
|
||||
"filters_and_highlights": "Bộ lọc và Nổi bật",
|
||||
"search_results_for": "Kết quả tìm kiếm cho"
|
||||
"search_results_for": "Kết quả tìm kiếm cho",
|
||||
"help": "Trợ giúp",
|
||||
"filter_and_highlights_help": "Trợ giúp bộ lọc và đánh dấu",
|
||||
"filter_and_highlights": "Bộ lọc và Nổi bật"
|
||||
}
|
||||
@@ -293,5 +293,8 @@
|
||||
"this_reply_was_removed": "该回复已被版主删除",
|
||||
"not_mod_of_any_board": "您不是任何板块的管理员。",
|
||||
"filters_and_highlights": "筛选器和高亮",
|
||||
"search_results_for": "搜索结果"
|
||||
"search_results_for": "搜索结果",
|
||||
"help": "帮助",
|
||||
"filter_and_highlights_help": "过滤器和高亮帮助",
|
||||
"filter_and_highlights": "筛选器与高亮"
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
.modal {
|
||||
top: 60px;
|
||||
left: 50%;
|
||||
left: calc(50% + 5px);
|
||||
transform: translateX(-50%);
|
||||
width: 380px;
|
||||
height: auto;
|
||||
@@ -41,14 +41,23 @@
|
||||
overflow-y: auto;
|
||||
position: fixed;
|
||||
z-index: 5;
|
||||
padding: 2px;
|
||||
padding: 2px 5px 5px 5px;
|
||||
font-size: var(--settings-modal-font-size);
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
|
||||
background-color: var(--settings-modal-background-color);
|
||||
border-top: var(--settings-modal-border-top);
|
||||
border-right: var(--settings-modal-border-right);
|
||||
border-bottom: var(--settings-modal-border-bottom);
|
||||
border-left: var(--settings-modal-border-left);
|
||||
}
|
||||
|
||||
.filtersProtipModal {
|
||||
top: 50px;
|
||||
width: 570px;
|
||||
left: 50%;
|
||||
padding: 2px 10px 5px 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 614px) {
|
||||
.filtersProtipModal {
|
||||
width: 90vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 420px) {
|
||||
@@ -82,6 +91,54 @@
|
||||
top: 5px;
|
||||
image-rendering: pixelated;
|
||||
background-image: var(--settings-modal-close-button-background-image);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.openHelpButton {
|
||||
right: 23px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: block;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
image-rendering: pixelated;
|
||||
background-image: var(--open-help-button-background-image);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.filtersProtip {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.filtersProtip code {
|
||||
padding: 1px 5px 1px 5px;
|
||||
background-color: #EEE;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.filtersProtip li {
|
||||
list-style: none;
|
||||
margin: 5px 0px;
|
||||
}
|
||||
|
||||
.filtersProtip ul {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.filtersProtip h4 {
|
||||
font-size: 15px;
|
||||
margin: 10px 0px 5px 0px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.filtersProtip h4:first-child {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.filtersProtip h4::before {
|
||||
content: "»";
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
@@ -108,16 +165,12 @@
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.saveButton {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.filtersTable {
|
||||
width: 100%;
|
||||
border-spacing: 1px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 10px 2px 2px 2px;
|
||||
padding: 0px 2px 2px 2px;
|
||||
}
|
||||
|
||||
.filtersTable th {
|
||||
@@ -168,7 +221,8 @@
|
||||
}
|
||||
|
||||
.saveButton {
|
||||
float: right;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.filterHits {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { useState, useCallback, useRef, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||
import useFeedResetStore from '../../stores/use-feed-reset-store';
|
||||
import styles from './catalog-filters.module.css';
|
||||
|
||||
const FiltersTable = ({ onSave }: { onSave: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const { filterItems, saveAndApplyFilters, currentSubplebbitAddress } = useCatalogFiltersStore();
|
||||
const resetFeed = useFeedResetStore((state) => state.reset);
|
||||
|
||||
const [localFilterItems, setLocalFilterItems] = useState(
|
||||
filterItems.map((item) => ({
|
||||
@@ -52,9 +54,17 @@ const FiltersTable = ({ onSave }: { onSave: () => void }) => {
|
||||
|
||||
const handleSave = useCallback(() => {
|
||||
const nonEmptyFilters = localFilterItems.filter((item) => item.text.trim() !== '');
|
||||
|
||||
saveAndApplyFilters(nonEmptyFilters);
|
||||
|
||||
useCatalogFiltersStore.getState().resetCountsForCurrentSubplebbit();
|
||||
|
||||
if (resetFeed) {
|
||||
resetFeed();
|
||||
}
|
||||
|
||||
onSave();
|
||||
}, [saveAndApplyFilters, localFilterItems, onSave]);
|
||||
}, [saveAndApplyFilters, localFilterItems, onSave, resetFeed]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
@@ -142,7 +152,7 @@ const FiltersTable = ({ onSave }: { onSave: () => void }) => {
|
||||
</span>
|
||||
</td>
|
||||
<td className={styles.filterHits}>
|
||||
{currentSubplebbitAddress && (item.subplebbitCounts?.get(currentSubplebbitAddress) ?? 0) > 0 && `x${item.subplebbitCounts?.get(currentSubplebbitAddress)}`}
|
||||
{currentSubplebbitAddress && item.subplebbitFilteredCids?.has(currentSubplebbitAddress) && `x${item.subplebbitCounts?.get(currentSubplebbitAddress) ?? 0}`}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
@@ -163,18 +173,107 @@ const FiltersTable = ({ onSave }: { onSave: () => void }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const FiltersProtip = () => {
|
||||
return (
|
||||
<div className={styles.filtersProtip}>
|
||||
<h4>Patterns</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Matching whole words:</strong>
|
||||
</li>
|
||||
<li>
|
||||
<code>feel</code> — will match <em>"feel"</em> but not <em>"feeling"</em>. This search is case-insensitive.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>AND operator:</strong>
|
||||
</li>
|
||||
<li>
|
||||
<code>feel girlfriend</code> — will match <em>"feel"</em> AND <em>"girlfriend"</em> in any order.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>OR operator:</strong>
|
||||
</li>
|
||||
<li>
|
||||
<code>feel|girlfriend</code> — will match <em>"feel"</em> OR <em>"girlfriend"</em>.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Mixing both operators:</strong>
|
||||
</li>
|
||||
<li>
|
||||
<code>girlfriend|boyfriend feel</code> — matches <em>"feel"</em> AND <em>"girlfriend"</em>, or <em>"feel"</em> AND <em>"boyfriend"</em>.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Exact match search:</strong>
|
||||
</li>
|
||||
<li>
|
||||
<code>"that feel when"</code> — place double quotes around the pattern to search for an exact string.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Wildcards:</strong>
|
||||
</li>
|
||||
<li>
|
||||
<code>feel*</code> — matches expressions such as <em>"feel"</em>, <em>"feels"</em>, <em>"feeling"</em>, <em>"feeler"</em>, etc…
|
||||
</li>
|
||||
<li>
|
||||
<code>idolm*ster</code> — this can match <em>"idolmaster"</em> or <em>"idolm@ster"</em>, etc…
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<strong>It is also possible to filter by regular expression:</strong>
|
||||
<li>
|
||||
<code>/^(?=.*detachable)(?=.*hats).*$/i</code> — AND operator.
|
||||
</li>
|
||||
<li>
|
||||
<code>/^(?!.*touhou).*$/i</code> — NOT operator.
|
||||
</li>
|
||||
<li>
|
||||
<code>{'/^>/'}</code> — threads starting with a quote (<em>{'">"'}</em> character as an html entity).
|
||||
</li>
|
||||
<li>
|
||||
<code>/^$/</code> — threads with no text.
|
||||
</li>
|
||||
</ul>
|
||||
<h4>Controls</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>On</strong> — enables or disables the filter.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hide</strong> — hides matched threads.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Top</strong> — moves the filter to the top of the feed.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const FiltersModal = ({ closeModal }: { closeModal: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [showHelp, setShowHelp] = useState(false);
|
||||
const openHelp = () => setShowHelp(true);
|
||||
const closeHelp = () => setShowHelp(false);
|
||||
return (
|
||||
<>
|
||||
<div className={styles.overlay} onClick={closeModal} />
|
||||
<div className={styles.modal}>
|
||||
<div className={styles.overlay} onClick={showHelp ? closeHelp : closeModal} />
|
||||
<div className={`${styles.modal} ${showHelp ? styles.filtersProtipModal : ''}`}>
|
||||
<div className={styles.header}>
|
||||
<span className={styles.title}>{t('filters_and_highlights')}</span>
|
||||
<span className={styles.closeButton} title='close' onClick={closeModal} />
|
||||
<span className={styles.title}>{showHelp ? t('filter_and_highlights_help') : t('filter_and_highlights')}</span>
|
||||
{!showHelp && <span className={styles.openHelpButton} title={t('help')} onClick={openHelp} />}
|
||||
<span className={styles.closeButton} title={t('close')} onClick={closeModal} />
|
||||
</div>
|
||||
<FiltersTable onSave={closeModal} />
|
||||
{showHelp ? <FiltersProtip /> : <FiltersTable onSave={closeModal} />}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import { Comment } from '@plebbit/plebbit-react-hooks';
|
||||
|
||||
/**
|
||||
* Checks if a text matches a pattern according to various pattern matching rules:
|
||||
* - Whole word matching: 'feel' matches 'feel' but not 'feeling'
|
||||
* - AND operator: 'feel girlfriend' matches both words in any order
|
||||
* - OR operator: 'feel|girlfriend' matches either word
|
||||
* - Mixed operators: 'girlfriend|boyfriend feel' matches complex logic
|
||||
* - Exact match: "that feel when" matches the exact phrase
|
||||
* - Wildcards: 'feel*' matches 'feel', 'feels', 'feeling', etc.
|
||||
* - Regex: /pattern/flags for regular expressions
|
||||
*
|
||||
* @param text The text to check against the pattern
|
||||
* @param pattern The pattern to match
|
||||
* @returns True if the text matches the pattern, false otherwise
|
||||
*/
|
||||
export const matchesPattern = (text: string, pattern: string): boolean => {
|
||||
if (!pattern || !text) return false;
|
||||
|
||||
const textLower = text.toLowerCase();
|
||||
|
||||
try {
|
||||
// Check if it's a regex pattern (starts and ends with /)
|
||||
if (pattern.startsWith('/') && pattern.length > 2 && /\/[gimsuy]*$/.test(pattern)) {
|
||||
const lastSlashIndex = pattern.lastIndexOf('/');
|
||||
const regexPattern = pattern.substring(1, lastSlashIndex);
|
||||
const flags = pattern.substring(lastSlashIndex + 1);
|
||||
const regex = new RegExp(regexPattern, flags);
|
||||
return regex.test(textLower);
|
||||
}
|
||||
// Check if it's an exact match pattern (surrounded by quotes)
|
||||
else if (pattern.startsWith('"') && pattern.endsWith('"') && pattern.length > 2) {
|
||||
const exactPattern = pattern.substring(1, pattern.length - 1).toLowerCase();
|
||||
return textLower.includes(exactPattern);
|
||||
}
|
||||
// Check for OR patterns (contains |)
|
||||
else if (pattern.includes('|')) {
|
||||
const orGroups = pattern.split(' ').filter(Boolean);
|
||||
|
||||
// Process each group (which might contain OR operators)
|
||||
return orGroups.every((group) => {
|
||||
const orTerms = group.split('|').map((term) => term.toLowerCase());
|
||||
return orTerms.some((term) => {
|
||||
// Handle wildcards in OR terms
|
||||
if (term.includes('*')) {
|
||||
const regexPattern = term.replace(/\*/g, '.*').toLowerCase();
|
||||
const regex = new RegExp(`\\b${regexPattern}\\b`, 'i');
|
||||
return regex.test(textLower);
|
||||
} else {
|
||||
// Match whole word only
|
||||
const regex = new RegExp(`\\b${term}\\b`, 'i');
|
||||
return regex.test(textLower);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// Check for AND patterns (space-separated words)
|
||||
else if (pattern.includes(' ')) {
|
||||
const andTerms = pattern
|
||||
.split(' ')
|
||||
.filter(Boolean)
|
||||
.map((term) => term.toLowerCase());
|
||||
return andTerms.every((term) => {
|
||||
// Handle wildcards in AND terms
|
||||
if (term.includes('*')) {
|
||||
const regexPattern = term.replace(/\*/g, '.*').toLowerCase();
|
||||
const regex = new RegExp(`\\b${regexPattern}\\b`, 'i');
|
||||
return regex.test(textLower);
|
||||
} else {
|
||||
// Match whole word only
|
||||
const regex = new RegExp(`\\b${term}\\b`, 'i');
|
||||
return regex.test(textLower);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Handle wildcard patterns
|
||||
else if (pattern.includes('*')) {
|
||||
const regexPattern = pattern.replace(/\*/g, '.*').toLowerCase();
|
||||
const regex = new RegExp(`\\b${regexPattern}\\b`, 'i');
|
||||
return regex.test(textLower);
|
||||
}
|
||||
// Simple whole word match
|
||||
else {
|
||||
const regex = new RegExp(`\\b${pattern.toLowerCase()}\\b`, 'i');
|
||||
return regex.test(textLower);
|
||||
}
|
||||
} catch (error) {
|
||||
// If regex parsing fails, fall back to simple includes
|
||||
console.error('Pattern matching error:', error);
|
||||
const simplifiedPattern = pattern.toLowerCase();
|
||||
return textLower.includes(simplifiedPattern);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a comment matches a pattern in its title or content
|
||||
*
|
||||
* @param comment The comment to check
|
||||
* @param pattern The pattern to match
|
||||
* @returns True if the comment matches the pattern, false otherwise
|
||||
*/
|
||||
export const commentMatchesPattern = (comment: Comment, pattern: string): boolean => {
|
||||
if (!pattern || !comment) return false;
|
||||
|
||||
const titleLower = comment?.title?.toLowerCase() || '';
|
||||
const contentLower = comment?.content?.toLowerCase() || '';
|
||||
const textToMatch = titleLower + ' ' + contentLower;
|
||||
|
||||
return matchesPattern(textToMatch, pattern);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { Comment } from '@plebbit/plebbit-react-hooks';
|
||||
import { commentMatchesPattern } from '../lib/utils/pattern-utils';
|
||||
|
||||
interface FilterItem {
|
||||
text: string;
|
||||
@@ -34,6 +35,7 @@ interface CatalogFiltersStore {
|
||||
searchText: string;
|
||||
setSearchFilter: (text: string) => void;
|
||||
clearSearchFilter: () => void;
|
||||
resetCountsForCurrentSubplebbit: () => void;
|
||||
}
|
||||
|
||||
const useCatalogFiltersStore = create(
|
||||
@@ -137,10 +139,39 @@ const useCatalogFiltersStore = create(
|
||||
hide: item.hide ?? true,
|
||||
top: item.top ?? false,
|
||||
}));
|
||||
|
||||
// Compare new filter items with existing ones to detect pattern changes
|
||||
const existingItems = get().filterItems;
|
||||
const updatedItems = nonEmptyItems.map((newItem) => {
|
||||
// Try to find matching existing item by index or text
|
||||
const existingItem = existingItems.find((item) => item.text === newItem.text);
|
||||
|
||||
// If we found a matching item, keep its counts
|
||||
if (existingItem) {
|
||||
return {
|
||||
...newItem,
|
||||
count: existingItem.count,
|
||||
filteredCids: existingItem.filteredCids,
|
||||
subplebbitCounts: existingItem.subplebbitCounts,
|
||||
subplebbitFilteredCids: existingItem.subplebbitFilteredCids,
|
||||
};
|
||||
}
|
||||
|
||||
// If pattern has changed or it's a new filter, reset all counts
|
||||
return {
|
||||
...newItem,
|
||||
count: 0,
|
||||
filteredCids: new Set<string>(),
|
||||
subplebbitCounts: new Map<string, number>(),
|
||||
subplebbitFilteredCids: new Map<string, Set<string>>(),
|
||||
};
|
||||
});
|
||||
|
||||
set({
|
||||
filterItems: nonEmptyItems,
|
||||
filterItems: updatedItems,
|
||||
filteredCids: new Set<string>(),
|
||||
});
|
||||
|
||||
get().recalcFilteredCount();
|
||||
get().updateFilter();
|
||||
},
|
||||
@@ -154,11 +185,7 @@ const useCatalogFiltersStore = create(
|
||||
|
||||
// Apply search filter
|
||||
if (state.searchText.trim() !== '') {
|
||||
const searchPattern = state.searchText.toLowerCase();
|
||||
const title = comment?.title?.toLowerCase() || '';
|
||||
const content = comment?.content?.toLowerCase() || '';
|
||||
|
||||
if (!title.includes(searchPattern) && !content.includes(searchPattern)) {
|
||||
if (!commentMatchesPattern(comment, state.searchText)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -170,11 +197,7 @@ const useCatalogFiltersStore = create(
|
||||
for (let i = 0; i < filterItems.length; i++) {
|
||||
const item = filterItems[i];
|
||||
if (item.enabled && item.text.trim() !== '') {
|
||||
const pattern = item.text.toLowerCase();
|
||||
const title = comment?.title?.toLowerCase() || '';
|
||||
const content = comment?.content?.toLowerCase() || '';
|
||||
|
||||
if (title.includes(pattern) || content.includes(pattern)) {
|
||||
if (commentMatchesPattern(comment, item.text)) {
|
||||
// If we have a current subplebbit and this is a match, increment the count
|
||||
if (currentSubplebbit && comment.subplebbitAddress === currentSubplebbit) {
|
||||
// We need to use a timeout to avoid modifying state during a state update
|
||||
@@ -272,6 +295,38 @@ const useCatalogFiltersStore = create(
|
||||
|
||||
return filteredCount;
|
||||
},
|
||||
resetCountsForCurrentSubplebbit: () => {
|
||||
const currentSubplebbit = get().currentSubplebbitAddress;
|
||||
if (!currentSubplebbit) return;
|
||||
|
||||
set((state) => {
|
||||
const updatedFilterItems = state.filterItems.map((item) => {
|
||||
const newItem = { ...item };
|
||||
|
||||
// Ensure maps are properly initialized
|
||||
if (!newItem.subplebbitCounts || !(newItem.subplebbitCounts instanceof Map)) {
|
||||
newItem.subplebbitCounts = new Map();
|
||||
}
|
||||
if (!newItem.subplebbitFilteredCids || !(newItem.subplebbitFilteredCids instanceof Map)) {
|
||||
newItem.subplebbitFilteredCids = new Map();
|
||||
}
|
||||
|
||||
// Reset counts for current subplebbit
|
||||
newItem.subplebbitCounts.set(currentSubplebbit, 0);
|
||||
newItem.subplebbitFilteredCids.set(currentSubplebbit, new Set<string>());
|
||||
|
||||
return newItem;
|
||||
});
|
||||
|
||||
return {
|
||||
filterItems: updatedFilterItems,
|
||||
filteredCount: 0,
|
||||
};
|
||||
});
|
||||
|
||||
// Trigger filter reapplication to start counting again
|
||||
get().updateFilter();
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'catalog-filters-storage',
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
--button-desktop-text-color: #00e;
|
||||
--button-desktop-text-color-hover: red;
|
||||
--close-button-background-image: url("/assets/buttons/cross-red.png");
|
||||
--open-help-button-background-image: url("/assets/buttons/help-red.png");
|
||||
|
||||
/* horizontal rule */
|
||||
--hr-border: none;
|
||||
@@ -263,6 +264,7 @@
|
||||
--button-desktop-text-color: #34345c;
|
||||
--button-desktop-text-color-hover: #d00;
|
||||
--close-button-background-image: url("/assets/buttons/cross-blue.png");
|
||||
--open-help-button-background-image: url("/assets/buttons/help-blue.png");
|
||||
|
||||
/* footer */
|
||||
--footer-item-background-color-desktop: #eef2ff;
|
||||
@@ -479,6 +481,7 @@
|
||||
--button-desktop-text-color-hover: red;
|
||||
--button-text-decoration: underline;
|
||||
--close-button-background-image: url("/assets/buttons/cross-red.png");
|
||||
--open-help-button-background-image: url("/assets/buttons/help-red.png");
|
||||
|
||||
/* footer */
|
||||
--footer-item-background-color-desktop: #fed;
|
||||
@@ -657,7 +660,7 @@
|
||||
--button-text-decoration: underline;
|
||||
--button-desktop-text-color-hover: #d00;
|
||||
--close-button-background-image: url("/assets/buttons/cross-blue.png");
|
||||
|
||||
--open-help-button-background-image: url("/assets/buttons/help-blue.png");
|
||||
/* footer */
|
||||
--footer-item-background-color-desktop: #eef2ff;
|
||||
|
||||
@@ -848,7 +851,7 @@
|
||||
--button-desktop-text-color: #81a2be;
|
||||
--button-desktop-text-color-hover: #5f89ac;
|
||||
--close-button-background-image: url("/assets/buttons/cross-dark.png");
|
||||
|
||||
--open-help-button-background-image: url("/assets/buttons/help-dark.png");
|
||||
/* filter for inputs */
|
||||
--filter80: brightness(85%);
|
||||
|
||||
@@ -1067,7 +1070,7 @@
|
||||
--button-desktop-text-color: #f60;
|
||||
--button-desktop-text-color-hover: #f30;
|
||||
--close-button-background-image: url("/assets/buttons/cross-photon.png");
|
||||
|
||||
--open-help-button-background-image: url("/assets/buttons/help-photon.png");
|
||||
/* horizontal rule */
|
||||
--hr-border: none;
|
||||
--hr-border-top: 1px solid #ddd;
|
||||
|
||||
@@ -18,6 +18,7 @@ import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||
import CatalogRow from '../../components/catalog-row';
|
||||
import LoadingEllipsis from '../../components/loading-ellipsis';
|
||||
import styles from './catalog.module.css';
|
||||
import { commentMatchesPattern } from '../../lib/utils/pattern-utils';
|
||||
|
||||
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
||||
|
||||
@@ -39,15 +40,12 @@ const createContentFilter = (
|
||||
|
||||
if (enabledFilters.length === 0) return true;
|
||||
|
||||
const titleLower = comment?.title?.toLowerCase() || '';
|
||||
const contentLower = comment?.content?.toLowerCase() || '';
|
||||
|
||||
// Check if any enabled filter matches the content
|
||||
for (let i = 0; i < enabledFilters.length; i++) {
|
||||
const item = enabledFilters[i];
|
||||
const pattern = item.text.toLowerCase();
|
||||
const pattern = item.text;
|
||||
|
||||
if (titleLower.includes(pattern) || contentLower.includes(pattern)) {
|
||||
if (commentMatchesPattern(comment, pattern)) {
|
||||
// Find the original filter index to increment count
|
||||
const filterIndex = filterItems.findIndex((f) => f.text === item.text && f.enabled);
|
||||
if (filterIndex !== -1) {
|
||||
@@ -102,12 +100,7 @@ const createCombinedFilter = (
|
||||
const searchFilter = {
|
||||
filter: (comment: Comment) => {
|
||||
if (!searchText.trim()) return true;
|
||||
|
||||
const titleLower = comment?.title?.toLowerCase() || '';
|
||||
const contentLower = comment?.content?.toLowerCase() || '';
|
||||
const searchPattern = searchText.toLowerCase();
|
||||
|
||||
return titleLower.includes(searchPattern) || contentLower.includes(searchPattern);
|
||||
return commentMatchesPattern(comment, searchText);
|
||||
},
|
||||
key: searchText ? `search-filter-${searchText}` : 'no-search-filter',
|
||||
};
|
||||
@@ -410,13 +403,9 @@ const Catalog = () => {
|
||||
combinedFeed.forEach((comment) => {
|
||||
if (!comment) return;
|
||||
|
||||
const titleLower = comment?.title?.toLowerCase() || '';
|
||||
const contentLower = comment?.content?.toLowerCase() || '';
|
||||
|
||||
let isTop = false;
|
||||
for (const filter of enabledTopFilters) {
|
||||
const pattern = filter.text.toLowerCase();
|
||||
if (titleLower.includes(pattern) || contentLower.includes(pattern)) {
|
||||
if (commentMatchesPattern(comment, filter.text)) {
|
||||
isTop = true;
|
||||
break;
|
||||
}
|
||||
|
||||