mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
@@ -164,8 +164,8 @@
|
||||
"creation_date": "تاريخ الإنشاء",
|
||||
"sort_by": "ترتيب حسب",
|
||||
"time_filter": "تصفية الوقت",
|
||||
"subplebbit_offline_info": "قد يكون الرد على الرسائل غير متاح حالياً وقد تفشل النشر.",
|
||||
"posts_last_synced_info": "آخر تزامن الرسائل {{time}}، قد يكون الرد على الرسائل غير متاح حالياً وقد تفشل النشر.",
|
||||
"subplebbit_offline_info": "قد يكون المنتدى غير متصل وقد تفشل النشر",
|
||||
"posts_last_synced_info": "آخر المشاركات تم مزامنتها {{time}} ، قد يكون المنتدى غير متصل وقد تفشل النشر.",
|
||||
"newer_than": "أحدث من",
|
||||
"no_threads": "لا توجد مواضيع",
|
||||
"unblock": "إلغاء الحظر",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "إحصائيات العقدة",
|
||||
"loading_default_boards": "جار تحميل قائمة اللوحات الافتراضية",
|
||||
"loading_subscriptions": "جارٍ تحميل الاشتراكات",
|
||||
"create_board": "إنشاء لوحة"
|
||||
"create_board": "إنشاء لوحة",
|
||||
"enter_board_address": "أدخل عنوان أي لوحة",
|
||||
"board_not_reachable": "اللوحة غير قابلة للوصول"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "তৈরি তারিখ",
|
||||
"sort_by": "দ্বারা বাছাই করুন",
|
||||
"time_filter": "সময় ফিল্টার",
|
||||
"subplebbit_offline_info": "সাবপ্লেবিট অফলাইন হতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে।",
|
||||
"posts_last_synced_info": "পোস্টগুলি সর্বশেষ সিঙ্ক হয়েছে {{time}}, সাবপ্লেবিট অফলাইন হতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে।",
|
||||
"subplebbit_offline_info": "বোর্ডটি অফলাইন থাকতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে",
|
||||
"posts_last_synced_info": "সর্বশেষ পোস্টগুলি {{time}} সময় সিঙ্ক করা হয়েছে, বোর্ডটি অফলাইনে থাকতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে।",
|
||||
"newer_than": "নতুন পরে",
|
||||
"no_threads": "কোন থ্রেড নেই",
|
||||
"unblock": "অনবন্ধ করুন",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "নোড পরিসংখ্যান",
|
||||
"loading_default_boards": "ডিফল্ট বোর্ড তালিকা লোড হচ্ছে",
|
||||
"loading_subscriptions": "সাবস্ক্রিপশন লোড হচ্ছে",
|
||||
"create_board": "বোর্ড তৈরি করুন"
|
||||
"create_board": "বোর্ড তৈরি করুন",
|
||||
"enter_board_address": "যেকোনো বোর্ডের ঠিকানা লিখুন",
|
||||
"board_not_reachable": "বোর্ডটি অ্যাক্সেসযোগ্য নয়"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Datum vytvoření",
|
||||
"sort_by": "Řadit podle",
|
||||
"time_filter": "Filtr času",
|
||||
"subplebbit_offline_info": "Subplebbit může být offline a zveřejnění může selhat.",
|
||||
"posts_last_synced_info": "Poslední synchronizace příspěvků {{time}}, subplebbit může být offline a zveřejňování může selhat.",
|
||||
"subplebbit_offline_info": "Deska může být offline a publikování může selhat",
|
||||
"posts_last_synced_info": "Poslední příspěvky synchronizovány {{time}}, deska může být offline a publikování může selhat.",
|
||||
"newer_than": "novější než",
|
||||
"no_threads": "Žádná témata",
|
||||
"unblock": "Odblokovat",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Statistiky uzlu",
|
||||
"loading_default_boards": "Načítání seznamu výchozích tabulí",
|
||||
"loading_subscriptions": "Načítání odběrů",
|
||||
"create_board": "Vytvořit desku"
|
||||
"create_board": "Vytvořit desku",
|
||||
"enter_board_address": "Zadejte adresu libovolné desky",
|
||||
"board_not_reachable": "Deska není dostupná"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Oprettelsesdato",
|
||||
"sort_by": "Sorter efter",
|
||||
"time_filter": "Tidsfilter",
|
||||
"subplebbit_offline_info": "Subplebbiten kan være offline, og offentliggørelse kan mislykkes.",
|
||||
"posts_last_synced_info": "Seneste synkroniserede indlæg {{time}}, subplebbiten kan være offline, og offentliggørelse kan mislykkes.",
|
||||
"subplebbit_offline_info": "Boardet kan være offline, og offentliggørelse kan mislykkes",
|
||||
"posts_last_synced_info": "Sidste indlæg synkroniseret {{time}}, tavlen kan være offline og offentliggørelse kan fejle.",
|
||||
"newer_than": "nyere end",
|
||||
"no_threads": "Ingen tråde",
|
||||
"unblock": "Fjern blokering",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Node-statistik",
|
||||
"loading_default_boards": "Indlæser standard tavleliste",
|
||||
"loading_subscriptions": "Indlæser abonnementer",
|
||||
"create_board": "Opret tavle"
|
||||
"create_board": "Opret tavle",
|
||||
"enter_board_address": "Indtast enhver tavleadresse",
|
||||
"board_not_reachable": "Boardet er ikke tilgængeligt"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Erstellungsdatum",
|
||||
"sort_by": "Sortieren nach",
|
||||
"time_filter": "Zeitfilter",
|
||||
"subplebbit_offline_info": "Der Subplebbit könnte offline sein und das Veröffentlichen könnte fehlschlagen.",
|
||||
"posts_last_synced_info": "Beiträge zuletzt synchronisiert {{time}}, der Subplebbit könnte offline sein und das Veröffentlichen könnte fehlschlagen.",
|
||||
"subplebbit_offline_info": "Das Board könnte offline sein und die Veröffentlichung könnte fehlschlagen",
|
||||
"posts_last_synced_info": "Letzte Beiträge synchronisiert {{time}}, das Board könnte offline sein und das Veröffentlichen könnte fehlschlagen.",
|
||||
"newer_than": "neuer als",
|
||||
"no_threads": "Keine Threads",
|
||||
"unblock": "Entsperren",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Knotenstatistiken",
|
||||
"loading_default_boards": "Laden der Standard-Boards-Liste",
|
||||
"loading_subscriptions": "Lade Abonnements",
|
||||
"create_board": "Board erstellen"
|
||||
"create_board": "Board erstellen",
|
||||
"enter_board_address": "Geben Sie eine beliebige Board-Adresse ein",
|
||||
"board_not_reachable": "Board ist nicht erreichbar"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Ημερομηνία δημιουργίας",
|
||||
"sort_by": "Ταξινόμηση κατά",
|
||||
"time_filter": "Φίλτρο χρόνου",
|
||||
"subplebbit_offline_info": "Το subplebbit ενδέχεται να είναι εκτός σύνδεσης και η δημοσίευση μπορεί να αποτύχει.",
|
||||
"posts_last_synced_info": "Τελευταία συγχρονισμένες αναρτήσεις {{time}}, το subplebbit ενδέχεται να είναι εκτός σύνδεσης και η δημοσίευση μπορεί να αποτύχει.",
|
||||
"subplebbit_offline_info": "Η φόρουμ μπορεί να είναι εκτός σύνδεσης και η δημοσίευση ενδέχεται να αποτύχει",
|
||||
"posts_last_synced_info": "Τελευταία δημοσιεύματα συγχρονίστηκαν {{time}}, το φόρουμ μπορεί να είναι εκτός σύνδεσης και η δημοσίευση μπορεί να αποτύχει.",
|
||||
"newer_than": "πιο πρόσφατο από",
|
||||
"no_threads": "Δεν υπάρχουν θέματα",
|
||||
"unblock": "Ξεκλείδωμα",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Στατιστικά κόμβου",
|
||||
"loading_default_boards": "Φόρτωση της λίστας προεπιλεγμένων πάνελ",
|
||||
"loading_subscriptions": "Φορτώνει συνδρομές",
|
||||
"create_board": "Δημιουργία πίνακα"
|
||||
"create_board": "Δημιουργία πίνακα",
|
||||
"enter_board_address": "Εισάγετε οποιαδήποτε διεύθυνση πίνακα",
|
||||
"board_not_reachable": "Ο πίνακας δεν είναι προσβάσιμος"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Creation date",
|
||||
"sort_by": "Sort by",
|
||||
"time_filter": "Time Filter",
|
||||
"subplebbit_offline_info": "The subplebbit might be offline and publishing might fail.",
|
||||
"posts_last_synced_info": "Posts last synced {{time}}, the subplebbit might be offline and publishing might fail.",
|
||||
"subplebbit_offline_info": "The board might be offline and publishing might fail",
|
||||
"posts_last_synced_info": "Posts last synced {{time}}, the board might be offline and publishing might fail.",
|
||||
"newer_than": "newer than",
|
||||
"no_threads": "No threads",
|
||||
"unblock": "Unblock",
|
||||
@@ -237,8 +237,8 @@
|
||||
"no_board_selected_warning": "Please select a board before posting.",
|
||||
"invalid_url_alert": "The provided link is not a valid URL.",
|
||||
"empty_comment_alert": "Cannot post empty comment.",
|
||||
"more_threads_last_week": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show more threads from last week</1>]",
|
||||
"more_threads_last_month": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show more threads from last month</1>]",
|
||||
"more_threads_last_week": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show More Threads from Last Week</1>]",
|
||||
"more_threads_last_month": "{{count}} threads since {{currentTimeFilterName}} — [<1>Show More Threads from Last Month</1>]",
|
||||
"newer_threads_available": "Newer threads available — [<1>Refresh</1>]",
|
||||
"stored_locally": "Stored locally ({{location}}), not synced across devices",
|
||||
"choose_one": "Choose one:",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Node stats",
|
||||
"loading_default_boards": "Loading default boards list",
|
||||
"loading_subscriptions": "Loading subscriptions",
|
||||
"create_board": "Create Board"
|
||||
"create_board": "Create Board",
|
||||
"enter_board_address": "Enter any board address",
|
||||
"board_not_reachable": "Board is not reachable"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Fecha de creación",
|
||||
"sort_by": "Ordenar por",
|
||||
"time_filter": "Filtro de tiempo",
|
||||
"subplebbit_offline_info": "El subplebbit podría estar fuera de línea y la publicación podría fallar.",
|
||||
"posts_last_synced_info": "Últimas publicaciones sincronizadas {{time}}, el subplebbit podría estar fuera de línea y la publicación podría fallar.",
|
||||
"subplebbit_offline_info": "El tablero podría estar fuera de línea y la publicación podría fallar",
|
||||
"posts_last_synced_info": "Últimas publicaciones sincronizadas {{time}}, el tablero podría estar fuera de línea y la publicación podría fallar.",
|
||||
"newer_than": "más reciente que",
|
||||
"no_threads": "No hay hilos",
|
||||
"unblock": "Desbloquear",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Estadísticas del nodo",
|
||||
"loading_default_boards": "Cargando lista de tableros predeterminados",
|
||||
"loading_subscriptions": "Cargando suscripciones",
|
||||
"create_board": "Crear tablero"
|
||||
"create_board": "Crear tablero",
|
||||
"enter_board_address": "Ingrese cualquier dirección de tablero",
|
||||
"board_not_reachable": "El tablero no es accesible"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "تاریخ ایجاد",
|
||||
"sort_by": "مرتبسازی بر اساس",
|
||||
"time_filter": "فیلتر زمانی",
|
||||
"subplebbit_offline_info": "زیرپلبیت ممکن است آفلاین باشد و انتشار ممکن است شکست خورده باشد.",
|
||||
"posts_last_synced_info": "آخرین پستها همگامسازی شدهاند {{time}}، زیرپلبیت ممکن است آفلاین باشد و انتشار ممکن است شکست خورده باشد.",
|
||||
"subplebbit_offline_info": "تابلو ممکن است آفلاین باشد و انتشار ممکن است شکست بخورد",
|
||||
"posts_last_synced_info": "آخرین پستها همگامسازی شد {{time}} ، ممکن است انجمن آفلاین باشد و انتشار ممکن است شکست بخورد.",
|
||||
"newer_than": "جدیدتر از",
|
||||
"no_threads": "هیچ موضوعی وجود ندارد",
|
||||
"unblock": "رفع مسدودیت",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "آمار گره",
|
||||
"loading_default_boards": "در حال بارگذاری فهرست تختههای پیشفرض",
|
||||
"loading_subscriptions": "در حال بارگذاری اشتراکها",
|
||||
"create_board": "ایجاد تابلو"
|
||||
"create_board": "ایجاد تابلو",
|
||||
"enter_board_address": "آدرس هر تابلو را وارد کنید",
|
||||
"board_not_reachable": "تابلو قابل دسترسی نیست"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Luomispäivämäärä",
|
||||
"sort_by": "Järjestä",
|
||||
"time_filter": "Aikasuodatin",
|
||||
"subplebbit_offline_info": "Subplebbit voi olla offline-tilassa, ja julkaisu voi epäonnistua.",
|
||||
"posts_last_synced_info": "Viimeksi synkronoidut viestit {{time}}, subplebbit voi olla offline-tilassa, ja julkaisu voi epäonnistua.",
|
||||
"subplebbit_offline_info": "Taulu voi olla offline-tilassa ja julkaiseminen voi epäonnistua",
|
||||
"posts_last_synced_info": "Viimeisimmät julkaisut synkronoitu {{time}}, taulu saattaa olla offline-tilassa ja julkaiseminen saattaa epäonnistua.",
|
||||
"newer_than": "uudempi kuin",
|
||||
"no_threads": "Ei ketjuja",
|
||||
"unblock": "Poista estäminen",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Solmun tilastot",
|
||||
"loading_default_boards": "Ladataan oletuslautalistaa",
|
||||
"loading_subscriptions": "Ladataan tilauksia",
|
||||
"create_board": "Luo taulu"
|
||||
"create_board": "Luo taulu",
|
||||
"enter_board_address": "Syötä mikä tahansa taulun osoite",
|
||||
"board_not_reachable": "Taulua ei ole käytettävissä"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Petsa ng Paglikha",
|
||||
"sort_by": "Ayusin ayon sa",
|
||||
"time_filter": "Time Filter",
|
||||
"subplebbit_offline_info": "Maaaring offline ang subplebbit at maaaring mabigo ang paglalathala.",
|
||||
"posts_last_synced_info": "Huling naka-sync na mga post {{time}}, maaaring offline ang subplebbit at maaaring mabigo ang paglalathala.",
|
||||
"subplebbit_offline_info": "Maaaring offline ang board at maaaring mabigo ang pag-publish",
|
||||
"posts_last_synced_info": "Huling na-sync na mga post {{time}}, maaaring offline ang board at maaaring mabigo ang pag-publish.",
|
||||
"newer_than": "mas bago kaysa",
|
||||
"no_threads": "Walang mga thread",
|
||||
"unblock": "I-unblock",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Istatistika ng node",
|
||||
"loading_default_boards": "Naglo-load ng default na listahan ng mga board",
|
||||
"loading_subscriptions": "Naglo-load ng mga subscription",
|
||||
"create_board": "Gumawa ng board"
|
||||
"create_board": "Gumawa ng board",
|
||||
"enter_board_address": "Ipasok ang anumang address ng board",
|
||||
"board_not_reachable": "Hindi maa-access ang board"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Date de création",
|
||||
"sort_by": "Trier par",
|
||||
"time_filter": "Filtre temporel",
|
||||
"subplebbit_offline_info": "Le subplebbit pourrait être hors ligne et la publication pourrait échouer.",
|
||||
"posts_last_synced_info": "Dernières publications synchronisées {{time}}, le subplebbit pourrait être hors ligne et la publication pourrait échouer.",
|
||||
"subplebbit_offline_info": "Le forum pourrait être hors ligne et la publication pourrait échouer",
|
||||
"posts_last_synced_info": "Derniers messages synchronisés {{time}}, le forum pourrait être hors ligne et la publication pourrait échouer.",
|
||||
"newer_than": "plus récent que",
|
||||
"no_threads": "Pas de fils",
|
||||
"unblock": "Débloquer",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Statistiques du nœud",
|
||||
"loading_default_boards": "Chargement de la liste des panneaux par défaut",
|
||||
"loading_subscriptions": "Chargement des abonnements",
|
||||
"create_board": "Créer un tableau"
|
||||
"create_board": "Créer un tableau",
|
||||
"enter_board_address": "Entrez n'importe quelle adresse du forum",
|
||||
"board_not_reachable": "Le tableau n'est pas accessible"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "תאריך יצירה",
|
||||
"sort_by": "מיין לפי",
|
||||
"time_filter": "סינון זמן",
|
||||
"subplebbit_offline_info": "הסאבפלביט עשוי להיות לא מקוון והפרסום עשוי להכשל.",
|
||||
"posts_last_synced_info": "הפוסטים סונכרנו לאחרונה {{time}}, הסאבפלביט עשוי להיות לא מקוון והפרסום עשוי להכשל.",
|
||||
"subplebbit_offline_info": "הפורום עשוי להיות לא זמין וייתכן שפרסום ייכשל",
|
||||
"posts_last_synced_info": "הפוסטים סונכרנו לאחרונה {{time}}, ייתכן שהפורום לא זמין ופרסום עשוי להיכשל.",
|
||||
"newer_than": "חדש יותר מ",
|
||||
"no_threads": "אין נושאים",
|
||||
"unblock": "בטל חסימה",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "סטטיסטיקות צומת",
|
||||
"loading_default_boards": "טוען את רשימת הלוחות ברירת המחדל",
|
||||
"loading_subscriptions": "טוען מנויים",
|
||||
"create_board": "צור לוח"
|
||||
"create_board": "צור לוח",
|
||||
"enter_board_address": "הזן כתובת לוח כלשהי",
|
||||
"board_not_reachable": "הלוח לא נגיש"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "निर्माण तिथि",
|
||||
"sort_by": "क्रमबद्ध करें द्वारा",
|
||||
"time_filter": "समय फ़िल्टर",
|
||||
"subplebbit_offline_info": "सबप्लेबिट ऑफलाइन हो सकता है और प्रकाशन विफल हो सकता है।",
|
||||
"posts_last_synced_info": "आखिरी बार सिंक की गई पोस्ट {{time}}, सबप्लेबिट ऑफलाइन हो सकता है और प्रकाशन विफल हो सकता है।",
|
||||
"subplebbit_offline_info": "बोर्ड ऑफ़लाइन हो सकता है और प्रकाशन विफल हो सकता है",
|
||||
"posts_last_synced_info": "पोस्ट्स अंतिम बार सिंक किए गए {{time}}, बोर्ड ऑफलाइन हो सकता है और प्रकाशन विफल हो सकता है।",
|
||||
"newer_than": "से नई",
|
||||
"no_threads": "कोई थ्रेड नहीं है",
|
||||
"unblock": "अनब्लॉक",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "नोड आँकड़े",
|
||||
"loading_default_boards": "डिफ़ॉल्ट बोर्ड सूची लोड हो रही है",
|
||||
"loading_subscriptions": "सब्सक्रिप्शन लोड हो रहे हैं",
|
||||
"create_board": "बोर्ड बनाएं"
|
||||
"create_board": "बोर्ड बनाएं",
|
||||
"enter_board_address": "किसी भी बोर्ड का पता दर्ज करें",
|
||||
"board_not_reachable": "बोर्ड पहुँच योग्य नहीं है"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Létrehozás dátuma",
|
||||
"sort_by": "Rendezés",
|
||||
"time_filter": "Idő szűrő",
|
||||
"subplebbit_offline_info": "A subplebbit offline lehet, és a közzététel sikertelen lehet.",
|
||||
"posts_last_synced_info": "Legutóbb szinkronizált bejegyzések {{time}}, a subplebbit offline lehet, és a közzététel sikertelen lehet.",
|
||||
"subplebbit_offline_info": "A tábla offline lehet, és a közzététel sikertelen lehet",
|
||||
"posts_last_synced_info": "Legutóbbi bejegyzések szinkronizálva {{time}}, a tábla offline lehet, és a közzététel sikertelen lehet.",
|
||||
"newer_than": "újabb, mint",
|
||||
"no_threads": "Nincsenek témák",
|
||||
"unblock": "Blokkolás feloldása",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Csomópont statisztikák",
|
||||
"loading_default_boards": "Alapértelmezett táblák listájának betöltése",
|
||||
"loading_subscriptions": "Előfizetések betöltése",
|
||||
"create_board": "Hozzon létre táblát"
|
||||
"create_board": "Hozzon létre táblát",
|
||||
"enter_board_address": "Adjon meg bármilyen táblázat címet",
|
||||
"board_not_reachable": "A tábla nem elérhető"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Tanggal pembuatan",
|
||||
"sort_by": "Urutkan berdasarkan",
|
||||
"time_filter": "Filter Waktu",
|
||||
"subplebbit_offline_info": "Subplebbit mungkin offline dan penerbitan mungkin gagal.",
|
||||
"posts_last_synced_info": "Posting terakhir disinkronkan {{time}}, subplebbit mungkin offline dan penerbitan mungkin gagal.",
|
||||
"subplebbit_offline_info": "Papan bisa jadi offline dan publikasi bisa gagal",
|
||||
"posts_last_synced_info": "Posting terakhir disinkronkan {{time}}, papan mungkin offline dan publikasi bisa gagal.",
|
||||
"newer_than": "baru daripada",
|
||||
"no_threads": "Tidak ada thread",
|
||||
"unblock": "Buka blokir",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Statistik node",
|
||||
"loading_default_boards": "Memuat daftar papan default",
|
||||
"loading_subscriptions": "Memuat langganan",
|
||||
"create_board": "Buat papan"
|
||||
"create_board": "Buat papan",
|
||||
"enter_board_address": "Masukkan alamat papan apa saja",
|
||||
"board_not_reachable": "Papan tidak dapat dijangkau"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Data di creazione",
|
||||
"sort_by": "Ordina per",
|
||||
"time_filter": "Filtro temporale",
|
||||
"subplebbit_offline_info": "Il subplebbit potrebbe essere offline e la pubblicazione potrebbe fallire.",
|
||||
"posts_last_synced_info": "Ultimi post sincronizzati {{time}}, il subplebbit potrebbe essere offline e la pubblicazione potrebbe fallire.",
|
||||
"subplebbit_offline_info": "La board potrebbe essere offline e la pubblicazione potrebbe fallire",
|
||||
"posts_last_synced_info": "Ultimi post sincronizzati {{time}}, la board potrebbe essere offline e la pubblicazione potrebbe fallire.",
|
||||
"newer_than": "più recente di",
|
||||
"no_threads": "Nessun thread",
|
||||
"unblock": "Sblocca",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Statistiche del nodo",
|
||||
"loading_default_boards": "Caricamento della lista delle board predefinite",
|
||||
"loading_subscriptions": "Caricamento abbonamenti",
|
||||
"create_board": "Crea Board"
|
||||
"create_board": "Crea Board",
|
||||
"enter_board_address": "Inserisci indirizzo di qualsiasi board",
|
||||
"board_not_reachable": "Board non raggiungibile"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "作成日",
|
||||
"sort_by": "並べ替え",
|
||||
"time_filter": "時間フィルター",
|
||||
"subplebbit_offline_info": "サブプレビットがオフラインになっている可能性があり、公開が失敗することがあります。",
|
||||
"posts_last_synced_info": "最後に同期された投稿 {{time}}, サブプレビットがオフラインになっている可能性があり、公開が失敗することがあります。",
|
||||
"subplebbit_offline_info": "ボードはオフラインの可能性があり、公開が失敗する可能性があります",
|
||||
"posts_last_synced_info": "最後に同期された投稿 {{time}}、ボードはオフラインの可能性があり、公開に失敗する可能性があります。",
|
||||
"newer_than": "より新しい",
|
||||
"no_threads": "スレッドはありません",
|
||||
"unblock": "ブロック解除",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "ノード統計",
|
||||
"loading_default_boards": "デフォルトのボードリストを読み込み中",
|
||||
"loading_subscriptions": "購読を読み込み中",
|
||||
"create_board": "ボードを作成"
|
||||
"create_board": "ボードを作成",
|
||||
"enter_board_address": "任意のボードアドレスを入力してください",
|
||||
"board_not_reachable": "ボードにアクセスできません"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "작성 날짜",
|
||||
"sort_by": "정렬 기준",
|
||||
"time_filter": "시간 필터",
|
||||
"subplebbit_offline_info": "서브플레빗이 오프라인 일 수 있으며 게시가 실패할 수 있습니다.",
|
||||
"posts_last_synced_info": "최근 동기화된 게시물 {{time}}, 서브플레빗이 오프라인 일 수 있으며 게시가 실패할 수 있습니다.",
|
||||
"subplebbit_offline_info": "보드가 오프라인일 수 있으며 게시물이 실패할 수 있습니다",
|
||||
"posts_last_synced_info": "마지막으로 동기화된 게시물 {{time}}, 게시판이 오프라인일 수 있으며 게시물이 실패할 수 있습니다.",
|
||||
"newer_than": "이전보다 최신",
|
||||
"no_threads": "스레드가 없습니다",
|
||||
"unblock": "차단 해제",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "노드 통계",
|
||||
"loading_default_boards": "기본 보드 목록을 로드 중",
|
||||
"loading_subscriptions": "구독 로딩 중",
|
||||
"create_board": "보드 만들기"
|
||||
"create_board": "보드 만들기",
|
||||
"enter_board_address": "어떤 보드 주소든 입력하세요",
|
||||
"board_not_reachable": "보드를 찾을 수 없습니다"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "निर्माण तारीख",
|
||||
"sort_by": "क्रमवार करा",
|
||||
"time_filter": "वेळ फिल्टर",
|
||||
"subplebbit_offline_info": "सबप्लेबिट मोबाइल असून प्रकाशन अयशस्वी होऊ शकतो.",
|
||||
"posts_last_synced_info": "शेवटच्या बारीस सिन्क केलेले पोस्ट {{time}}, सबप्लेबिट मोबाइल असून प्रकाशन अयशस्वी होऊ शकतो.",
|
||||
"subplebbit_offline_info": "बोर्ड ऑफलाइन असू शकतो आणि प्रकाशित करणे अयशस्वी होऊ शकते",
|
||||
"posts_last_synced_info": "शेवटचे पोस्ट सिंक्रनाइज केले {{time}}, बोर्ड ऑफलाइन असू शकतो आणि प्रकाशन अयशस्वी होऊ शकते.",
|
||||
"newer_than": "नवीनतम आहे",
|
||||
"no_threads": "कोणतेही थ्रेड्स नाहीत",
|
||||
"unblock": "ब्लॉक सोडा",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "नोड आकडेवारी",
|
||||
"loading_default_boards": "डीफॉल्ट बोर्ड यादी लोड करत आहे",
|
||||
"loading_subscriptions": "सदस्यता लोड होत आहे",
|
||||
"create_board": "बोर्ड तयार करा"
|
||||
"create_board": "बोर्ड तयार करा",
|
||||
"enter_board_address": "कोणत्याही बोर्ड पत्त्याची नोंद करा",
|
||||
"board_not_reachable": "बोर्ड उपलब्ध नाही"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Creatiedatum",
|
||||
"sort_by": "Sorteer op",
|
||||
"time_filter": "Tijdsfilter",
|
||||
"subplebbit_offline_info": "De subplebbit kan offline zijn en publiceren kan mislukken.",
|
||||
"posts_last_synced_info": "Laatste keer gesynchroniseerde berichten {{time}}, de subplebbit kan offline zijn en publiceren kan mislukken.",
|
||||
"subplebbit_offline_info": "Het bord kan offline zijn en publicatie kan mislukken",
|
||||
"posts_last_synced_info": "Laatste berichten gesynchroniseerd {{time}}, het bord is mogelijk offline en publiceren kan mislukken.",
|
||||
"newer_than": "nieuwer dan",
|
||||
"no_threads": "Geen threads",
|
||||
"unblock": "Deblokkeren",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Node-statistieken",
|
||||
"loading_default_boards": "Laden van de standaard boardlijst",
|
||||
"loading_subscriptions": "Abonnementen laden",
|
||||
"create_board": "Maak bord"
|
||||
"create_board": "Maak bord",
|
||||
"enter_board_address": "Voer een willekeurig bordadres in",
|
||||
"board_not_reachable": "Bord is niet bereikbaar"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Opprettelsesdato",
|
||||
"sort_by": "Sorter etter",
|
||||
"time_filter": "Tidsfilter",
|
||||
"subplebbit_offline_info": "Subplebbiten kan være offline, og publisering kan mislykkes.",
|
||||
"posts_last_synced_info": "Siste synkroniserte innlegg {{time}}, subplebbiten kan være offline, og publisering kan mislykkes.",
|
||||
"subplebbit_offline_info": "Brettet kan være offline, og publisering kan mislykkes",
|
||||
"posts_last_synced_info": "Siste innlegg synkronisert {{time}}, tavlen kan være offline og publisering kan feile.",
|
||||
"newer_than": "nyere enn",
|
||||
"no_threads": "Ingen tråder",
|
||||
"unblock": "Fjern blokkering",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Node-statistikk",
|
||||
"loading_default_boards": "Laster standard tavleliste",
|
||||
"loading_subscriptions": "Laster abonnementer",
|
||||
"create_board": "Lag tavle"
|
||||
"create_board": "Lag tavle",
|
||||
"enter_board_address": "Skriv inn hvilken som helst brettadresse",
|
||||
"board_not_reachable": "Brettet er ikke tilgjengelig"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Data utworzenia",
|
||||
"sort_by": "Sortuj według",
|
||||
"time_filter": "Filtr czasu",
|
||||
"subplebbit_offline_info": "Subplebbit może być offline, a publikacja może się nie powieść.",
|
||||
"posts_last_synced_info": "Ostatnio zsynchronizowane posty {{time}}, subplebbit może być offline, a publikacja może się nie powieść.",
|
||||
"subplebbit_offline_info": "Tablica może być offline, a publikacja może nie udać się",
|
||||
"posts_last_synced_info": "Ostatnie posty zsynchronizowane {{time}}, tablica może być offline, a publikacja może nie powieść się.",
|
||||
"newer_than": "nowsze niż",
|
||||
"no_threads": "Brak wątków",
|
||||
"unblock": "Odblokuj",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Statystyki węzła",
|
||||
"loading_default_boards": "Ładowanie domyślnej listy tablic",
|
||||
"loading_subscriptions": "Ładowanie subskrypcji",
|
||||
"create_board": "Utwórz tablicę"
|
||||
"create_board": "Utwórz tablicę",
|
||||
"enter_board_address": "Wprowadź dowolny adres tablicy",
|
||||
"board_not_reachable": "Tablica jest niedostępna"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Data de criação",
|
||||
"sort_by": "Ordenar por",
|
||||
"time_filter": "Filtro de tempo",
|
||||
"subplebbit_offline_info": "O subplebbit pode estar offline e a publicação pode falhar.",
|
||||
"posts_last_synced_info": "Posts sincronizados pela última vez {{time}}, o subplebbit pode estar offline e a publicação pode falhar.",
|
||||
"subplebbit_offline_info": "O quadro pode estar offline e a publicação pode falhar",
|
||||
"posts_last_synced_info": "Últimas postagens sincronizadas {{time}}, o quadro pode estar offline e a publicação pode falhar.",
|
||||
"newer_than": "mais recente que",
|
||||
"no_threads": "Sem tópicos",
|
||||
"unblock": "Desbloquear",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Estatísticas do nó",
|
||||
"loading_default_boards": "Carregando lista de quadros padrão",
|
||||
"loading_subscriptions": "Carregando assinaturas",
|
||||
"create_board": "Criar quadro"
|
||||
"create_board": "Criar quadro",
|
||||
"enter_board_address": "Digite qualquer endereço de quadro",
|
||||
"board_not_reachable": "O quadro não é acessível"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Data de creare",
|
||||
"sort_by": "Sortează după",
|
||||
"time_filter": "Filtru de timp",
|
||||
"subplebbit_offline_info": "Subplebbitul ar putea fi offline și publicarea ar putea eșua.",
|
||||
"posts_last_synced_info": "Ultimele postări sincronizate {{time}}, subplebbitul ar putea fi offline și publicarea ar putea eșua.",
|
||||
"subplebbit_offline_info": "Tabloul ar putea fi offline și publicarea ar putea eșua",
|
||||
"posts_last_synced_info": "Ultimele postări sincronizate {{time}}, tabla poate fi offline și publicarea poate eșua.",
|
||||
"newer_than": "mai nou decât",
|
||||
"no_threads": "Nu sunt subiecte",
|
||||
"unblock": "Deblocare",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Statistici nod",
|
||||
"loading_default_boards": "Se încarcă lista de panouri implicite",
|
||||
"loading_subscriptions": "Încărcarea abonamentelor",
|
||||
"create_board": "Creați tablou"
|
||||
"create_board": "Creați tablou",
|
||||
"enter_board_address": "Introduceți orice adresă de tablă",
|
||||
"board_not_reachable": "Tabloul nu este accesibil"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Дата создания",
|
||||
"sort_by": "Сортировать по",
|
||||
"time_filter": "Фильтр времени",
|
||||
"subplebbit_offline_info": "Сабплеббит может быть офлайн, и публикация может не удалиться.",
|
||||
"posts_last_synced_info": "Последние синхронизированные сообщения {{time}}, сабплеббит может быть офлайн, и публикация может не удалиться.",
|
||||
"subplebbit_offline_info": "Доска может быть офлайн, и публикация может не удаться",
|
||||
"posts_last_synced_info": "Последние сообщения синхронизированы {{time}}, доска может быть оффлайн, и публикация может не удаться.",
|
||||
"newer_than": "новее чем",
|
||||
"no_threads": "Нет тем",
|
||||
"unblock": "Разблокировать",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Статистика узла",
|
||||
"loading_default_boards": "Загрузка списка стандартных досок",
|
||||
"loading_subscriptions": "Загрузка подписок",
|
||||
"create_board": "Создать доску"
|
||||
"create_board": "Создать доску",
|
||||
"enter_board_address": "Введите любой адрес доски",
|
||||
"board_not_reachable": "Доска недоступна"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Data e krijimit",
|
||||
"sort_by": "Rendit sipas",
|
||||
"time_filter": "Filtri i kohës",
|
||||
"subplebbit_offline_info": "Subplebbiti mund të jetë jashtë linje dhe publikimi mund të dështojë.",
|
||||
"posts_last_synced_info": "Postimet e fundit të sinkronizuara {{time}}, subplebbiti mund të jetë jashtë linje dhe publikimi mund të dështojë.",
|
||||
"subplebbit_offline_info": "Tablli mund të jetë offline dhe publikimi mund të dështojë",
|
||||
"posts_last_synced_info": "Postimet e fundit janë sinkronizuar {{time}}, bordi mund të jetë jashtë linje dhe botimi mund të dështojë.",
|
||||
"newer_than": "më i ri se",
|
||||
"no_threads": "Nuk ka tema",
|
||||
"unblock": "Zhblloko",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Statistikat e nyjës",
|
||||
"loading_default_boards": "Po ngarkohen listat e bordit të parazgjedhur",
|
||||
"loading_subscriptions": "Po ngarkohen abonimet",
|
||||
"create_board": "Krijo bord"
|
||||
"create_board": "Krijo bord",
|
||||
"enter_board_address": "Shkruani çdo adresë bordi",
|
||||
"board_not_reachable": "Tabela nuk është e arritshme"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Skapelsedatum",
|
||||
"sort_by": "Sortera efter",
|
||||
"time_filter": "Tidsfilter",
|
||||
"subplebbit_offline_info": "Subplebbit kan vara offline och publicering kan misslyckas.",
|
||||
"posts_last_synced_info": "Inlägg senast synkroniserade {{time}}, subplebbit kan vara offline och publicering kan misslyckas.",
|
||||
"subplebbit_offline_info": "Brettet kan vara offline och publicering kan misslyckas",
|
||||
"posts_last_synced_info": "Senaste inlägg synkroniserades {{time}}, tavlan kan vara offline och publiceringen kan misslyckas.",
|
||||
"newer_than": "nyare än",
|
||||
"no_threads": "Inga trådar",
|
||||
"unblock": "Avblockera",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Node-statistik",
|
||||
"loading_default_boards": "Laddar standardlistan för tavlor",
|
||||
"loading_subscriptions": "Laddar prenumerationer",
|
||||
"create_board": "Skapa tavla"
|
||||
"create_board": "Skapa tavla",
|
||||
"enter_board_address": "Ange vilken som helst brädets adress",
|
||||
"board_not_reachable": "Tavlan är inte tillgänglig"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "సృష్టి తేదీ",
|
||||
"sort_by": "గట్టిగా",
|
||||
"time_filter": "సమయ ఫిల్టర్",
|
||||
"subplebbit_offline_info": "సబ్ప్లెబిట్ ఆఫ్లైన్ ఉండవచ్చు మరియు ప్రచురణ విఫలమైనా ఉంటుంది.",
|
||||
"posts_last_synced_info": "ఇటీవలే సింక్ చేసిన పోస్ట్లు {{time}}, సబ్ప్లెబిట్ ఆఫ్లైన్ ఉండవచ్చు, మరియు ప్రకటన విఫలమవుతుంది.",
|
||||
"subplebbit_offline_info": "బోర్డు ఆఫ్లైన్లో ఉండవచ్చు మరియు ప్రచురణ విఫలమవ్వవచ్చు",
|
||||
"posts_last_synced_info": "తాజా పోస్టులు సింక్ చేసినవి {{time}}, బోర్డు ఆఫ్లైన్లో ఉండవచ్చు మరియు ప్రచురణ విఫలమవచ్చు.",
|
||||
"newer_than": "కనునుగా",
|
||||
"no_threads": "ఏ థ్రెడ్లు లేవు",
|
||||
"unblock": "బ్లాక్ను తీసుకో",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "నోడ్ గణాంకాలు",
|
||||
"loading_default_boards": "డిఫాల్ట్ బోర్డుల జాబితా లోడవుతోంది",
|
||||
"loading_subscriptions": "సబ్స్క్రిప్షన్లు లోడ్ అవుతున్నాయి",
|
||||
"create_board": "బోర్డ్ రూపొందించండి"
|
||||
"create_board": "బోర్డ్ రూపొందించండి",
|
||||
"enter_board_address": "ఏదైనా బోర్డ్ అడ్రస్ నమోదు చేయండి",
|
||||
"board_not_reachable": "బోర్డు అందుబాటులో లేదు"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "วันที่สร้าง",
|
||||
"sort_by": "เรียงลำดับตาม",
|
||||
"time_filter": "ตัวกรองเวลา",
|
||||
"subplebbit_offline_info": "เซ็บเพล็บบิทอาจออฟไลน์และการเผยแพร่อาจล้มเหลว",
|
||||
"posts_last_synced_info": "โพสต์ล่าสุดที่ซิงค์ {{time}}, ซับเพลบบิทอาจออฟไลน์และการเผยแพร่อาจล้มเหลว",
|
||||
"subplebbit_offline_info": "กระดานอาจออฟไลน์และการเผยแพร่อาจล้มเหลว",
|
||||
"posts_last_synced_info": "โพสต์ล่าสุดซิงค์ {{time}} แล้ว บอร์ดอาจออฟไลน์และการเผยแพร่อาจล้มเหลว",
|
||||
"newer_than": "ใหม่กว่า",
|
||||
"no_threads": "ไม่มีกระทู้",
|
||||
"unblock": "ยกเลิกการบล็อก",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "สถิติโหนด",
|
||||
"loading_default_boards": "กำลังโหลดรายการกระดานเริ่มต้น",
|
||||
"loading_subscriptions": "กำลังโหลดการสมัครสมาชิก",
|
||||
"create_board": "สร้างกระดาน"
|
||||
"create_board": "สร้างกระดาน",
|
||||
"enter_board_address": "ป้อนที่อยู่บอร์ดใดก็ได้",
|
||||
"board_not_reachable": "ไม่สามารถเข้าถึงบอร์ดได้"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Oluşturulma tarihi",
|
||||
"sort_by": "Sırala",
|
||||
"time_filter": "Zaman Filtresi",
|
||||
"subplebbit_offline_info": "Subplebbit çevrimdışı olabilir ve yayınlama başarısız olabilir.",
|
||||
"posts_last_synced_info": "Son senkronize edilen gönderiler {{time}}, subplebbit çevrimdışı olabilir ve yayınlama başarısız olabilir.",
|
||||
"subplebbit_offline_info": "Tahta çevrimdışı olabilir ve yayınlama başarısız olabilir",
|
||||
"posts_last_synced_info": "Son gönderiler senkronize edildi {{time}}, board çevrimdışı olabilir ve yayınlama başarısız olabilir.",
|
||||
"newer_than": "daha yeni",
|
||||
"no_threads": "Hiç gönderi yok",
|
||||
"unblock": "Engeli kaldır",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Düğüm istatistikleri",
|
||||
"loading_default_boards": "Varsayılan panolar listesi yükleniyor",
|
||||
"loading_subscriptions": "Abonelikler yükleniyor",
|
||||
"create_board": "Tahta oluştur"
|
||||
"create_board": "Tahta oluştur",
|
||||
"enter_board_address": "Herhangi bir tahta adresini girin",
|
||||
"board_not_reachable": "Board erişilemez"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Дата створення",
|
||||
"sort_by": "Сортувати за",
|
||||
"time_filter": "Фільтр за часом",
|
||||
"subplebbit_offline_info": "Сабплебіт може бути офлайн, а публікація може не вдастися.",
|
||||
"posts_last_synced_info": "Останні синхронізовані повідомлення {{time}}, сабплебіт може бути офлайн, а публікація може не вдастися.",
|
||||
"subplebbit_offline_info": "Дошка може бути офлайн, а публікація може не вдатися",
|
||||
"posts_last_synced_info": "Останні пости синхронізовано {{time}}, дошка може бути офлайн, і публікація може не вдатися.",
|
||||
"newer_than": "новіше ніж",
|
||||
"no_threads": "Немає тем",
|
||||
"unblock": "Розблокувати",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Статистика вузла",
|
||||
"loading_default_boards": "Завантаження списку стандартних дошок",
|
||||
"loading_subscriptions": "Завантаження підписок",
|
||||
"create_board": "Створити дошку"
|
||||
"create_board": "Створити дошку",
|
||||
"enter_board_address": "Введіть будь-яку адресу дошки",
|
||||
"board_not_reachable": "Дошка недоступна"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "تخلیق کی تاریخ",
|
||||
"sort_by": "کے ذریعہ سارٹ کریں",
|
||||
"time_filter": "وقت فلٹر",
|
||||
"subplebbit_offline_info": "سب پلیبٹ آف لائن ہوسکتا ہے اور شائع ہونے میں ناکام ہوسکتا ہے۔",
|
||||
"posts_last_synced_info": "آخری بار پوسٹ سنک کی گئی {{time}}, سب پلیبٹ آف لائن ہوسکتا ہے اور شائع ہونے میں ناکام ہوسکتا ہے۔",
|
||||
"subplebbit_offline_info": "بورڈ آف لائن ہوسکتا ہے اور اشاعت ناکام ہوسکتی ہے",
|
||||
"posts_last_synced_info": "آخری پوسٹس ہم آہنگ کی گئیں {{time}} ، بورڈ آف لائن ہو سکتا ہے اور اشاعت ناکام ہو سکتی ہے۔",
|
||||
"newer_than": "نئی سے",
|
||||
"no_threads": "کوئی تھریڈز نہیں ہیں",
|
||||
"unblock": "بلاک ہٹائیں",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "نوڈ کے اعدادوشمار",
|
||||
"loading_default_boards": "ڈिफالٹ بورڈ کی فہرست لوڈ ہو رہی ہے",
|
||||
"loading_subscriptions": "سبسکرپشن لوڈ ہو رہی ہے",
|
||||
"create_board": "بورڈ بنائیں"
|
||||
"create_board": "بورڈ بنائیں",
|
||||
"enter_board_address": "کسی بھی بورڈ کا پتہ درج کریں",
|
||||
"board_not_reachable": "بورڈ قابل رسائی نہیں ہے"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "Ngày tạo",
|
||||
"sort_by": "Sắp xếp theo",
|
||||
"time_filter": "Bộ lọc thời gian",
|
||||
"subplebbit_offline_info": "Subplebbit có thể ngoại tuyến và việc xuất bản có thể thất bại.",
|
||||
"posts_last_synced_info": "Bài viết được đồng bộ lần cuối {{time}}, subplebbit có thể ngoại tuyến và việc xuất bản có thể thất bại.",
|
||||
"subplebbit_offline_info": "Bảng có thể ngoại tuyến và việc xuất bản có thể thất bại",
|
||||
"posts_last_synced_info": "Các bài viết cuối cùng đã đồng bộ {{time}}, bảng có thể ngoại tuyến và việc xuất bản có thể thất bại.",
|
||||
"newer_than": "mới hơn",
|
||||
"no_threads": "Không có chủ đề",
|
||||
"unblock": "Bỏ chặn",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "Thống kê nút",
|
||||
"loading_default_boards": "Đang tải danh sách bảng mặc định",
|
||||
"loading_subscriptions": "Đang tải đăng ký",
|
||||
"create_board": "Tạo bảng"
|
||||
"create_board": "Tạo bảng",
|
||||
"enter_board_address": "Nhập bất kỳ địa chỉ bảng nào",
|
||||
"board_not_reachable": "Bảng không thể truy cập"
|
||||
}
|
||||
@@ -164,8 +164,8 @@
|
||||
"creation_date": "创造日期",
|
||||
"sort_by": "排序方式",
|
||||
"time_filter": "时间过滤器",
|
||||
"subplebbit_offline_info": "子维基可能离线,发布可能失败。",
|
||||
"posts_last_synced_info": "最后同步的帖子 {{time}}, 子维基可能离线,发布可能失败。",
|
||||
"subplebbit_offline_info": "该板可能离线,发布可能失败",
|
||||
"posts_last_synced_info": "最后同步的帖子 {{time}},板块可能离线,发布可能失败。",
|
||||
"newer_than": "新于",
|
||||
"no_threads": "没有帖子",
|
||||
"unblock": "解除封禁",
|
||||
@@ -282,5 +282,7 @@
|
||||
"node_stats": "节点统计",
|
||||
"loading_default_boards": "正在加载默认板块列表",
|
||||
"loading_subscriptions": "加载订阅",
|
||||
"create_board": "创建板块"
|
||||
"create_board": "创建板块",
|
||||
"enter_board_address": "输入任何板块地址",
|
||||
"board_not_reachable": "无法访问板块"
|
||||
}
|
||||
@@ -28,14 +28,28 @@
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.offlineIconWrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.offlineIcon {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
image-rendering: pixelated;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
image-rendering: pixelated;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.redOfflineIcon {
|
||||
background-image: var(--offline-icon);
|
||||
}
|
||||
|
||||
.yellowOfflineIcon {
|
||||
background-image: var(--offline-loading-icon);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useMultisubMetadata } from '../../hooks/use-default-subplebbits';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
import { shouldShowSnow } from '../../lib/snow';
|
||||
import Tooltip from '../tooltip';
|
||||
|
||||
const totalBanners = 61;
|
||||
|
||||
@@ -47,7 +48,11 @@ const BoardHeader = () => {
|
||||
<div className={styles.boardTitle}>
|
||||
{title || (shortAddress ? (shortAddress.endsWith('.eth') || shortAddress.endsWith('.sol') ? shortAddress.slice(0, -4) : shortAddress) : subplebbitAddress)}
|
||||
{(isOffline || isOnlineStatusLoading) && !isInAllView && !isInSubscriptionsView && (
|
||||
<span className={`${styles.offlineIcon} ${offlineIconClass}`} title={offlineTitle} />
|
||||
<span className={styles.offlineIconWrapper}>
|
||||
<Tooltip content={offlineTitle}>
|
||||
<span className={`${styles.offlineIcon} ${offlineIconClass}`} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.boardSubtitle}>{subtitle}</div>
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
import { useState } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isPostPageView } from '../../lib/utils/view-utils';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import useStateString from '../../hooks/use-state-string';
|
||||
import LoadingEllipsis from '../../components/loading-ellipsis';
|
||||
import ReplyQuotePreview from '../../components/reply-quote-preview';
|
||||
import Markdown from '../../components/markdown';
|
||||
import Tooltip from '../../components/tooltip';
|
||||
import { Comment, useComment } from '@plebbit/plebbit-react-hooks';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
import _ from 'lodash';
|
||||
|
||||
const CommentContent = ({ comment: post }: { comment: Comment }) => {
|
||||
const { t } = useTranslation();
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const isInPostView = isPostPageView(location.pathname, params);
|
||||
const [showOriginal, setShowOriginal] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
// TODO: commentAuthor is not yet available outside of editedComment, wait for API to be updated
|
||||
const { cid, content, deleted, edit, isRules, original, parentCid, postCid, reason, removed, state } = post || {};
|
||||
// const banned = !!post?.commentAuthor?.banExpiresAt;
|
||||
|
||||
const [showFullComment, setShowFullComment] = useState(false);
|
||||
const displayContent =
|
||||
content &&
|
||||
(!isInPostView && content.length > 1000 && !showFullComment
|
||||
? content.slice(0, 1000)
|
||||
: isInPostView && content.length > 2000 && !showFullComment
|
||||
? content.slice(0, 2000)
|
||||
: content);
|
||||
|
||||
const quotelinkReply = useComment({ commentCid: parentCid });
|
||||
const isReply = parentCid;
|
||||
const isReplyingToReply = (postCid && postCid !== parentCid) || quotelinkReply?.postCid !== parentCid;
|
||||
|
||||
const stateString = useStateString(post);
|
||||
|
||||
const loadingString = <div className={styles.stateString}>{stateString !== 'Failed' ? <LoadingEllipsis string={stateString || t('loading')} /> : stateString}</div>;
|
||||
|
||||
return (
|
||||
<blockquote className={`${styles.postMessage} ${!isReply && isMobile && styles.clampLines} ${isRules && styles.rulesMessage}`}>
|
||||
{isReply && state !== 'failed' && isReplyingToReply && !(deleted || removed) && <ReplyQuotePreview isQuotelinkReply={true} quotelinkReply={quotelinkReply} />}
|
||||
{removed ? (
|
||||
reason ? (
|
||||
<>
|
||||
<span className={styles.redEditMessage}>({t('this_post_was_removed')})</span>
|
||||
<br />
|
||||
<br />
|
||||
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className={styles.grayEditMessage}>{_.capitalize(t('this_post_was_removed'))}.</span>
|
||||
)
|
||||
) : deleted ? (
|
||||
reason ? (
|
||||
<>
|
||||
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>{' '}
|
||||
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
{!showOriginal && <Markdown content={displayContent} />}
|
||||
{((!isInPostView && content?.length > 1000 && !showFullComment) || (isInPostView && content?.length > 2000 && !showFullComment)) && (
|
||||
<span className={styles.abbr}>
|
||||
<br />
|
||||
<br />
|
||||
<Trans i18nKey={'comment_too_long'} shouldUnescape={true} components={{ 1: <span onClick={() => setShowFullComment(true)} /> }} />
|
||||
</span>
|
||||
)}
|
||||
{edit && original?.content !== content && (
|
||||
<span className={styles.editedInfo}>
|
||||
{showOriginal && <Markdown content={original?.content} />}
|
||||
<br />
|
||||
<br />
|
||||
<Trans
|
||||
i18nKey={'comment_edited_at_timestamp'}
|
||||
values={{ timestamp: getFormattedDate(edit?.timestamp) }}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <Tooltip content={getFormattedTimeAgo(edit?.timestamp)} children={<></>} /> }}
|
||||
/>{' '}
|
||||
{reason && <>{t('reason_reason', { reason: reason, interpolation: { escapeValue: false } })} </>}
|
||||
{showOriginal ? (
|
||||
<Trans
|
||||
i18nKey={'click_here_to_hide_original'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <span className={styles.showOriginal} onClick={() => setShowOriginal(!showOriginal)} /> }}
|
||||
/>
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey={'click_here_to_show_original'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <span className={styles.showOriginal} onClick={() => setShowOriginal(!showOriginal)} /> }}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* TODO: commentAuthor is not yet available outside of editedComment, wait for API to be updated */}
|
||||
{/* {banned && (
|
||||
<span className={styles.removedContent}>
|
||||
<br />
|
||||
<br />
|
||||
<Tooltip
|
||||
children={`(${t('user_banned')})`}
|
||||
content={`${t('ban_expires_at', {
|
||||
address: subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress),
|
||||
timestamp: getFormattedDate(commentAuthor?.banExpiresAt),
|
||||
interpolation: { escapeValue: false },
|
||||
})}${reason ? `. ${_.capitalize(t('reason'))}: "${reason}"` : ''}`}
|
||||
/>
|
||||
</span>
|
||||
)} */}
|
||||
{!cid && state === 'pending' && stateString !== 'Failed' && (
|
||||
<>
|
||||
<br />
|
||||
<br />
|
||||
{loadingString}
|
||||
</>
|
||||
)}
|
||||
</blockquote>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommentContent;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './comment-content';
|
||||
@@ -135,7 +135,7 @@ interface ImageProps {
|
||||
|
||||
const Image = ({ commentMediaInfo, displayHeight, displayWidth, isOutOfFeed, post }: ImageProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { parentCid } = post || {};
|
||||
const { parentCid, spoiler } = post || {};
|
||||
const { type, url } = commentMediaInfo || {};
|
||||
const isReply = parentCid;
|
||||
const isMobile = useIsMobile();
|
||||
@@ -151,6 +151,15 @@ const Image = ({ commentMediaInfo, displayHeight, displayWidth, isOutOfFeed, pos
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const handleError = () => setHasError(true);
|
||||
|
||||
if (spoiler && !isImageExpanded) {
|
||||
const spoilerDimensions = { '--width': '150px', '--height': '150px' } as React.CSSProperties;
|
||||
return (
|
||||
<span className={`${isOutOfFeed ? styles.subplebbitAvatar : styles.thumbnailBig} ${styles.thumbnail}`} style={spoilerDimensions}>
|
||||
<img className={styles.spoiler} src='assets/spoiler.png' alt='' onClick={() => setIsImageExpanded(true)} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return isMobile ? (
|
||||
<span className={styles.thumbnail}>
|
||||
<span
|
||||
@@ -227,7 +236,7 @@ const CommentMedia = ({ commentMediaInfo, isFloatingEmbed, post, showThumbnail,
|
||||
displayHeight = '100%';
|
||||
}
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const isOutOfFeed = isDescription || isRules || isFloatingEmbed; // virtuoso wrapper unneeded
|
||||
const isOutOfFeed = isDescription || isRules || isFloatingEmbed || spoiler; // virtuoso wrapper unneeded
|
||||
|
||||
return (
|
||||
<span className={styles.content}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { Comment, useAuthorAvatar, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
import { getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
||||
@@ -17,11 +17,11 @@ import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
||||
import useHide from '../../hooks/use-hide';
|
||||
import useReplies from '../../hooks/use-replies';
|
||||
import useStateString from '../../hooks/use-state-string';
|
||||
import CommentContent from '../comment-content';
|
||||
import CommentMedia from '../comment-media';
|
||||
import EditMenu from '../edit-menu/edit-menu';
|
||||
import { canEmbed } from '../embed';
|
||||
import LoadingEllipsis from '../loading-ellipsis';
|
||||
import Markdown from '../markdown';
|
||||
import PostMenuDesktop from './post-menu-desktop';
|
||||
import ReplyQuotePreview from '../reply-quote-preview';
|
||||
import Tooltip from '../tooltip';
|
||||
@@ -251,8 +251,7 @@ const PostMediaContent = ({ post, hasThumbnail, spoiler, t }: { post: any; hasTh
|
||||
{mediaDimensions && `, ${mediaDimensions}`})
|
||||
{!showThumbnail && (type === 'iframe' || type === 'video' || type === 'audio') && (
|
||||
<span>
|
||||
{' '}
|
||||
[
|
||||
-[
|
||||
<span className={styles.closeMedia} onClick={() => setShowThumbnail(true)}>
|
||||
{t('close')}
|
||||
</span>
|
||||
@@ -285,120 +284,6 @@ const PostMediaContent = ({ post, hasThumbnail, spoiler, t }: { post: any; hasTh
|
||||
);
|
||||
};
|
||||
|
||||
const PostMessage = ({ post }: PostProps) => {
|
||||
const { cid, content, deleted, edit, isRules, original, parentCid, postCid, reason, removed, state } = post || {};
|
||||
// TODO: commentAuthor is not yet available outside of editedComment, wait for API to be updated
|
||||
// const banned = !!post?.commentAuthor?.banExpiresAt;
|
||||
const { t } = useTranslation();
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const isInPostView = isPostPageView(location.pathname, params);
|
||||
const [showOriginal, setShowOriginal] = useState(false);
|
||||
|
||||
const [showFullComment, setShowFullComment] = useState(false);
|
||||
const displayContent =
|
||||
content &&
|
||||
(!isInPostView && content.length > 1000 && !showFullComment
|
||||
? content.slice(0, 1000)
|
||||
: isInPostView && content.length > 2000 && !showFullComment
|
||||
? content.slice(0, 2000)
|
||||
: content);
|
||||
|
||||
const quotelinkReply = useComment({ commentCid: parentCid });
|
||||
const isReply = parentCid;
|
||||
const isReplyingToReply = (postCid && postCid !== parentCid) || quotelinkReply?.postCid !== parentCid;
|
||||
|
||||
const stateString = useStateString(post);
|
||||
|
||||
const loadingString = (
|
||||
<div className={`${styles.stateString} ${styles.ellipsis}`}>{stateString !== 'Failed' ? <LoadingEllipsis string={stateString || t('loading')} /> : stateString}</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<blockquote className={`${styles.postMessage} ${isRules && styles.rulesMessage}`}>
|
||||
{isReply && state !== 'failed' && isReplyingToReply && !(deleted || removed) && <ReplyQuotePreview isQuotelinkReply={true} quotelinkReply={quotelinkReply} />}
|
||||
{removed ? (
|
||||
reason ? (
|
||||
<>
|
||||
<span className={styles.redEditMessage}>({t('this_post_was_removed')})</span>
|
||||
<br />
|
||||
<br />
|
||||
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className={styles.grayEditMessage}>{_.capitalize(t('this_post_was_removed'))}.</span>
|
||||
)
|
||||
) : deleted ? (
|
||||
reason ? (
|
||||
<>
|
||||
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>{' '}
|
||||
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
{!showOriginal && <Markdown content={displayContent} />}
|
||||
{edit && original?.content !== post?.content && (
|
||||
<span className={styles.editedInfo}>
|
||||
{showOriginal && <Markdown content={original?.content} />}
|
||||
<br />
|
||||
<Trans
|
||||
i18nKey={'comment_edited_at_timestamp'}
|
||||
values={{ timestamp: getFormattedDate(edit?.timestamp) }}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <Tooltip content={getFormattedTimeAgo(edit?.timestamp)} children={<></>} /> }}
|
||||
/>{' '}
|
||||
{reason && <>{t('reason_reason', { reason: reason, interpolation: { escapeValue: false } })} </>}
|
||||
{showOriginal ? (
|
||||
<Trans
|
||||
i18nKey={'click_here_to_hide_original'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <span className={styles.showOriginal} onClick={() => setShowOriginal(!showOriginal)} /> }}
|
||||
/>
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey={'click_here_to_show_original'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <span className={styles.showOriginal} onClick={() => setShowOriginal(!showOriginal)} /> }}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* TODO: commentAuthor is not yet available outside of editedComment, wait for API to be updated */}
|
||||
{/* {banned && (
|
||||
<span className={styles.removedContent}>
|
||||
<br />
|
||||
<br />
|
||||
<Tooltip
|
||||
children={`(${t('user_banned')})`}
|
||||
content={`${t('ban_expires_at', {
|
||||
address: subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress),
|
||||
timestamp: getFormattedDate(commentAuthor?.banExpiresAt),
|
||||
interpolation: { escapeValue: false },
|
||||
})}${reason ? `. ${_.capitalize(t('reason'))}: "${reason}"` : ''}`}
|
||||
/>
|
||||
</span>
|
||||
)} */}
|
||||
{((!isInPostView && content?.length > 1000 && !showFullComment) || (isInPostView && content?.length > 2000 && !showFullComment)) && (
|
||||
<span className={styles.abbr}>
|
||||
<br />
|
||||
<Trans i18nKey={'comment_too_long'} shouldUnescape={true} components={{ 1: <span onClick={() => setShowFullComment(true)} /> }} />
|
||||
</span>
|
||||
)}
|
||||
{!cid && state === 'pending' && stateString !== 'Failed' && (
|
||||
<>
|
||||
<br />
|
||||
{loadingString}
|
||||
</>
|
||||
)}
|
||||
</blockquote>
|
||||
);
|
||||
};
|
||||
|
||||
const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
|
||||
let post = reply;
|
||||
// handle pending mod or author edit
|
||||
@@ -420,7 +305,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
|
||||
<div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight}`} data-cid={cid} data-author-address={author?.shortAddress} data-post-cid={postCid}>
|
||||
<PostInfo openReplyModal={openReplyModal} post={post} postReplyCount={postReplyCount} roles={roles} isHidden={hidden} />
|
||||
{link && !hidden && !(deleted || removed) && isValidURL(link) && <PostMedia post={post} hasThumbnail={hasThumbnail} />}
|
||||
{!hidden && (!(removed || deleted) || ((removed || deleted) && reason)) && <PostMessage post={post} />}
|
||||
{!hidden && (!(removed || deleted) || ((removed || deleted) && reason)) && <CommentContent comment={post} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -483,7 +368,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
|
||||
{link && !isHidden && !(deleted || removed) && isValidURL(link) && <PostMedia post={post} hasThumbnail={hasThumbnail} />}
|
||||
<PostInfo isHidden={hidden} openReplyModal={openReplyModal} post={post} postReplyCount={replyCount} roles={roles} />
|
||||
{!isHidden && !content && !(deleted || removed) && <div className={styles.spacer} />}
|
||||
{!isHidden && <PostMessage post={post} />}
|
||||
{!isHidden && <CommentContent comment={post} />}
|
||||
</div>
|
||||
{!isHidden && !isDescription && !isRules && !isInPendingPostView && (replyCount > 5 || (pinned && repliesCount > 0)) && !isInPostPageView && (
|
||||
<span className={styles.summary}>
|
||||
@@ -522,16 +407,20 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
|
||||
)}
|
||||
</div>
|
||||
{!isInPendingPostView &&
|
||||
!isDescription &&
|
||||
!isRules &&
|
||||
(stateString && stateString !== 'Failed' && state !== 'succeeded' && isInPostPageView ? (
|
||||
<div className={styles.stateString}>
|
||||
<br />
|
||||
<LoadingEllipsis string={stateString} />
|
||||
</div>
|
||||
) : (
|
||||
state === 'failed' && <span className={styles.error}>{t('failed')}</span>
|
||||
))}
|
||||
!isDescription &&
|
||||
!isRules &&
|
||||
stateString &&
|
||||
stateString !== 'Failed' &&
|
||||
state !== 'succeeded' &&
|
||||
isInPostPageView &&
|
||||
!(!showReplies && !showAllReplies) ? (
|
||||
<div className={styles.stateString}>
|
||||
<br />
|
||||
<LoadingEllipsis string={stateString} />
|
||||
</div>
|
||||
) : (
|
||||
state === 'failed' && <span className={styles.error}>{t('failed')}</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { Comment, useAuthorAvatar, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
import { shouldShowSnow } from '../../lib/snow';
|
||||
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
@@ -15,15 +16,14 @@ import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
|
||||
import useHide from '../../hooks/use-hide';
|
||||
import useReplies from '../../hooks/use-replies';
|
||||
import useStateString from '../../hooks/use-state-string';
|
||||
import CommentContent from '../comment-content';
|
||||
import CommentMedia from '../comment-media';
|
||||
import LoadingEllipsis from '../loading-ellipsis';
|
||||
import Markdown from '../markdown';
|
||||
import PostMenuMobile from './post-menu-mobile';
|
||||
import ReplyQuotePreview from '../reply-quote-preview';
|
||||
import Tooltip from '../tooltip';
|
||||
import { PostProps } from '../../views/post/post';
|
||||
import _ from 'lodash';
|
||||
import { shouldShowSnow } from '../../lib/snow';
|
||||
|
||||
const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -215,121 +215,6 @@ const ReplyBacklinks = ({ post }: PostProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const PostMessageMobile = ({ post }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { cid, content, deleted, edit, isRules, original, parentCid, postCid, reason, removed, state } = post || {};
|
||||
// TODO: commentAuthor is not available outside of editedComment, update when available
|
||||
// const banned = !!post?.commentAuthor?.banExpiresAt;
|
||||
const [showOriginal, setShowOriginal] = useState(false);
|
||||
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const isInPostView = isPostPageView(location.pathname, params);
|
||||
|
||||
const [showFullComment, setShowFullComment] = useState(false);
|
||||
const displayContent =
|
||||
content &&
|
||||
(!isInPostView && content.length > 1000 && !showFullComment
|
||||
? content.slice(0, 1000)
|
||||
: isInPostView && content.length > 2000 && !showFullComment
|
||||
? content.slice(0, 2000)
|
||||
: content);
|
||||
|
||||
const quotelinkReply = useComment({ commentCid: parentCid });
|
||||
const isReply = parentCid;
|
||||
const isReplyingToReply = (postCid && postCid !== parentCid) || quotelinkReply?.postCid !== parentCid;
|
||||
|
||||
const stateString = useStateString(post);
|
||||
|
||||
const loadingString = (
|
||||
<div className={`${styles.stateString} ${styles.ellipsis}`}>{stateString !== 'Failed' ? <LoadingEllipsis string={stateString || t('loading')} /> : stateString}</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<blockquote className={`${styles.postMessage} ${!isReply && styles.clampLines} ${isRules && styles.rulesMessage}`}>
|
||||
{isReply && !(removed || deleted) && state !== 'failed' && isReplyingToReply && <ReplyQuotePreview isQuotelinkReply={true} quotelinkReply={quotelinkReply} />}
|
||||
{removed ? (
|
||||
reason ? (
|
||||
<>
|
||||
<span className={styles.redEditMessage}>({t('this_post_was_removed')})</span>
|
||||
<br />
|
||||
<br />
|
||||
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className={styles.grayEditMessage}>{_.capitalize(t('this_post_was_removed'))}.</span>
|
||||
)
|
||||
) : deleted ? (
|
||||
reason ? (
|
||||
<>
|
||||
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>{' '}
|
||||
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
{!showOriginal && <Markdown content={displayContent} />}
|
||||
{edit && original?.content !== post?.content && (
|
||||
<span className={styles.editedInfo}>
|
||||
{showOriginal && <Markdown content={original?.content} />}
|
||||
<br />
|
||||
<Trans
|
||||
i18nKey={'comment_edited_at_timestamp'}
|
||||
values={{ timestamp: getFormattedDate(edit?.timestamp) }}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <Tooltip content={getFormattedTimeAgo(edit?.timestamp)} children={<></>} /> }}
|
||||
/>{' '}
|
||||
{reason && <>{t('reason_reason', { reason: reason, interpolation: { escapeValue: false } })} </>}
|
||||
{showOriginal ? (
|
||||
<Trans
|
||||
i18nKey={'click_here_to_hide_original'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <span className={styles.showOriginal} onClick={() => setShowOriginal(!showOriginal)} /> }}
|
||||
/>
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey={'click_here_to_show_original'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <span className={styles.showOriginal} onClick={() => setShowOriginal(!showOriginal)} /> }}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* TODO: commentAuthor is not available outside of editedComment, update when available */}
|
||||
{/* {banned && (
|
||||
<span className={styles.removedContent}>
|
||||
<br />
|
||||
<br />
|
||||
<Tooltip
|
||||
children={`(${t('user_banned')})`}
|
||||
content={`${t('ban_expires_at', {
|
||||
address: subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress),
|
||||
timestamp: getFormattedDate(commentAuthor?.banExpiresAt),
|
||||
interpolation: { escapeValue: false },
|
||||
})}${reason ? `. ${_.capitalize(t('reason'))}: "${reason}"` : ''}`}
|
||||
/>
|
||||
</span>
|
||||
)} */}
|
||||
{((!isInPostView && content?.length > 1000 && !showFullComment) || (isInPostView && content?.length > 2000 && !showFullComment)) && (
|
||||
<span className={styles.abbr}>
|
||||
<br />
|
||||
<Trans i18nKey={'comment_too_long'} shouldUnescape={true} components={{ 1: <span onClick={() => setShowFullComment(true)} /> }} />
|
||||
</span>
|
||||
)}
|
||||
{!cid && state === 'pending' && stateString !== 'Failed' && (
|
||||
<>
|
||||
<br />
|
||||
{loadingString}
|
||||
</>
|
||||
)}
|
||||
</blockquote>
|
||||
);
|
||||
};
|
||||
|
||||
const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
|
||||
let post = reply;
|
||||
// handle pending mod or author edit
|
||||
@@ -351,7 +236,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
|
||||
data-post-cid={postCid}
|
||||
>
|
||||
<PostInfoAndMedia openReplyModal={openReplyModal} post={post} postReplyCount={postReplyCount} roles={roles} />
|
||||
{!hidden && (!(removed || deleted) || ((removed || deleted) && reason)) && <PostMessageMobile post={post} />}
|
||||
{!hidden && (!(removed || deleted) || ((removed || deleted) && reason)) && <CommentContent comment={post} />}
|
||||
<ReplyBacklinks post={reply} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -415,7 +300,7 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
|
||||
>
|
||||
{shouldShowSnow() && <img src={`${process.env.PUBLIC_URL}/assets/xmashat.gif`} className={styles.xmasHat} alt='' />}
|
||||
<PostInfoAndMedia openReplyModal={openReplyModal} post={post} postReplyCount={replyCount} roles={roles} />
|
||||
<PostMessageMobile post={post} />
|
||||
<CommentContent comment={post} />
|
||||
</div>
|
||||
{!isInPostView && !isInPendingPostView && showReplies && (
|
||||
<div className={styles.postLink}>
|
||||
@@ -448,15 +333,19 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
|
||||
)}
|
||||
</div>
|
||||
{!isInPendingPostView &&
|
||||
!isDescription &&
|
||||
!isRules &&
|
||||
(stateString && stateString !== 'Failed' && state !== 'succeeded' && isInPostPageView ? (
|
||||
<div className={styles.stateString}>
|
||||
<LoadingEllipsis string={stateString} />
|
||||
</div>
|
||||
) : (
|
||||
state === 'failed' && <span className={styles.error}>{t('failed')}</span>
|
||||
))}
|
||||
!isDescription &&
|
||||
!isRules &&
|
||||
stateString &&
|
||||
stateString !== 'Failed' &&
|
||||
state !== 'succeeded' &&
|
||||
isInPostPageView &&
|
||||
!(!showReplies && !showAllReplies) ? (
|
||||
<div className={styles.stateString}>
|
||||
<LoadingEllipsis string={stateString} />
|
||||
</div>
|
||||
) : (
|
||||
state === 'failed' && <span className={styles.error}>{t('failed')}</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -137,7 +137,8 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
|
||||
onClick={(e) => handleClick(e, backlinkReply?.cid, backlinkReply?.subplebbitAddress)}
|
||||
>
|
||||
c/{backlinkReply?.shortCid}
|
||||
{'>>'}
|
||||
{backlinkReply?.shortCid}
|
||||
</Link>
|
||||
{hoveredCid === backlinkReply?.cid &&
|
||||
outOfViewCid === backlinkReply?.cid &&
|
||||
@@ -164,7 +165,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
|
||||
onClick={(e) => handleClick(e, quotelinkReply?.cid, quotelinkReply?.subplebbitAddress)}
|
||||
>
|
||||
{quotelinkReply?.shortCid && `c/${quotelinkReply?.shortCid}`}
|
||||
{quotelinkReply?.shortCid && `>>${quotelinkReply?.shortCid}`}
|
||||
{(quotelinkReply?.author?.address === account?.author?.address || quotelinkReply?.author?.address === threadSigner?.address) && ' (You)'}
|
||||
</Link>
|
||||
<br />
|
||||
@@ -239,7 +240,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
|
||||
>
|
||||
{backlinkReply?.shortCid && `c/${backlinkReply?.shortCid}`}
|
||||
{backlinkReply?.shortCid && `>>${backlinkReply?.shortCid}`}
|
||||
</span>
|
||||
{backlinkReply?.shortCid && (
|
||||
<Link
|
||||
@@ -274,7 +275,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
|
||||
>
|
||||
{quotelinkReply?.shortCid && `c/${quotelinkReply?.shortCid}`}
|
||||
{quotelinkReply?.shortCid && `>>${quotelinkReply?.shortCid}`}
|
||||
{(quotelinkReply?.author?.address === account?.author?.address || quotelinkReply?.author?.address === threadSigner?.address) && ' (You)'}
|
||||
</span>
|
||||
{quotelinkReply?.shortCid && (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
background-color: #181f24;
|
||||
background-color: var(--tooltip-background-color);
|
||||
font-size: 11px;
|
||||
line-height: 13px;
|
||||
padding: 3px 6px;
|
||||
@@ -9,7 +9,6 @@
|
||||
white-space: pre-line;
|
||||
max-width: 400px;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -21,8 +20,15 @@
|
||||
position: absolute;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
border-top: 4px solid #181f24;
|
||||
border-top: 4px solid var(--tooltip-background-color);
|
||||
margin-left: -4px;
|
||||
bottom: -4px;
|
||||
left: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.tooltip {
|
||||
max-width: 80vw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useAccount, useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import { useAccount, useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { isAllView, isCatalogView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import styles from './topbar.module.css';
|
||||
import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
|
||||
import _, { debounce } from 'lodash';
|
||||
import { TimeFilter } from '../board-buttons';
|
||||
import { useAutoSubscribe } from '../../hooks/use-auto-subscribe';
|
||||
import { TimeFilter } from '../board-buttons';
|
||||
import styles from './topbar.module.css';
|
||||
import _, { debounce } from 'lodash';
|
||||
|
||||
const SearchBar = ({ setShowSearchBar }: { setShowSearchBar: (show: boolean) => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const searchBarRef = useRef<HTMLDivElement>(null);
|
||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||
const placeholder = `"community.eth/.sol" / "12D3KooW..."`;
|
||||
const placeholder = _.lowerCase(t('enter_board_address'));
|
||||
|
||||
useEffect(() => {
|
||||
searchInputRef.current?.focus();
|
||||
|
||||
@@ -35,7 +35,7 @@ const useFeedStateString = (subplebbitAddresses?: string[]): string | undefined
|
||||
if (states['resolving-address']) {
|
||||
const { subplebbitAddresses, clientUrls } = states['resolving-address'];
|
||||
if (subplebbitAddresses.length && clientUrls.length) {
|
||||
stateString += `loading ${subplebbitAddresses.length} ${subplebbitAddresses.length === 1 ? 'address' : 'addresses'} from ${clientUrls
|
||||
stateString += `resolving ${subplebbitAddresses.length} ${subplebbitAddresses.length === 1 ? 'address' : 'addresses'} from ${clientUrls
|
||||
.map(getClientHost)
|
||||
.join(', ')}`;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ const useStateString = (commentOrSubplebbit: CommentOrSubplebbit): string | unde
|
||||
.replace('ipfs', 'post')
|
||||
.replace('ipns', 'subplebbit')
|
||||
.replace('fetching', 'loading')
|
||||
.replace('resolving', 'loading')
|
||||
.replace('subplebbit subplebbit', 'board')
|
||||
.replace('loading subplebbit', 'loading board');
|
||||
}
|
||||
|
||||
@@ -196,6 +196,9 @@
|
||||
|
||||
/* stats */
|
||||
--stats-font-size: 11px;
|
||||
|
||||
/* tooltip */
|
||||
--tooltip-background-color: #181f24;
|
||||
|
||||
/* topbar */
|
||||
--topbar-font-size: 9pt;
|
||||
@@ -406,6 +409,9 @@
|
||||
/* stats */
|
||||
--stats-font-size: 11px;
|
||||
|
||||
/* tooltip */
|
||||
--tooltip-background-color: #181f24;
|
||||
|
||||
/* topbar */
|
||||
--topbar-font-size: 9pt;
|
||||
--topbar-separator-color: #89a;
|
||||
@@ -584,6 +590,9 @@
|
||||
/* stats */
|
||||
--stats-font-size: 10pt;
|
||||
|
||||
/* tooltip */
|
||||
--tooltip-background-color: #181f24;
|
||||
|
||||
/* topbar */
|
||||
--topbar-font-size: 11pt;
|
||||
--topbar-separator-color: none;
|
||||
@@ -769,6 +778,9 @@
|
||||
/* stats */
|
||||
--stats-font-size: 10pt;
|
||||
|
||||
/* tooltip */
|
||||
--tooltip-background-color: #181f24;
|
||||
|
||||
/* topbar */
|
||||
--topbar-font-size: 11pt;
|
||||
--topbar-separator-color: none;
|
||||
@@ -988,6 +1000,9 @@
|
||||
/* stats */
|
||||
--stats-font-size: 11px;
|
||||
|
||||
/* tooltip */
|
||||
--tooltip-background-color: #000;
|
||||
|
||||
/* topbar */
|
||||
--topbar-font-size: 9pt;
|
||||
--topbar-separator-color: #c5c8c6;
|
||||
@@ -1188,6 +1203,9 @@
|
||||
/* stats */
|
||||
--stats-font-size: 11px;
|
||||
|
||||
/* tooltip */
|
||||
--tooltip-background-color: #181f24;
|
||||
|
||||
/* topbar */
|
||||
--topbar-font-size: 9pt;
|
||||
--topbar-separator-color: #333;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.content {
|
||||
overflow-x: hidden;
|
||||
overflow-y: visible;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
||||
@@ -165,7 +165,7 @@ const Board = () => {
|
||||
|
||||
const Footer = () => {
|
||||
let footerContent;
|
||||
if (feed.length === 0) {
|
||||
if (combinedFeed.length === 0) {
|
||||
footerContent = t('no_threads');
|
||||
}
|
||||
if (hasMore || (subplebbitAddresses && subplebbitAddresses.length === 0)) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Comment, useAccount, useFeed, useSubplebbit, useBlock } from '@plebbit/plebbit-react-hooks';
|
||||
import { Comment, useAccount, useFeed, useSubplebbit, useBlock, useAccountComments } from '@plebbit/plebbit-react-hooks';
|
||||
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
||||
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
@@ -90,6 +90,46 @@ const Catalog = () => {
|
||||
}, [subplebbitAddresses, sortType, isInAllView, isInSubscriptionsView, postsPerPage, timeFilterSeconds, hideThreadsWithoutImages]);
|
||||
|
||||
const { feed, hasMore, loadMore, reset, subplebbitAddressesWithNewerPosts } = useFeed(feedOptions);
|
||||
const { accountComments } = useAccountComments();
|
||||
|
||||
const resetTriggeredRef = useRef(false);
|
||||
|
||||
// show account comments instantly in the feed once published (cid defined), instead of waiting for the feed to update
|
||||
const filteredComments = useMemo(
|
||||
() =>
|
||||
accountComments.filter((comment) => {
|
||||
const { cid, deleted, postCid, removed, state, timestamp } = comment || {};
|
||||
return (
|
||||
!deleted &&
|
||||
!removed &&
|
||||
timestamp > Date.now() / 1000 - 60 * 60 &&
|
||||
state === 'succeeded' &&
|
||||
cid &&
|
||||
(hideThreadsWithoutImages ? getHasThumbnail(getCommentMediaInfo(comment), comment?.link) : true) &&
|
||||
cid === postCid &&
|
||||
comment?.subplebbitAddress === subplebbitAddress &&
|
||||
!feed.some((post) => post.cid === cid)
|
||||
);
|
||||
}),
|
||||
[accountComments, subplebbitAddress, feed, hideThreadsWithoutImages],
|
||||
);
|
||||
|
||||
// show newest account comment at the top of the feed but after pinned posts
|
||||
const combinedFeed = useMemo(() => {
|
||||
const newFeed = [...feed];
|
||||
const lastPinnedIndex = newFeed.map((post) => post.pinned).lastIndexOf(true);
|
||||
if (filteredComments.length > 0) {
|
||||
newFeed.splice(lastPinnedIndex + 1, 0, ...filteredComments);
|
||||
}
|
||||
return newFeed;
|
||||
}, [feed, filteredComments]);
|
||||
|
||||
useEffect(() => {
|
||||
if (filteredComments.length > 0 && !resetTriggeredRef.current) {
|
||||
reset();
|
||||
resetTriggeredRef.current = true;
|
||||
}
|
||||
}, [filteredComments, reset]);
|
||||
|
||||
const handleNewerPostsButtonClick = () => {
|
||||
window.scrollTo({ top: 0, left: 0 });
|
||||
@@ -147,7 +187,7 @@ const Catalog = () => {
|
||||
t('not_subscribed_to_any_board')
|
||||
) : blocked ? (
|
||||
t('you_have_blocked_this_board')
|
||||
) : !hasMore && feed.length === 0 ? (
|
||||
) : !hasMore && combinedFeed.length === 0 ? (
|
||||
t('no_threads')
|
||||
) : (
|
||||
hasMore && <LoadingEllipsis string={loadingStateString} />
|
||||
@@ -169,7 +209,7 @@ const Catalog = () => {
|
||||
if (feed.length === 0) {
|
||||
if (blocked) {
|
||||
footerContent = t('you_have_blocked_this_board');
|
||||
} else {
|
||||
} else if (combinedFeed.length === 0) {
|
||||
footerContent = t('no_threads');
|
||||
}
|
||||
}
|
||||
@@ -222,7 +262,7 @@ const Catalog = () => {
|
||||
|
||||
const isFeedLoaded = feed.length > 0 || state === 'failed';
|
||||
|
||||
const rows = useCatalogFeedRows(columnCount, feed, isFeedLoaded, subplebbit);
|
||||
const rows = useCatalogFeedRows(columnCount, combinedFeed, isFeedLoaded, subplebbit);
|
||||
|
||||
// save the last Virtuoso state to restore it when navigating back
|
||||
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
|
||||
@@ -251,7 +291,7 @@ const Catalog = () => {
|
||||
{location.pathname.endsWith('/settings') && <SettingsModal />}
|
||||
<hr />
|
||||
<div className={styles.catalog}>
|
||||
{feed.length !== 0 ? (
|
||||
{combinedFeed.length !== 0 ? (
|
||||
<>
|
||||
<Virtuoso
|
||||
increaseViewportBy={{ bottom: 1200, top: 1200 }}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
|
||||
.boardsBox {
|
||||
overflow: hidden;
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
.boardsBox table {
|
||||
display: table;
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
table-layout: fixed;
|
||||
width: calc(100% + 4px);
|
||||
margin-left: -2px;
|
||||
border-collapse: separate;
|
||||
border-spacing: 2px 0;
|
||||
}
|
||||
|
||||
.boardsBox table thead th {
|
||||
background: #fca;
|
||||
color: #800;
|
||||
border: 1px solid #800;
|
||||
padding: 4px 15px 5px 5px;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.boardsBox table tbody td {
|
||||
margin: 0;
|
||||
padding: 4px 15px 4px 4px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.boardsBox table tbody tr:nth-of-type( even ) {
|
||||
background: #ede2d4;
|
||||
}
|
||||
|
||||
.boardCell {
|
||||
position: static;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.offlineIconContainer {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.offlineIcon {
|
||||
vertical-align: text-top;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
image-rendering: pixelated;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.boardCell a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.loadingBoardCellValue {
|
||||
color: var(--topbar-separator-color);
|
||||
}
|
||||
|
||||
.loadMoreButton {
|
||||
text-align: center;
|
||||
margin-bottom: 14px;
|
||||
color: var(--topbar-separator-color);
|
||||
}
|
||||
|
||||
.displayCount {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.loadMoreButton span {
|
||||
color: var(--topbar-desktop-link-text-color);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.loadMoreButton span:hover {
|
||||
cursor: pointer;
|
||||
color: var(--button-desktop-text-color-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.nsfw {
|
||||
color: red;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.boardPPH {
|
||||
width: 33px;
|
||||
}
|
||||
@@ -3,17 +3,18 @@ import { Link, useLocation } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import { Subplebbit, useSubplebbit, useSubplebbitStats } from '@plebbit/plebbit-react-hooks';
|
||||
import { useDefaultSubplebbitTags } from '../../../hooks/use-default-subplebbits-tags';
|
||||
import { useDefaultSubplebbitsState } from '../../../hooks/use-default-subplebbits';
|
||||
import { useDefaultSubplebbitTags } from '../../../hooks/use-default-subplebbits-tags';
|
||||
import useIsMobile from '../../../hooks/use-is-mobile';
|
||||
import useIsSubplebbitOffline from '../../../hooks/use-is-subplebbit-offline';
|
||||
import styles from '../home.module.css';
|
||||
import { nsfwTags } from '../home';
|
||||
import LoadingEllipsis from '../../../components/loading-ellipsis';
|
||||
import Tooltip from '../../../components/tooltip';
|
||||
import styles from './boards-list.module.css';
|
||||
import { nsfwTags } from '../home';
|
||||
|
||||
const Board = ({ subplebbit, isMobile }: { subplebbit: Subplebbit; isMobile: boolean }) => {
|
||||
const { t } = useTranslation();
|
||||
const { address, title, tags } = subplebbit || {};
|
||||
const { address, tags } = subplebbit || {};
|
||||
const nsfwTag = tags?.find((tag: string) => nsfwTags.includes(tag));
|
||||
|
||||
let stats = useSubplebbitStats({ subplebbitAddress: address });
|
||||
@@ -24,22 +25,40 @@ const Board = ({ subplebbit, isMobile }: { subplebbit: Subplebbit; isMobile: boo
|
||||
const displayAddress = address && Plebbit.getShortAddress(address);
|
||||
const showOfflineIcon = address && (isOffline || isOnlineStatusLoading);
|
||||
|
||||
const title =
|
||||
subplebbitData?.title ||
|
||||
(subplebbitData?.updatedAt ? (
|
||||
displayAddress.endsWith('.eth') || displayAddress.endsWith('.sol') ? (
|
||||
displayAddress.slice(0, -4)
|
||||
) : (
|
||||
displayAddress
|
||||
)
|
||||
) : (
|
||||
<span className={styles.loadingBoardCellValue}>{isOffline ? t('board_not_reachable') : t('loading_board')}</span>
|
||||
));
|
||||
|
||||
return (
|
||||
<tr className={styles.subplebbit} key={address}>
|
||||
<td className={styles.boardAddress}>
|
||||
<tr key={address}>
|
||||
<td>
|
||||
<p className={styles.boardCell}>
|
||||
{showOfflineIcon && <span className={`${styles.offlineIcon} ${offlineIconClass}`} title={offlineTitle} />}
|
||||
<Link to={`/p/${address}`}>{displayAddress}</Link>
|
||||
{nsfwTag && <span className={styles.nsfw}> ({t(nsfwTag)})</span>}
|
||||
{showOfflineIcon && (
|
||||
<span className={styles.offlineIconContainer}>
|
||||
<Tooltip content={offlineTitle}>
|
||||
<span className={`${styles.offlineIcon} ${offlineIconClass}`} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
</td>
|
||||
<td className={styles.boardTitle}>
|
||||
<p className={styles.boardCell}>{title || displayAddress}</p>
|
||||
<td>
|
||||
<p className={styles.boardCell}>{title}</p>
|
||||
</td>
|
||||
{!isMobile && (
|
||||
<>
|
||||
<td className={styles.boardPPH}>
|
||||
<p className={styles.boardCell}>{stats.hourPostCount ?? '?'}</p>
|
||||
<p className={styles.boardCell}>{stats.hourPostCount ?? <span className={styles.loadingBoardCellValue}>?</span>}</p>
|
||||
</td>
|
||||
<td className={styles.boardTags}>
|
||||
<p className={styles.boardCell}>
|
||||
|
||||
@@ -29,11 +29,6 @@
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.boardsBox {
|
||||
overflow: hidden;
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -41,86 +36,6 @@
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.offlineIcon {
|
||||
display: inline-block;
|
||||
vertical-align: text-top;
|
||||
margin-right: 2px;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.boardsBox table {
|
||||
display: table;
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
table-layout: fixed;
|
||||
width: calc(100% + 4px);
|
||||
margin-left: -2px;
|
||||
border-collapse: separate;
|
||||
border-spacing: 2px 0;
|
||||
}
|
||||
|
||||
.boardsBox table thead th {
|
||||
background: #fca;
|
||||
color: #800;
|
||||
border: 1px solid #800;
|
||||
padding: 4px 15px 5px 5px;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.boardsBox table tbody td {
|
||||
margin: 0;
|
||||
padding: 4px 15px 4px 4px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.boardsBox table tbody tr:nth-of-type( even ) {
|
||||
background: #ede2d4;
|
||||
}
|
||||
|
||||
.boardCell {
|
||||
position: static;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.boardCell a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.loadMoreButton {
|
||||
text-align: center;
|
||||
margin-bottom: 14px;
|
||||
color: var(--topbar-separator-color);
|
||||
}
|
||||
|
||||
.displayCount {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.loadMoreButton span {
|
||||
color: var(--topbar-desktop-link-text-color);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.loadMoreButton span:hover {
|
||||
cursor: pointer;
|
||||
color: var(--button-desktop-text-color-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.boxBar, .infoboxBar {
|
||||
padding-left: 0.5em;
|
||||
line-height: 2em;
|
||||
@@ -245,13 +160,6 @@
|
||||
content: '✔ ';
|
||||
}
|
||||
|
||||
.nsfw {
|
||||
color: red;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
@@ -338,10 +246,6 @@
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.boardPPH {
|
||||
width: 33px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.content {
|
||||
min-width: 0;
|
||||
|
||||
@@ -9,6 +9,7 @@ import useSubplebbitsStats from '../../hooks/use-subplebbits-stats';
|
||||
import PopularThreadsBox from './popular-threads-box';
|
||||
import BoardsList from './boards-list';
|
||||
import Version from '../../components/version';
|
||||
import _ from 'lodash';
|
||||
|
||||
// https://github.com/plebbit/temporary-default-subplebbits/blob/master/README.md
|
||||
// plebchan shouldn't consider 'vulgar' or 'anti' as nsfw tags, unlike more sfw-oriented clients
|
||||
@@ -35,7 +36,7 @@ const SearchBar = () => {
|
||||
spellCheck='false'
|
||||
autoCapitalize='off'
|
||||
type='text'
|
||||
placeholder={`"board.eth/.sol" ${t('or')} "12D3KooW..."`}
|
||||
placeholder={_.lowerCase(t('enter_board_address'))}
|
||||
ref={searchInputRef}
|
||||
/>
|
||||
<button className={styles.searchButton}>{t('go')}</button>
|
||||
|
||||
@@ -221,7 +221,6 @@
|
||||
|
||||
.stateString {
|
||||
color: var(--post-mobile-abbr-text-color);
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.loadingString {
|
||||
|
||||
Reference in New Issue
Block a user