|
Before Width: | Height: | Size: 223 B After Width: | Height: | Size: 223 B |
|
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 215 B |
|
Before Width: | Height: | Size: 220 B After Width: | Height: | Size: 221 B |
|
Before Width: | Height: | Size: 220 B After Width: | Height: | Size: 221 B |
@@ -295,5 +295,6 @@
|
||||
"help": "مساعدة",
|
||||
"filter_and_highlights_help": "مساعدة الفلاتر والإبرازات",
|
||||
"filter_and_highlights": "التصفية والتسليط الضوء",
|
||||
"boards_you_moderate": "المنتديات التي تقوم بالإشراف عليها"
|
||||
"boards_you_moderate": "المنتديات التي تقوم بالإشراف عليها",
|
||||
"more_threads_last_year": "{{count}} مواضيع منذ {{currentTimeFilterName}} — [<1>عرض المزيد من المواضيع من السنة الماضية</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "সাহায্য",
|
||||
"filter_and_highlights_help": "ফিল্টার এবং হাইলাইট সাহায্য",
|
||||
"filter_and_highlights": "ফিল্টার এবং হাইলাইট",
|
||||
"boards_you_moderate": "আপনি যে বোর্ডগুলি পরিচালনা করেন"
|
||||
"boards_you_moderate": "আপনি যে বোর্ডগুলি পরিচালনা করেন",
|
||||
"more_threads_last_year": "{{count}} থ্রেড {{currentTimeFilterName}} থেকে — [<1>গত বছরের আরও থ্রেড দেখান</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Pomoc",
|
||||
"filter_and_highlights_help": "Pomoc s filtry a zvýrazněním",
|
||||
"filter_and_highlights": "Filtry a zvýraznění",
|
||||
"boards_you_moderate": "Fóra, která moderujete"
|
||||
"boards_you_moderate": "Fóra, která moderujete",
|
||||
"more_threads_last_year": "{{count}} příspěvků od {{currentTimeFilterName}} — [<1>Zobrazit více příspěvků z minulého roku</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Hjælp",
|
||||
"filter_and_highlights_help": "Filtre og fremhævelser Hjælp",
|
||||
"filter_and_highlights": "Filtre og fremhævninger",
|
||||
"boards_you_moderate": "Boards du modererer"
|
||||
"boards_you_moderate": "Boards du modererer",
|
||||
"more_threads_last_year": "{{count}} tråde siden {{currentTimeFilterName}} — [<1>Vis flere tråde fra sidste år</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Hilfe",
|
||||
"filter_and_highlights_help": "Filter- und Markierungs-Hilfe",
|
||||
"filter_and_highlights": "Filter und Hervorhebungen",
|
||||
"boards_you_moderate": "Boards, die Sie moderieren"
|
||||
"boards_you_moderate": "Boards, die Sie moderieren",
|
||||
"more_threads_last_year": "{{count}} Threads seit {{currentTimeFilterName}} — [<1>Mehr Threads vom letzten Jahr anzeigen</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Βοήθεια",
|
||||
"filter_and_highlights_help": "Βοήθεια φίλτρων και επισήμανσης",
|
||||
"filter_and_highlights": "Φίλτρα και Επισημάνσεις",
|
||||
"boards_you_moderate": "Boards που διαχειρίζεστε"
|
||||
"boards_you_moderate": "Boards που διαχειρίζεστε",
|
||||
"more_threads_last_year": "{{count}} νήματα από {{currentTimeFilterName}} — [<1>Προβολή περισσότερων νημάτων από το περασμένο έτος</1>]"
|
||||
}
|
||||
|
||||
@@ -296,5 +296,6 @@
|
||||
"help": "Help",
|
||||
"filter_and_highlights_help": "Filters & Highlights Help",
|
||||
"filter_and_highlights": "Filters & Highlights",
|
||||
"boards_you_moderate": "boards you moderate"
|
||||
}
|
||||
"boards_you_moderate": "boards you moderate",
|
||||
"more_threads_last_year": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show More Threads from Last Year</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Ayuda",
|
||||
"filter_and_highlights_help": "Ayuda de filtros y resaltes",
|
||||
"filter_and_highlights": "Filtros y resaltados",
|
||||
"boards_you_moderate": "tableros que moderas"
|
||||
"boards_you_moderate": "tableros que moderas",
|
||||
"more_threads_last_year": "{{count}} hilos desde {{currentTimeFilterName}} — [<1>Ver más hilos del año pasado</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "کمک",
|
||||
"filter_and_highlights_help": "کمک فیلترها و برجستهها",
|
||||
"filter_and_highlights": "فیلترها و برجستهها",
|
||||
"boards_you_moderate": "تابلوهایی که مدیریت میکنید"
|
||||
"boards_you_moderate": "تابلوهایی که مدیریت میکنید",
|
||||
"more_threads_last_year": "{{count}} پست از {{currentTimeFilterName}} — [<1>نمایش بیشتر پستهای سال گذشته</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Apua",
|
||||
"filter_and_highlights_help": "Suodattimet ja korostukset -apu",
|
||||
"filter_and_highlights": "Suodattimet ja korostukset",
|
||||
"boards_you_moderate": "lautakunnat, joita valvot"
|
||||
"boards_you_moderate": "lautakunnat, joita valvot",
|
||||
"more_threads_last_year": "{{count}} ketjua sitten {{currentTimeFilterName}} — [<1>Näytä lisää viime vuoden ketjuja</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Tulong",
|
||||
"filter_and_highlights_help": "Tulong sa mga filter at highlight",
|
||||
"filter_and_highlights": "Mga filter at highlight",
|
||||
"boards_you_moderate": "mga board na iyong minomoderate"
|
||||
"boards_you_moderate": "mga board na iyong minomoderate",
|
||||
"more_threads_last_year": "{{count}} mga thread mula {{currentTimeFilterName}} — [<1>Ipakita ang higit pang mga thread mula noong nakaraang taon</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Aide",
|
||||
"filter_and_highlights_help": "Aide sur les filtres et surlignages",
|
||||
"filter_and_highlights": "Filtres et surlignages",
|
||||
"boards_you_moderate": "boards que vous modérez"
|
||||
"boards_you_moderate": "boards que vous modérez",
|
||||
"more_threads_last_year": "{{count}} fils depuis {{currentTimeFilterName}} — [<1>Afficher plus de fils de l'année dernière</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "עזרה",
|
||||
"filter_and_highlights_help": "עזרה במסננים והדגשות",
|
||||
"filter_and_highlights": "מסננים והדגשות",
|
||||
"boards_you_moderate": "לוחות שאתה מפקח עליהם"
|
||||
"boards_you_moderate": "לוחות שאתה מפקח עליהם",
|
||||
"more_threads_last_year": "{{count}} חוטים מאז {{currentTimeFilterName}} — [<1>הצג עוד חוטים מהשנה שעברה</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "मदद",
|
||||
"filter_and_highlights_help": "फ़िल्टर और हाइलाइट्स सहायता",
|
||||
"filter_and_highlights": "फ़िल्टर और हाइलाइट्स",
|
||||
"boards_you_moderate": "बोर्ड जो आप मॉडरेट करते हैं"
|
||||
"boards_you_moderate": "बोर्ड जो आप मॉडरेट करते हैं",
|
||||
"more_threads_last_year": "{{count}} थ्रेड्स {{currentTimeFilterName}} से — [<1>पिछले साल के अधिक थ्रेड्स दिखाएं</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"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",
|
||||
"boards_you_moderate": "boardok, amelyeket moderálsz"
|
||||
"boards_you_moderate": "boardok, amelyeket moderálsz",
|
||||
"more_threads_last_year": "{{count}} szál {{currentTimeFilterName}} óta — [<1>Több szál megjelenítése a múlt évből</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Bantuan",
|
||||
"filter_and_highlights_help": "Bantuan Filter dan Sorotan",
|
||||
"filter_and_highlights": "Filter dan Sorotan",
|
||||
"boards_you_moderate": "board yang Anda moderasi"
|
||||
"boards_you_moderate": "board yang Anda moderasi",
|
||||
"more_threads_last_year": "{{count}} thread sejak {{currentTimeFilterName}} — [<1>Tampilkan lebih banyak thread dari tahun lalu</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Aiuto",
|
||||
"filter_and_highlights_help": "Aiuto su Filtri e Evidenziazioni",
|
||||
"filter_and_highlights": "Filtri e Evidenziazioni",
|
||||
"boards_you_moderate": "board che moderi"
|
||||
"boards_you_moderate": "board che moderi",
|
||||
"more_threads_last_year": "{{count}} thread da {{currentTimeFilterName}} — [<1>Mostra altri thread dell'anno scorso</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "ヘルプ",
|
||||
"filter_and_highlights_help": "フィルターとハイライトのヘルプ",
|
||||
"filter_and_highlights": "フィルターとハイライト",
|
||||
"boards_you_moderate": "あなたが管理するボード"
|
||||
"boards_you_moderate": "あなたが管理するボード",
|
||||
"more_threads_last_year": "{{count}} スレッド {{currentTimeFilterName}} から — [<1>去年のスレッドをさらに表示</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "도움말",
|
||||
"filter_and_highlights_help": "필터 및 하이라이트 도움말",
|
||||
"filter_and_highlights": "필터 및 하이라이트",
|
||||
"boards_you_moderate": "당신이 관리하는 게시판"
|
||||
"boards_you_moderate": "당신이 관리하는 게시판",
|
||||
"more_threads_last_year": "{{count}} 스레드 {{currentTimeFilterName}} 이후 — [<1>작년의 스레드 더 보기</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "मदत",
|
||||
"filter_and_highlights_help": "फिल्टर आणि हायलाइट्स सहाय्य",
|
||||
"filter_and_highlights": "फिल्टर आणि हायलाइट्स",
|
||||
"boards_you_moderate": "तुम्ही ज्यांचे नियंत्रण करता अशा बोर्ड्स"
|
||||
"boards_you_moderate": "तुम्ही ज्यांचे नियंत्रण करता अशा बोर्ड्स",
|
||||
"more_threads_last_year": "{{count}} ध糀ं {{currentTimeFilterName}} पासून — [<1>गेल्या वर्षातील आणखी थ्रेड्स दाखवा</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Help",
|
||||
"filter_and_highlights_help": "Filters en Markeringen Help",
|
||||
"filter_and_highlights": "Filters en markeringen",
|
||||
"boards_you_moderate": "boards die je beheert"
|
||||
"boards_you_moderate": "boards die je beheert",
|
||||
"more_threads_last_year": "{{count}} threads sinds {{currentTimeFilterName}} — [<1>Meer threads van afgelopen jaar tonen</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Hjelp",
|
||||
"filter_and_highlights_help": "Filtre og fremhevinger Hjelp",
|
||||
"filter_and_highlights": "Filtre og uthevinger",
|
||||
"boards_you_moderate": "boards du modererer"
|
||||
"boards_you_moderate": "boards du modererer",
|
||||
"more_threads_last_year": "{{count}} tråder siden {{currentTimeFilterName}} — [<1>Vis flere tråder fra forrige år</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Pomoc",
|
||||
"filter_and_highlights_help": "Pomoc dotycząca filtrów i wyróżnień",
|
||||
"filter_and_highlights": "Filtry i wyróżnienia",
|
||||
"boards_you_moderate": "boards, które moderujesz"
|
||||
"boards_you_moderate": "boards, które moderujesz",
|
||||
"more_threads_last_year": "{{count}} wątki od {{currentTimeFilterName}} — [<1>Pokaż więcej wątków z zeszłego roku</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Ajuda",
|
||||
"filter_and_highlights_help": "Ajuda de Filtros e Realces",
|
||||
"filter_and_highlights": "Filtros e Destaques",
|
||||
"boards_you_moderate": "boards que você modera"
|
||||
"boards_you_moderate": "boards que você modera",
|
||||
"more_threads_last_year": "{{count}} tópicos desde {{currentTimeFilterName}} — [<1>Mostrar mais tópicos do ano passado</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Ajutor",
|
||||
"filter_and_highlights_help": "Ajutor pentru filtre și evidențieri",
|
||||
"filter_and_highlights": "Filtre și evidențieri",
|
||||
"boards_you_moderate": "boards pe care le moderezi"
|
||||
"boards_you_moderate": "boards pe care le moderezi",
|
||||
"more_threads_last_year": "{{count}} subiecte din {{currentTimeFilterName}} — [<1>Afișați mai multe subiecte de anul trecut</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Помощь",
|
||||
"filter_and_highlights_help": "Помощь с фильтрами и выделениями",
|
||||
"filter_and_highlights": "Фильтры и выделения",
|
||||
"boards_you_moderate": "boards, которые вы модерируете"
|
||||
"boards_you_moderate": "boards, которые вы модерируете",
|
||||
"more_threads_last_year": "{{count}} темы с {{currentTimeFilterName}} — [<1>Показать больше тем с прошлого года</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Ndihmë",
|
||||
"filter_and_highlights_help": "Ndihma për Filtro & Thekso",
|
||||
"filter_and_highlights": "Filtra dhe thekson",
|
||||
"boards_you_moderate": "boards që i moderoni"
|
||||
"boards_you_moderate": "boards që i moderoni",
|
||||
"more_threads_last_year": "{{count}} tema nga {{currentTimeFilterName}} — [<1>Shfaq më shumë tema nga viti i kaluar</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Hjälp",
|
||||
"filter_and_highlights_help": "Filter och markeringar Hjälp",
|
||||
"filter_and_highlights": "Filter och markeringar",
|
||||
"boards_you_moderate": "boards du modererar"
|
||||
"boards_you_moderate": "boards du modererar",
|
||||
"more_threads_last_year": "{{count}} trådar sedan {{currentTimeFilterName}} — [<1>Visa fler trådar från förra året</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "సహాయం",
|
||||
"filter_and_highlights_help": "ఫిల్టర్లు మరియు హైలైట్ సహాయం",
|
||||
"filter_and_highlights": "ఫిల్టర్లు మరియు హైలైట్స్",
|
||||
"boards_you_moderate": "మీరు మోడరేట్ చేసే బోర్డులు"
|
||||
"boards_you_moderate": "మీరు మోడరేట్ చేసే బోర్డులు",
|
||||
"more_threads_last_year": "{{count}} థ్రెడ్లు {{currentTimeFilterName}} నుండి — [<1>గత సంవత్సరం నుండి మరిన్ని థ్రెడ్లను చూపించండి</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "ช่วยเหลือ",
|
||||
"filter_and_highlights_help": "ตัวกรองและการเน้นความช่วยเหลือ",
|
||||
"filter_and_highlights": "ตัวกรองและไฮไลท์",
|
||||
"boards_you_moderate": "บอร์ดที่คุณดูแล"
|
||||
"boards_you_moderate": "บอร์ดที่คุณดูแล",
|
||||
"more_threads_last_year": "{{count}} กระทู้ตั้งแต่ {{currentTimeFilterName}} — [<1>แสดงกระทู้จากปีที่แล้วเพิ่มเติม</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Yardım",
|
||||
"filter_and_highlights_help": "Filtreler ve Vurgular Yardımı",
|
||||
"filter_and_highlights": "Filtreler ve Vurgular",
|
||||
"boards_you_moderate": "modere ettiğiniz panolar"
|
||||
"boards_you_moderate": "modere ettiğiniz panolar",
|
||||
"more_threads_last_year": "{{count}} konu {{currentTimeFilterName}} itibariyle — [<1>Geçen yıldan daha fazla konu göster</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "Допомога",
|
||||
"filter_and_highlights_help": "Допомога з фільтрами та підсвічуваннями",
|
||||
"filter_and_highlights": "Фільтри та виділення",
|
||||
"boards_you_moderate": "boards, які ви модеруватимете"
|
||||
"boards_you_moderate": "boards, які ви модеруватимете",
|
||||
"more_threads_last_year": "{{count}} тем з {{currentTimeFilterName}} — [<1>Показати більше тем з минулого року</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "مدد",
|
||||
"filter_and_highlights_help": "فلٹرز اور ہائی لائٹس کی مدد",
|
||||
"filter_and_highlights": "فلٹرز اور ہائلाइटس",
|
||||
"boards_you_moderate": "وہ بورڈز جن کی آپ نگرانی کرتے ہیں"
|
||||
"boards_you_moderate": "وہ بورڈز جن کی آپ نگرانی کرتے ہیں",
|
||||
"more_threads_last_year": "{{count}} تھریڈز {{currentTimeFilterName}} سے — [<1>گزشتہ سال کے مزید تھریڈز دکھائیں</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"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",
|
||||
"boards_you_moderate": "boards bạn điều hành"
|
||||
"boards_you_moderate": "boards bạn điều hành",
|
||||
"more_threads_last_year": "{{count}} chủ đề từ {{currentTimeFilterName}} — [<1>Hiển thị thêm các chủ đề từ năm ngoái</1>]"
|
||||
}
|
||||
|
||||
@@ -295,5 +295,6 @@
|
||||
"help": "帮助",
|
||||
"filter_and_highlights_help": "过滤器和高亮帮助",
|
||||
"filter_and_highlights": "筛选器与高亮",
|
||||
"boards_you_moderate": "您管理的板块"
|
||||
"boards_you_moderate": "您管理的板块",
|
||||
"more_threads_last_year": "{{count}} 主题自 {{currentTimeFilterName}} — [<1>显示更多去年的主题</1>]"
|
||||
}
|
||||
|
||||
@@ -148,10 +148,10 @@ const App = () => (
|
||||
<Route path='/all/catalog/:timeFilterName?' element={<Catalog />} />
|
||||
<Route path='/all/catalog/:timeFilterName?/settings' element={<Catalog />} />
|
||||
|
||||
<Route path='/subscriptions/:timeFilterName?' element={<Board />} />
|
||||
<Route path='/subscriptions/:timeFilterName?/settings' element={<Board />} />
|
||||
<Route path='/subscriptions/catalog/:timeFilterName?' element={<Catalog />} />
|
||||
<Route path='/subscriptions/catalog/:timeFilterName?/settings' element={<Catalog />} />
|
||||
<Route path='/subs/:timeFilterName?' element={<Board />} />
|
||||
<Route path='/subs/:timeFilterName?/settings' element={<Board />} />
|
||||
<Route path='/subs/catalog/:timeFilterName?' element={<Catalog />} />
|
||||
<Route path='/subs/catalog/:timeFilterName?/settings' element={<Catalog />} />
|
||||
|
||||
<Route path='/mod/:timeFilterName?' element={<Board />} />
|
||||
<Route path='/mod/:timeFilterName?/settings' element={<Board />} />
|
||||
|
||||
@@ -5,7 +5,7 @@ import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subple
|
||||
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
|
||||
import { isAllView, isCatalogView, isDescriptionView, isModView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||
import { getBoardPath, isDirectoryBoard } from '../../lib/utils/route-utils';
|
||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
|
||||
@@ -39,8 +39,8 @@ const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModVie
|
||||
if (params?.timeFilterName) return `/all/catalog/${params.timeFilterName}`;
|
||||
return `/all/catalog`;
|
||||
} else if (isInSubscriptionsView) {
|
||||
if (params?.timeFilterName) return `/subscriptions/catalog/${params.timeFilterName}`;
|
||||
return `/subscriptions/catalog`;
|
||||
if (params?.timeFilterName) return `/subs/catalog/${params.timeFilterName}`;
|
||||
return `/subs/catalog`;
|
||||
} else if (isInModView) {
|
||||
if (params?.timeFilterName) return `/mod/catalog/${params.timeFilterName}`;
|
||||
return `/mod/catalog`;
|
||||
@@ -82,8 +82,8 @@ const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView
|
||||
if (params?.timeFilterName) return `/all/${params.timeFilterName}`;
|
||||
return `/all`;
|
||||
} else if (isInSubscriptionsView) {
|
||||
if (params?.timeFilterName) return `/subscriptions/${params.timeFilterName}`;
|
||||
return `/subscriptions`;
|
||||
if (params?.timeFilterName) return `/subs/${params.timeFilterName}`;
|
||||
return `/subs`;
|
||||
} else if (isInModView) {
|
||||
if (params?.timeFilterName) return `/mod/${params.timeFilterName}`;
|
||||
return `/mod`;
|
||||
@@ -104,6 +104,28 @@ const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView
|
||||
);
|
||||
};
|
||||
|
||||
const VoteButton = () => {
|
||||
const { t } = useTranslation();
|
||||
const params = useParams();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
// Get the boardIdentifier from params (try boardIdentifier first, then subplebbitAddress for backward compatibility)
|
||||
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
||||
|
||||
// Only render the vote button if we're on a directory board route
|
||||
if (!boardIdentifier || !isDirectoryBoard(boardIdentifier, defaultSubplebbits)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const message = `Not available yet. Users will be able to submit and vote for boards competing for directory slots (like /${boardIdentifier}). The highest-voted board becomes the directory board.`;
|
||||
|
||||
return (
|
||||
<button className={`button ${styles.disabledButton}`} title={message} onClick={() => window.alert(message)}>
|
||||
{t('vote')}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const RefreshButton = () => {
|
||||
const { t } = useTranslation();
|
||||
const reset = useFeedResetStore((state) => state.reset);
|
||||
@@ -227,8 +249,8 @@ export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView
|
||||
: `/all/${timeFilterName}`
|
||||
: isInSubscriptionsView
|
||||
? isInCatalogView
|
||||
? `/subscriptions/catalog/${timeFilterName}`
|
||||
: `/subscriptions/${timeFilterName}`
|
||||
? `/subs/catalog/${timeFilterName}`
|
||||
: `/subs/${timeFilterName}`
|
||||
: isInModView
|
||||
? isInCatalogView
|
||||
? `/mod/catalog/${timeFilterName}`
|
||||
@@ -278,11 +300,17 @@ export const MobileBoardButtons = () => {
|
||||
|
||||
const { filteredCount, searchText } = useCatalogFiltersStore();
|
||||
|
||||
// Check if we should show the vote button (only for directory boards)
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
||||
const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, defaultSubplebbits);
|
||||
|
||||
return (
|
||||
<div className={`${styles.mobileBoardButtons} ${!isInCatalogView ? styles.addMargin : ''}`}>
|
||||
{isInPostView || isInPendingPostPage ? (
|
||||
<>
|
||||
<ReturnButton address={subplebbitAddress} isInAllView={isInAllView} isInSubscriptionsView={isInSubscriptionsView} isInModView={isInModView} />
|
||||
{showVoteButton && <VoteButton />}
|
||||
<CatalogButton address={subplebbitAddress} isInAllView={isInAllView} isInSubscriptionsView={isInSubscriptionsView} isInModView={isInModView} />
|
||||
<SubscribeButton address={subplebbitAddress} />
|
||||
<div className={styles.secondRow}>
|
||||
@@ -297,6 +325,7 @@ export const MobileBoardButtons = () => {
|
||||
) : (
|
||||
<CatalogButton address={subplebbitAddress} isInAllView={isInAllView} isInSubscriptionsView={isInSubscriptionsView} isInModView={isInModView} />
|
||||
)}
|
||||
{showVoteButton && <VoteButton />}
|
||||
{!(isInAllView || isInSubscriptionsView || isInModView) && <SubscribeButton address={subplebbitAddress} />}
|
||||
<RefreshButton />
|
||||
{isInCatalogView && searchText ? (
|
||||
@@ -374,6 +403,11 @@ export const DesktopBoardButtons = () => {
|
||||
|
||||
const { filteredCount, searchText } = useCatalogFiltersStore();
|
||||
|
||||
// Check if we should show the vote button (only for directory boards)
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
||||
const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, defaultSubplebbits);
|
||||
|
||||
return (
|
||||
<>
|
||||
<hr />
|
||||
@@ -406,6 +440,12 @@ export const DesktopBoardButtons = () => {
|
||||
</>
|
||||
)}
|
||||
[<RefreshButton />]
|
||||
{showVoteButton && (
|
||||
<>
|
||||
{' '}
|
||||
[<VoteButton />]
|
||||
</>
|
||||
)}
|
||||
{isInCatalogView && searchText ? (
|
||||
<span className={styles.filteredThreadsCount}>
|
||||
{' '}
|
||||
@@ -474,8 +514,8 @@ const SearchOPsBar = () => {
|
||||
: `/all/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
} else if (isInSubscriptionsView) {
|
||||
catalogUrl = params?.timeFilterName
|
||||
? `/subscriptions/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/subscriptions/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
? `/subs/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/subs/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
} else if (isInModView) {
|
||||
catalogUrl = params?.timeFilterName
|
||||
? `/mod/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
color: var(--board-address-text-color);
|
||||
}
|
||||
|
||||
.clickableSubtitle {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.clickableSubtitle:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.content hr {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { useLocation, useParams, useNavigate } from 'react-router-dom';
|
||||
import { useAccount, useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js';
|
||||
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
||||
import { isAllView, isSubscriptionsView, isModView } from '../../lib/utils/view-utils';
|
||||
@@ -25,6 +25,7 @@ const BoardHeader = () => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||
const isInModView = isModView(location.pathname);
|
||||
@@ -42,14 +43,18 @@ const BoardHeader = () => {
|
||||
// Find matching subplebbit from default list to get its title
|
||||
const defaultSubplebbit = subplebbitAddress ? defaultSubplebbits.find((s) => s.address === subplebbitAddress) : null;
|
||||
|
||||
const account = useAccount() || {};
|
||||
const subscriptions = account?.subscriptions || [];
|
||||
const subscriptionsSubtitle = subscriptions?.length === 1 ? `${subscriptions?.length} subscription` : `${subscriptions?.length} subscriptions`;
|
||||
|
||||
const title = isInAllView
|
||||
? multisubMetadata?.title || 'all'
|
||||
? multisubMetadata?.title || '/all/ - 5chan Directories'
|
||||
: isInSubscriptionsView
|
||||
? 'Subscriptions'
|
||||
? '/subs/ - Subscriptions'
|
||||
: isInModView
|
||||
? _.startCase(t('boards_you_moderate'))
|
||||
: defaultSubplebbit?.title || subplebbit?.title;
|
||||
const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : isInModView ? 'p/mod' : `p/${address || subplebbitAddress || ''}`;
|
||||
const subtitle = isInAllView ? '' : isInSubscriptionsView ? subscriptionsSubtitle : isInModView ? '/mod/' : `${address || subplebbitAddress || ''}`;
|
||||
|
||||
const { isOffline, isOnlineStatusLoading, offlineIconClass, offlineTitle } = useIsSubplebbitOffline(subplebbit);
|
||||
|
||||
@@ -75,7 +80,15 @@ const BoardHeader = () => {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.boardSubtitle}>{subtitle}</div>
|
||||
<div className={styles.boardSubtitle}>
|
||||
{isInSubscriptionsView ? (
|
||||
<span className={styles.clickableSubtitle} onClick={() => navigate('/subs/settings#subscriptions-settings')}>
|
||||
{subtitle}
|
||||
</span>
|
||||
) : (
|
||||
subtitle
|
||||
)}
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -63,6 +63,18 @@
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
image-rendering: pixelated;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.closeButton:focus {
|
||||
outline: 2px solid currentColor;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.closeButton:focus-visible {
|
||||
outline: 2px solid #0066cc;
|
||||
outline-offset: 2px;
|
||||
box-shadow: 0 0 0 2px #0066cc, 0 0 0 4px rgba(0, 102, 204, 0.3);
|
||||
}
|
||||
|
||||
.bd {
|
||||
|
||||
@@ -24,16 +24,20 @@
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 2px 2px 0px 1px;
|
||||
font-family: arial, helvetica, clean, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 16.003px;
|
||||
line-height: 18px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.directoryDialog {
|
||||
width: calc(100% - 20px);
|
||||
margin-left: -50%;
|
||||
left: 50%;
|
||||
max-width: 500px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: 0;
|
||||
transform: translate(-50%, -50%);
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +61,8 @@
|
||||
.closeButton {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
@@ -66,6 +70,14 @@
|
||||
background-size: 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.closeButtonHome {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url("/assets/buttons/icon-close-red.png");
|
||||
image-rendering: auto;
|
||||
}
|
||||
|
||||
.bd {
|
||||
|
||||
@@ -22,27 +22,17 @@ const DirectoryModal = () => {
|
||||
<div className={styles.directoryDialog}>
|
||||
<div className={styles.hd}>
|
||||
<h2>Submit a Board to a Directory</h2>
|
||||
<button className={styles.closeButton} onClick={closeDirectoryModal} title='Close' />
|
||||
<button className={`${styles.closeButton} ${isHomeView ? styles.closeButtonHome : ''}`} onClick={closeDirectoryModal} title='Close' />
|
||||
</div>
|
||||
<div className={styles.bd}>
|
||||
<p className={styles.introMessage}>
|
||||
<strong>The board you clicked on doesn't exist yet, but it can be yours!</strong>
|
||||
</p>
|
||||
|
||||
<div className={styles.section}>
|
||||
<h3>Directory vs Regular Board</h3>
|
||||
<p>
|
||||
A "directory board" is assigned to a category on the homepage (like "Anime & Manga" or "Video Games"). Directory assignments
|
||||
are temporary and handpicked by devs until DAO curation is implemented.{' '}
|
||||
<strong>Anyone can create a board and users can access it anytime using its address</strong>—use the search bar, direct links, or the
|
||||
"[Subscribe]" button to access boards regardless of directory assignment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.section}>
|
||||
<h3>Creating Your Board</h3>
|
||||
<p>
|
||||
Create a board using the{' '}
|
||||
<strong>Anyone can create a board</strong> using the{' '}
|
||||
<a href='https://plebbit.github.io/docs/learn/clients/5chan/create-a-board' target='_blank' rel='noopener noreferrer'>
|
||||
Seedit GUI client
|
||||
</a>{' '}
|
||||
@@ -50,27 +40,21 @@ const DirectoryModal = () => {
|
||||
<a href='https://github.com/plebbit/plebbit-cli' target='_blank' rel='noopener noreferrer'>
|
||||
plebbit-cli
|
||||
</a>
|
||||
. <strong>Build a following:</strong> Users can subscribe to your board via the "[Subscribe]" button, which adds it to their top bar. You can gain
|
||||
subscribers through direct links, word of mouth, or search—no directory assignment or dev approval needed.
|
||||
. Users can access it anytime via the search bar, direct links, or by subscribing with the "[Subscribe]" button—
|
||||
<strong>no directory assignment or dev approval needed</strong>. Directory boards are simply featured in homepage categories (like "Anime &
|
||||
Manga") and are handpicked by devs until DAO curation is implemented.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.section}>
|
||||
<h3>Directory Requirements</h3>
|
||||
<h3>Directory Submission</h3>
|
||||
<p>
|
||||
Boards need 99% uptime (they're P2P nodes), plus be active, well-moderated, and relevant to the category. Devs review and approve/reject based on these
|
||||
criteria.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.section}>
|
||||
<h3>Submitting to a Directory</h3>
|
||||
<p>
|
||||
Open a PR editing{' '}
|
||||
To submit your board, open a PR editing{' '}
|
||||
<a href='https://github.com/plebbit/lists/blob/master/5chan-multisub.json' target='_blank' rel='noopener noreferrer'>
|
||||
5chan-multisub.json
|
||||
</a>{' '}
|
||||
with your board's title, address, and NSFW status. Devs will review and merge if approved. 99% uptime is required.
|
||||
with your board's title, address, and NSFW status. Requirements: 99% uptime (they're P2P nodes), active, well-moderated, and relevant to the
|
||||
category. Devs will review and approve/reject based on these criteria.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -85,14 +69,6 @@ const DirectoryModal = () => {
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.section}>
|
||||
<h3>Decentralization</h3>
|
||||
<p>
|
||||
Devs can change directories via commits in the open-source repo. No centralized servers—anyone can fork, modify, and redeploy to their own domain. 5chan is
|
||||
adminless with no central authority.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.directoryFooter}>
|
||||
<button onClick={closeDirectoryModal}>Close</button>
|
||||
|
||||
@@ -55,6 +55,10 @@
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.closeButtonHome {
|
||||
background-image: url("/assets/buttons/icon-close-red.png");
|
||||
}
|
||||
|
||||
.bd {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import useDisclaimerModalStore from '../../stores/use-disclaimer-modal-store';
|
||||
import useDirectoryModalStore from '../../stores/use-directory-modal-store';
|
||||
import styles from './disclaimer-modal.module.css';
|
||||
|
||||
const DisclaimerModal = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const isHomeView = location.pathname === '/';
|
||||
const { showModal, closeDisclaimerModal, acceptDisclaimer, targetBoardPath } = useDisclaimerModalStore();
|
||||
const { openDirectoryModal } = useDirectoryModalStore();
|
||||
|
||||
@@ -33,7 +35,7 @@ const DisclaimerModal = () => {
|
||||
<div className={styles.disclaimerDialog}>
|
||||
<div className={styles.hd}>
|
||||
<h2>Disclaimer</h2>
|
||||
<button className={styles.closeButton} onClick={closeDisclaimerModal} title='Close' />
|
||||
<button className={`${styles.closeButton} ${isHomeView ? styles.closeButtonHome : ''}`} onClick={closeDisclaimerModal} title='Close' />
|
||||
</div>
|
||||
<div className={styles.bd}>
|
||||
<p>To access boards on 5chan (the "website"), you understand and agree to the following:</p>
|
||||
|
||||
@@ -71,7 +71,6 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
|
||||
const location = useLocation();
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInPostPageView = isPostPageView(location.pathname, params);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
|
||||
const userID = address && Plebbit.getShortAddress(address);
|
||||
const userIDBackgroundColor = hashStringToColor(userID);
|
||||
@@ -166,12 +165,6 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
|
||||
{isDescription || isRules ? '' : ' '}
|
||||
</span>
|
||||
<span className={styles.postNum}>
|
||||
{subplebbitAddress && (isInAllView || isInSubscriptionsView) && !isReply && boardPath && (
|
||||
<span className={styles.postNumLink}>
|
||||
{' '}
|
||||
<Link to={`/${boardPath}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>{' '}
|
||||
</span>
|
||||
)}
|
||||
{!(isDescription || isRules) &&
|
||||
(cid ? (
|
||||
<span className={styles.postNumLink}>
|
||||
@@ -181,7 +174,7 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
|
||||
title={t('link_to_post')}
|
||||
onClick={(e) => !cid && e.preventDefault()}
|
||||
>
|
||||
c/
|
||||
CID:
|
||||
</Link>
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
|
||||
{shortCid}
|
||||
@@ -189,7 +182,7 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
<span>c/</span>
|
||||
<span>CID:</span>
|
||||
<span className={styles.pendingCid}>
|
||||
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
|
||||
</span>
|
||||
@@ -250,13 +243,31 @@ interface PostMediaProps {
|
||||
linkHeight: number;
|
||||
linkWidth: number;
|
||||
parentCid: string;
|
||||
subplebbitAddress: string;
|
||||
isInAllView: boolean;
|
||||
isInSubscriptionsView: boolean;
|
||||
}
|
||||
|
||||
const PostMedia = ({ commentMediaInfo, hasThumbnail, isDescription, isRules, spoiler, deleted, removed, linkHeight, linkWidth, parentCid }: PostMediaProps) => {
|
||||
const PostMedia = ({
|
||||
commentMediaInfo,
|
||||
hasThumbnail,
|
||||
isDescription,
|
||||
isRules,
|
||||
spoiler,
|
||||
deleted,
|
||||
removed,
|
||||
linkHeight,
|
||||
linkWidth,
|
||||
parentCid,
|
||||
subplebbitAddress,
|
||||
isInAllView,
|
||||
isInSubscriptionsView,
|
||||
}: PostMediaProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { url } = commentMediaInfo || {};
|
||||
let type = commentMediaInfo?.type;
|
||||
const gifFrameUrl = useFetchGifFirstFrame(url);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
if (type === 'gif' && gifFrameUrl !== null) {
|
||||
type = 'animated gif';
|
||||
@@ -268,10 +279,16 @@ const PostMedia = ({ commentMediaInfo, hasThumbnail, isDescription, isRules, spo
|
||||
const [showThumbnail, setShowThumbnail] = useState(true);
|
||||
|
||||
const mediaDimensions = getMediaDimensions(commentMediaInfo);
|
||||
const boardPath = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
||||
|
||||
return (
|
||||
<div className={styles.file}>
|
||||
<div className={styles.fileText}>
|
||||
{subplebbitAddress && (isInAllView || isInSubscriptionsView) && boardPath && !parentCid && (
|
||||
<>
|
||||
{t('board')}: <Link to={`/${boardPath}`}>{boardPath}</Link>{' '}
|
||||
</>
|
||||
)}
|
||||
{t('link')}:{' '}
|
||||
<a href={url} target='_blank' rel='noopener noreferrer'>
|
||||
{spoiler ? _.capitalize(t('spoiler')) : url && url.length > 30 ? url.slice(0, 30) + '...' : url}
|
||||
@@ -337,6 +354,10 @@ const Reply = ({ postReplyCount, reply, roles }: PostProps) => {
|
||||
const isRouteLinkToReply = cid ? location.pathname.startsWith(route) : false;
|
||||
const { hidden } = useHide({ cid });
|
||||
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const params = useParams();
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
|
||||
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
|
||||
@@ -357,6 +378,9 @@ const Reply = ({ postReplyCount, reply, roles }: PostProps) => {
|
||||
linkHeight={linkHeight}
|
||||
linkWidth={linkWidth}
|
||||
parentCid={parentCid}
|
||||
subplebbitAddress={subplebbitAddress}
|
||||
isInAllView={isInAllView}
|
||||
isInSubscriptionsView={isInSubscriptionsView}
|
||||
/>
|
||||
)}
|
||||
{!hidden && (!(removed || deleted) || ((removed || deleted) && reason)) && <CommentContent comment={post} />}
|
||||
@@ -373,6 +397,8 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
|
||||
const location = useLocation();
|
||||
const isInPendingPostView = isPendingPostView(location.pathname, params);
|
||||
const isInPostPageView = isPostPageView(location.pathname, params);
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
|
||||
|
||||
@@ -433,6 +459,9 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
|
||||
linkHeight={linkHeight}
|
||||
linkWidth={linkWidth}
|
||||
parentCid={parentCid}
|
||||
subplebbitAddress={subplebbitAddress}
|
||||
isInAllView={isInAllView}
|
||||
isInSubscriptionsView={isInSubscriptionsView}
|
||||
/>
|
||||
)}
|
||||
<PostInfo isHidden={hidden} post={post} postReplyCount={replyCount} roles={roles} />
|
||||
|
||||
@@ -10,7 +10,7 @@ import { formatMarkdown } from '../../lib/utils/post-utils';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isDescriptionView, isModView, isPostPageView, isRulesView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import useAnonMode from '../../hooks/use-anon-mode';
|
||||
import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
@@ -59,7 +59,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
const isInModView = isModView(location.pathname);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||
const subscriptions = account?.subscriptions || [];
|
||||
const defaultSubplebbitAddresses = useDefaultSubplebbitAddresses();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
const { accountSubplebbits } = useAccountSubplebbits();
|
||||
const accountSubplebbitAddresses = Object.keys(accountSubplebbits);
|
||||
@@ -408,11 +408,13 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
<select onChange={(e) => setPublishPostOptions({ subplebbitAddress: e.target.value })} value={subplebbitAddress}>
|
||||
<option value=''>{t('choose_one')}</option>
|
||||
{isInAllView &&
|
||||
defaultSubplebbitAddresses.map((address: string) => (
|
||||
<option key={address} value={address}>
|
||||
{address && Plebbit.getShortAddress(address)}
|
||||
</option>
|
||||
))}
|
||||
defaultSubplebbits
|
||||
.filter((subplebbit) => subplebbit.title && subplebbit.address)
|
||||
.map((subplebbit) => (
|
||||
<option key={subplebbit.address} value={subplebbit.address}>
|
||||
{subplebbit.title}
|
||||
</option>
|
||||
))}
|
||||
{isInModView &&
|
||||
accountSubplebbitAddresses.map((address: string) => (
|
||||
<option key={address} value={address}>
|
||||
|
||||
@@ -178,7 +178,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
|
||||
{subplebbitAddress && (isInAllView || isInSubscriptionsView) && !isReply && boardPath && (
|
||||
<div className={styles.postNumLink}>
|
||||
{' '}
|
||||
<Link to={`/${boardPath}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>
|
||||
<Link to={`/${boardPath}`}>Board: {boardPath}</Link>
|
||||
</div>
|
||||
)}
|
||||
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />{' '}
|
||||
@@ -191,7 +191,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
|
||||
title={t('link_to_post')}
|
||||
onClick={(e) => !cid && e.preventDefault()}
|
||||
>
|
||||
c/
|
||||
CID:
|
||||
</Link>
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
|
||||
{shortCid.slice(0, -4)}
|
||||
@@ -199,7 +199,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
<span>c/</span>
|
||||
<span>CID:</span>
|
||||
<span className={styles.pendingCid}>
|
||||
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
|
||||
</span>
|
||||
|
||||
@@ -230,7 +230,7 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
|
||||
}
|
||||
}, []);
|
||||
|
||||
const contentPrefix = `c/${parentCid && Plebbit.getShortCid(parentCid)}\n`;
|
||||
const contentPrefix = `>>${parentCid && Plebbit.getShortCid(parentCid)}\n`;
|
||||
|
||||
// enable spellcheck after the prefix is set
|
||||
useEffect(() => {
|
||||
@@ -311,7 +311,7 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
|
||||
}}
|
||||
>
|
||||
<div className={`replyModalHandle ${styles.title}`} {...(!isMobile ? bind() : {})}>
|
||||
{t('reply_to_cid', { cid: `c/${parentCid && Plebbit.getShortCid(parentCid)}`, interpolation: { escapeValue: false } })}
|
||||
{t('reply_to_cid', { cid: `CID:${parentCid && Plebbit.getShortCid(parentCid)}`, interpolation: { escapeValue: false } })}
|
||||
<button
|
||||
className={styles.closeIcon}
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -10,7 +10,7 @@ const TopbarEditModal = () => {
|
||||
const { showModal, closeTopbarEditModal } = useTopbarEditModalStore();
|
||||
const { visibleDirectories, visibleSubscriptions, setDirectoryVisibility, setSubscriptionVisibility } = useTopbarVisibilityStore();
|
||||
const account = useAccount();
|
||||
const subscriptions = account?.subscriptions || [];
|
||||
const subscriptions = useMemo(() => account?.subscriptions || [], [account?.subscriptions]);
|
||||
const location = useLocation();
|
||||
|
||||
// Convert visible directories set to space-separated string for input
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import Plebbit from '@plebbit/plebbit-js';
|
||||
import { useAccount, useAccountComment, useAccountSubplebbits } from '@plebbit/plebbit-react-hooks';
|
||||
import { isAllView, isCatalogView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { useDefaultSubplebbitAddresses, useDefaultSubplebbits, MultisubSubplebbit } from '../../hooks/use-default-subplebbits';
|
||||
import { useDefaultSubplebbits, MultisubSubplebbit } from '../../hooks/use-default-subplebbits';
|
||||
import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import { getBoardPath, extractDirectoryFromTitle } from '../../lib/utils/route-utils';
|
||||
import { TimeFilter } from '../board-buttons';
|
||||
@@ -179,7 +179,7 @@ const TopBarDesktop = () => {
|
||||
return (
|
||||
<div className={styles.boardNavDesktop}>
|
||||
<span className={styles.boardList}>
|
||||
[<Link to='/all'>all</Link> / <Link to='/subscriptions'>subscriptions</Link>
|
||||
[<Link to='/all'>all</Link> / <Link to='/subs'>subs</Link>
|
||||
{accountSubplebbitAddresses.length > 0 && (
|
||||
<>
|
||||
{' '}
|
||||
@@ -228,12 +228,12 @@ const TopBarDesktop = () => {
|
||||
const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const subplebbitAddresses = useDefaultSubplebbitAddresses();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const displaySubplebbitAddress = subplebbitAddress && subplebbitAddress.length > 30 ? subplebbitAddress.slice(0, 30).concat('...') : subplebbitAddress;
|
||||
const [showSearchBar, setShowSearchBar] = useState(false);
|
||||
|
||||
const currentSubplebbitIsInList = subplebbitAddresses.some((address: string) => address === subplebbitAddress);
|
||||
// Filter to only show directory boards (those with titles)
|
||||
const directoryBoards = useMemo(() => defaultSubplebbits.filter((sub) => sub.title && extractDirectoryFromTitle(sub.title)), [defaultSubplebbits]);
|
||||
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
@@ -241,36 +241,37 @@ const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
|
||||
const isInCatalogView = isCatalogView(location.pathname, params);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
const boardPath = useBoardPath(subplebbitAddress);
|
||||
const selectValue = isInAllView ? 'all' : isInSubscriptionsView ? 'subscriptions' : boardPath || subplebbitAddress;
|
||||
const selectValue = isInAllView ? 'all' : isInSubscriptionsView ? 'subs' : boardPath || subplebbitAddress;
|
||||
|
||||
const { accountSubplebbits } = useAccountSubplebbits();
|
||||
const accountSubplebbitAddresses = Object.keys(accountSubplebbits);
|
||||
|
||||
// Check if current subplebbit is a directory board
|
||||
const currentIsDirectoryBoard = directoryBoards.some((board) => board.address === subplebbitAddress);
|
||||
|
||||
const boardSelect = (
|
||||
<select
|
||||
value={selectValue}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
// If it's a directory code or special route, use it directly
|
||||
if (value === 'all' || value === 'subscriptions' || value === 'mod') {
|
||||
// If it's a special route, use it directly
|
||||
if (value === 'all' || value === 'subs' || value === 'mod') {
|
||||
navigate(`/${value}${isInCatalogView ? '/catalog' : ''}`);
|
||||
} else {
|
||||
// Otherwise, resolve to board path
|
||||
const path = getBoardPath(value, defaultSubplebbits);
|
||||
navigate(`/${path}${isInCatalogView ? '/catalog' : ''}`);
|
||||
// Otherwise, it's a directory code, use it directly
|
||||
navigate(`/${value}${isInCatalogView ? '/catalog' : ''}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{!currentSubplebbitIsInList && subplebbitAddress && <option value={subplebbitAddress}>{displaySubplebbitAddress}</option>}
|
||||
{!currentIsDirectoryBoard && subplebbitAddress && <option value={subplebbitAddress}>{displaySubplebbitAddress}</option>}
|
||||
<option value='all'>all</option>
|
||||
<option value='subscriptions'>subscriptions</option>
|
||||
<option value='subs'>subs</option>
|
||||
{accountSubplebbitAddresses.length > 0 && <option value='mod'>mod</option>}
|
||||
{subplebbitAddresses.map((address: any, index: number) => {
|
||||
const subplebbitAddress = address?.includes('.') ? address : Plebbit.getShortAddress(address);
|
||||
const boardPath = getBoardPath(address, defaultSubplebbits);
|
||||
{directoryBoards.map((board, index) => {
|
||||
const directoryCode = extractDirectoryFromTitle(board.title!);
|
||||
return (
|
||||
<option key={index} value={boardPath}>
|
||||
{Plebbit.getShortAddress(subplebbitAddress)}
|
||||
<option key={index} value={directoryCode!}>
|
||||
{board.title}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -62,7 +62,7 @@ const useTheme = (): [string, (theme: string) => void] => {
|
||||
|
||||
let storedTheme = null;
|
||||
if (isInAllView || isInSubscriptionsView || isInModView) {
|
||||
storedTheme = themes.sfw;
|
||||
storedTheme = themes.nsfw;
|
||||
} else if (subplebbitAddress) {
|
||||
const subplebbit = subplebbits.find((s) => s.address === subplebbitAddress);
|
||||
if (subplebbit?.nsfw) {
|
||||
@@ -83,7 +83,7 @@ const useTheme = (): [string, (theme: string) => void] => {
|
||||
const setSubplebbitTheme = useCallback(
|
||||
async (newTheme: string) => {
|
||||
if (isInAllView || isInSubscriptionsView || isInModView) {
|
||||
await setThemeStore('sfw', newTheme);
|
||||
await setThemeStore('nsfw', newTheme);
|
||||
} else if (subplebbitAddress) {
|
||||
const subplebbit = subplebbits.find((s) => s.address === subplebbitAddress);
|
||||
if (subplebbit?.nsfw) {
|
||||
|
||||
@@ -59,7 +59,7 @@ export const is5chanLink = (url: string): boolean => {
|
||||
// - /{boardIdentifier}/catalog
|
||||
// - /{boardIdentifier}/description
|
||||
// - /{boardIdentifier}/rules
|
||||
// - /all, /subscriptions, /mod, /pending/{index}
|
||||
// - /all, /subs, /mod, /pending/{index}
|
||||
return (
|
||||
/^\/p\/[^/]+(\/c\/[^/]+)?$/.test(routePath) ||
|
||||
/^\/[^/]+(\/thread\/[^/]+|\/catalog|\/description|\/rules)?$/.test(routePath) ||
|
||||
|
||||
@@ -16,7 +16,7 @@ export const isBoardView = (pathname: string, params: ParamsType): boolean => {
|
||||
// Check if it's a board view (not all, subscriptions, mod, pending, or special routes)
|
||||
if (
|
||||
pathname.startsWith('/all') ||
|
||||
pathname.startsWith('/subscriptions') ||
|
||||
pathname.startsWith('/subs') ||
|
||||
pathname.startsWith('/mod') ||
|
||||
pathname.startsWith('/pending') ||
|
||||
pathname === '/' ||
|
||||
@@ -40,10 +40,10 @@ export const isCatalogView = (pathname: string, params: ParamsType): boolean =>
|
||||
decodedPathname === `/all/catalog/settings` ||
|
||||
decodedPathname === `/all/catalog/${timeFilterName}` ||
|
||||
decodedPathname === `/all/catalog/${timeFilterName}/settings` ||
|
||||
decodedPathname === `/subscriptions/catalog` ||
|
||||
decodedPathname === `/subscriptions/catalog/settings` ||
|
||||
decodedPathname === `/subscriptions/catalog/${timeFilterName}` ||
|
||||
decodedPathname === `/subscriptions/catalog/${timeFilterName}/settings` ||
|
||||
decodedPathname === `/subs/catalog` ||
|
||||
decodedPathname === `/subs/catalog/settings` ||
|
||||
decodedPathname === `/subs/catalog/${timeFilterName}` ||
|
||||
decodedPathname === `/subs/catalog/${timeFilterName}/settings` ||
|
||||
decodedPathname === `/mod/catalog` ||
|
||||
decodedPathname === `/mod/catalog/settings` ||
|
||||
decodedPathname === `/mod/catalog/${timeFilterName}` ||
|
||||
@@ -99,14 +99,14 @@ export const isSettingsView = (pathname: string, params: ParamsType): boolean =>
|
||||
export const isSubscriptionsView = (pathname: string, params: ParamsType): boolean => {
|
||||
const { timeFilterName } = params;
|
||||
return (
|
||||
pathname === '/subscriptions' ||
|
||||
pathname === '/subscriptions/settings' ||
|
||||
pathname === `/subscriptions/${timeFilterName}` ||
|
||||
pathname === `/subscriptions/${timeFilterName}/settings` ||
|
||||
pathname === '/subscriptions/catalog' ||
|
||||
pathname === '/subscriptions/catalog/settings' ||
|
||||
pathname === `/subscriptions/catalog/${timeFilterName}` ||
|
||||
pathname === `/subscriptions/catalog/${timeFilterName}/settings`
|
||||
pathname === '/subs' ||
|
||||
pathname === '/subs/settings' ||
|
||||
pathname === `/subs/${timeFilterName}` ||
|
||||
pathname === `/subs/${timeFilterName}/settings` ||
|
||||
pathname === '/subs/catalog' ||
|
||||
pathname === '/subs/catalog/settings' ||
|
||||
pathname === `/subs/catalog/${timeFilterName}` ||
|
||||
pathname === `/subs/catalog/${timeFilterName}/settings`
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,12 @@ const useReplyModalStore = create<ReplyModalState>((set, get) => ({
|
||||
},
|
||||
|
||||
openReplyModal: (parentCid, postCid, subplebbitAddress) => {
|
||||
// Don't update if already open with different parent
|
||||
if (get().activeCid && get().activeCid !== parentCid) {
|
||||
window.alert('Multiple quotes are not possible on 5chan for the time being, because of a protocol limitation. Please reply to one post at a time.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get selected text
|
||||
const text = document.getSelection()?.toString();
|
||||
if (text) {
|
||||
@@ -38,11 +44,6 @@ const useReplyModalStore = create<ReplyModalState>((set, get) => ({
|
||||
const isMobile = window.innerWidth <= 768; // Simple check, adjust as needed
|
||||
const scrollY = isMobile ? window.scrollY : 0;
|
||||
|
||||
// Don't update if already open with different parent
|
||||
if (get().activeCid && get().activeCid !== parentCid) {
|
||||
return;
|
||||
}
|
||||
|
||||
set({
|
||||
activeCid: parentCid,
|
||||
threadCid: postCid,
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
--directory-modal-header-background-color: rgb(136, 0, 0);
|
||||
--directory-modal-header-text-color: rgb(255, 255, 255);
|
||||
--directory-modal-close-button-background-image: url("/assets/buttons/cross-red.png");
|
||||
--disclaimer-modal-close-button-background-image: url("/assets/buttons/cross-red.png");
|
||||
|
||||
|
||||
/* footer */
|
||||
@@ -297,6 +298,7 @@
|
||||
--directory-modal-header-background-color: #98e;
|
||||
--directory-modal-header-text-color: #000;
|
||||
--directory-modal-close-button-background-image: url("/assets/buttons/cross-blue.png");
|
||||
--disclaimer-modal-close-button-background-image: url("/assets/buttons/cross-blue.png");
|
||||
|
||||
/* horizontal rule */
|
||||
--hr-border: none;
|
||||
@@ -503,6 +505,7 @@
|
||||
--directory-modal-header-background-color: #ea8;
|
||||
--directory-modal-header-text-color: #800;
|
||||
--directory-modal-close-button-background-image: url("/assets/buttons/cross-red.png");
|
||||
--disclaimer-modal-close-button-background-image: url("/assets/buttons/cross-red.png");
|
||||
|
||||
/* footer */
|
||||
--footer-item-background-color-desktop: #fed;
|
||||
@@ -700,6 +703,7 @@
|
||||
--directory-modal-header-background-color: #98e;
|
||||
--directory-modal-header-text-color: #000;
|
||||
--directory-modal-close-button-background-image: url("/assets/buttons/cross-blue.png");
|
||||
--disclaimer-modal-close-button-background-image: url("/assets/buttons/cross-blue.png");
|
||||
|
||||
/* media */
|
||||
--media-thumbnail-background-color: rgba(0, 0, 0, 0.05);
|
||||
@@ -897,6 +901,7 @@
|
||||
--directory-modal-header-background-color: #282a2e;
|
||||
--directory-modal-header-text-color: #c5c8c6;
|
||||
--directory-modal-close-button-background-image: url("/assets/buttons/cross-dark.png");
|
||||
--disclaimer-modal-close-button-background-image: url("/assets/buttons/cross-dark.png");
|
||||
|
||||
/* horizontal rule */
|
||||
--hr-border: none;
|
||||
@@ -1243,6 +1248,7 @@
|
||||
--directory-modal-header-background-color: #ddd;
|
||||
--directory-modal-header-text-color: #333;
|
||||
--directory-modal-close-button-background-image: url("/assets/buttons/cross-photon.png");
|
||||
--disclaimer-modal-close-button-background-image: url("/assets/buttons/cross-photon.png");
|
||||
|
||||
/* stats */
|
||||
--stats-font-size: 11px;
|
||||
|
||||
@@ -148,14 +148,23 @@ const Board = () => {
|
||||
newerThan: 60 * 60 * 24 * 30,
|
||||
filter: hideThreadsWithoutImages ? createThreadsWithoutImagesFilter() : undefined,
|
||||
});
|
||||
const { feed: yearlyFeed } = useFeed({
|
||||
subplebbitAddresses,
|
||||
sortType,
|
||||
newerThan: 60 * 60 * 24 * 365,
|
||||
filter: hideThreadsWithoutImages ? createThreadsWithoutImagesFilter() : undefined,
|
||||
});
|
||||
|
||||
const feedLength = feed.length;
|
||||
const weeklyFeedLength = weeklyFeed.length;
|
||||
const monthlyFeedLength = monthlyFeed.length;
|
||||
const yearlyFeedLength = yearlyFeed.length;
|
||||
const hasFeedLoaded = !!feed;
|
||||
const loadingStateString =
|
||||
useFeedStateString(subplebbitAddresses) ||
|
||||
(!hasFeedLoaded || (feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength)) ? t('loading_feed') : t('looking_for_more_posts'));
|
||||
(!hasFeedLoaded || (feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength))
|
||||
? t('loading_feed')
|
||||
: t('looking_for_more_posts'));
|
||||
|
||||
const [showMorePostsSuggestion, setShowMorePostsSuggestion] = useState(false);
|
||||
useEffect(() => {
|
||||
@@ -189,9 +198,9 @@ const Board = () => {
|
||||
) : (
|
||||
(isInAllView || isInSubscriptionsView || isInModView) &&
|
||||
showMorePostsSuggestion &&
|
||||
monthlyFeed.length > feed.length &&
|
||||
(monthlyFeed.length > feed.length || yearlyFeed.length > monthlyFeed.length) &&
|
||||
(() => {
|
||||
const basePath = isInAllView ? '/all' : isInSubscriptionsView ? '/subscriptions' : isInModView ? '/mod' : boardPath ? `/${boardPath}` : '';
|
||||
const basePath = isInAllView ? '/all' : isInSubscriptionsView ? '/subs' : isInModView ? '/mod' : boardPath ? `/${boardPath}` : '';
|
||||
return weeklyFeed.length > feed.length ? (
|
||||
<div className={styles.morePostsSuggestion}>
|
||||
<Trans
|
||||
@@ -202,7 +211,7 @@ const Board = () => {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
) : monthlyFeed.length > feed.length ? (
|
||||
<div className={styles.morePostsSuggestion}>
|
||||
<Trans
|
||||
i18nKey='more_threads_last_month'
|
||||
@@ -212,6 +221,16 @@ const Board = () => {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.morePostsSuggestion}>
|
||||
<Trans
|
||||
i18nKey='more_threads_last_year'
|
||||
values={{ currentTimeFilterName, count: feed.length }}
|
||||
components={{
|
||||
1: <Link to={`${basePath}/1y`} />,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})()
|
||||
)}
|
||||
|
||||
@@ -285,6 +285,13 @@ const Catalog = () => {
|
||||
filter: createCombinedFilter(showTextOnlyThreads, filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
|
||||
});
|
||||
|
||||
const { feed: yearlyFeed } = useFeed({
|
||||
subplebbitAddresses,
|
||||
sortType,
|
||||
newerThan: 60 * 60 * 24 * 365,
|
||||
filter: createCombinedFilter(showTextOnlyThreads, filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
|
||||
});
|
||||
|
||||
const [showMorePostsSuggestion, setShowMorePostsSuggestion] = useState(false);
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
@@ -306,9 +313,12 @@ const Catalog = () => {
|
||||
const feedLength = feed.length;
|
||||
const weeklyFeedLength = weeklyFeed.length;
|
||||
const monthlyFeedLength = monthlyFeed.length;
|
||||
const yearlyFeedLength = yearlyFeed.length;
|
||||
const hasFeedLoaded = !!feed;
|
||||
const loadingStateString =
|
||||
useFeedStateString(subplebbitAddresses) || !hasFeedLoaded || (feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength))
|
||||
useFeedStateString(subplebbitAddresses) ||
|
||||
!hasFeedLoaded ||
|
||||
(feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength))
|
||||
? t('loading_feed')
|
||||
: t('looking_for_more_posts');
|
||||
|
||||
@@ -317,7 +327,7 @@ const Catalog = () => {
|
||||
{state === 'failed' ? (
|
||||
<span className='red'>{state}</span>
|
||||
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
|
||||
t('not_subscribed_to_any_board')
|
||||
<span className='red'>{t('not_subscribed_to_any_board')}</span>
|
||||
) : blocked ? (
|
||||
t('you_have_blocked_this_board')
|
||||
) : !hasMore && combinedFeed.length === 0 ? (
|
||||
@@ -361,24 +371,34 @@ const Catalog = () => {
|
||||
) : (
|
||||
(isInAllView || isInSubscriptionsView) &&
|
||||
showMorePostsSuggestion &&
|
||||
monthlyFeed.length > feed.length &&
|
||||
(monthlyFeed.length > feed.length || yearlyFeed.length > monthlyFeed.length) &&
|
||||
(weeklyFeed.length > feed.length ? (
|
||||
<div className={styles.stateString}>
|
||||
<Trans
|
||||
i18nKey='more_threads_last_week'
|
||||
values={{ currentTimeFilterName, count: feed.length }}
|
||||
components={{
|
||||
1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subscriptions/catalog' : `/${boardPath}/catalog`) + '/1w'} />,
|
||||
1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : `/${boardPath}/catalog`) + '/1w'} />,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : monthlyFeed.length > feed.length ? (
|
||||
<div className={styles.stateString}>
|
||||
<Trans
|
||||
i18nKey='more_threads_last_month'
|
||||
values={{ currentTimeFilterName, count: feed.length }}
|
||||
components={{
|
||||
1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : `/${boardPath}/catalog`) + '/1m'} />,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.stateString}>
|
||||
<Trans
|
||||
i18nKey='more_threads_last_month'
|
||||
i18nKey='more_threads_last_year'
|
||||
values={{ currentTimeFilterName, count: feed.length }}
|
||||
components={{
|
||||
1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subscriptions/catalog' : `/${boardPath}/catalog`) + '/1m'} />,
|
||||
1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : `/${boardPath}/catalog`) + '/1y'} />,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -101,6 +101,7 @@ const BoardsList = ({ multisub }: { multisub: MultisubSubplebbit[] }) => {
|
||||
const showOther = showAll || showWorksafeOnly;
|
||||
const showMisc = showAll || showNsfwOnly;
|
||||
const showAdult = showAll || showNsfwOnly;
|
||||
const showMultiboards = showAll || showNsfwOnly;
|
||||
|
||||
return (
|
||||
<div className={styles.box}>
|
||||
@@ -603,6 +604,22 @@ const BoardsList = ({ multisub }: { multisub: MultisubSubplebbit[] }) => {
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Column 6: Meta */}
|
||||
{showMultiboards && (
|
||||
<div className={styles.boardsColumn}>
|
||||
<h3>Multiboards</h3>
|
||||
<NSFWBadge />
|
||||
<ul>
|
||||
<li>
|
||||
<Link to='/all'>All 5chan Directories</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to='/subs'>Subscriptions</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -343,6 +343,14 @@
|
||||
color: var(--homepage-infobox-link-text-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.boardsColumn li {
|
||||
padding: 5px 10px 5px 0;
|
||||
}
|
||||
|
||||
.boardsColumn a {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||