Merge pull request #517 from plebbit/development

Development
This commit is contained in:
Tom (plebeius.eth)
2024-09-03 12:09:13 +02:00
committed by GitHub
54 changed files with 470 additions and 195 deletions
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "بواسطة",
"last_reply_by": "آخر رد بواسطة",
"showing_all_replies": "عرض جميع الردود.",
"highlight_posts": سليط الضوء على المشاركات من خلال هذا العنوان للمستخدم",
"highlight_posts": مييز المشاركات بواسطة هذا المعرف",
"display_name_too_long": "اسم العرض طويل جداً",
"title_too_long": "العنوان طويل جداً",
"1_post_by_this_id": "مشاركة واحدة بهذا المعرف",
@@ -221,5 +221,10 @@
"hide_gore_boards": "إخفاء لوحات الجور",
"hide_adult_boards": "إخفاء لوحات الكبار",
"static_gif": "GIF ثابت",
"animated_gif": "GIF متحرك"
"animated_gif": "GIF متحرك",
"hide_avatars": "إخفاء الصور الرمزية",
"anon_mode": "وضع مجهول",
"anon_mode_description": "يتم استخدام معرف مستخدم مختلف تلقائيًا في كل موضوع",
"pending": "قيد الانتظار",
"failed": "فشل"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "দ্বারা",
"last_reply_by": "শেষ উত্তর দেননি",
"showing_all_replies": "সব উত্তর দেখাচ্ছি।",
"highlight_posts": "এই ব্যবহারকারী ঠিকানা দ্বারা পোস্টগুলি হাইলাইট করুন",
"highlight_posts": "এই আইডি দ্বারা পোস্ট হাইলাইট করুন",
"display_name_too_long": "প্রদর্শনী নাম অত্যন্ত দীর্ঘ",
"title_too_long": "শিরোনাম অত্যন্ত দীর্ঘ",
"1_post_by_this_id": "এই আইডি দ্বারা 1 পোস্ট",
@@ -221,5 +221,10 @@
"hide_gore_boards": "গর বোর্ডস লুকান",
"hide_adult_boards": "পুরুষ বোর্ডস লুকান",
"static_gif": "স্ট্যাটিক GIF",
"animated_gif": "অ্যানিমেটেড GIF"
"animated_gif": "অ্যানিমেটেড GIF",
"hide_avatars": "অ্যাভাটার লুকান",
"anon_mode": "অজ্ঞাত মোড",
"anon_mode_description": "প্রতিটি থ্রেডে স্বয়ংক্রিয়ভাবে একটি ভিন্ন ব্যবহারকারীর আইডি ব্যবহার করুন",
"pending": "অপেক্ষমাণ",
"failed": "ব্যর্থ"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "od",
"last_reply_by": "Poslední odpověď od",
"showing_all_replies": "Zobrazuji všechny odpovědi.",
"highlight_posts": "Zraznit příspěvky z této uživatelské adresy",
"highlight_posts": "Zraznit příspěvky podle tohoto ID",
"display_name_too_long": "Zobrazované jméno je příliš dlouhé",
"title_too_long": "Název je příliš dlouhý",
"1_post_by_this_id": "1 příspěvek s tímto ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Skrýt gore desky",
"hide_adult_boards": "Skrýt dospělé desky",
"static_gif": "Statický GIF",
"animated_gif": "Animovaný GIF"
"animated_gif": "Animovaný GIF",
"hide_avatars": "Skrýt avatary",
"anon_mode": "Anonymní režim",
"anon_mode_description": "Automaticky používejte jiný uživatelský ID v každém vlákně",
"pending": "Čeká na schválení",
"failed": "Nepodařilo se"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "af",
"last_reply_by": "Seneste svar fra",
"showing_all_replies": "Viser alle svar.",
"highlight_posts": "Fremhæv indlæg fra denne brugeradresse",
"highlight_posts": "Fremhæv indlæg fra denne ID",
"display_name_too_long": "Visningsnavn for langt",
"title_too_long": "Titel for lang",
"1_post_by_this_id": "1 post med dette ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Skjul Gore Boards",
"hide_adult_boards": "Skjul Voksne Boards",
"static_gif": "Statisk GIF",
"animated_gif": "Animeret GIF"
"animated_gif": "Animeret GIF",
"hide_avatars": "Skjul avatarer",
"anon_mode": "Anonim tilstand",
"anon_mode_description": "Brug automatisk en anden bruger-ID i hver tråd",
"pending": "Afventer",
"failed": "Mislykkedes"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "von",
"last_reply_by": "Letzte Antwort von",
"showing_all_replies": "Zeige alle Antworten.",
"highlight_posts": "Beiträge von dieser Benutzeradresse hervorheben",
"highlight_posts": "Beiträge nach dieser ID hervorheben",
"display_name_too_long": "Angezeigter Name zu lang",
"title_too_long": "Titel zu lang",
"1_post_by_this_id": "1 Beitrag mit dieser ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Gore-Boards ausblenden",
"hide_adult_boards": "Erwachsenen-Boards ausblenden",
"static_gif": "Statisches GIF",
"animated_gif": "Animiertes GIF"
"animated_gif": "Animiertes GIF",
"hide_avatars": "Avatare ausblenden",
"anon_mode": "Anonymer Modus",
"anon_mode_description": "Verwenden Sie automatisch eine andere Benutzer-ID in jedem Thread",
"pending": "Ausstehend",
"failed": "Fehlgeschlagen"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "από",
"last_reply_by": "Τελευταία απάντηση από",
"showing_all_replies": "Εμφανίζονται όλες οι απαντήσεις.",
"highlight_posts": "Επισήμανση δημοσιεύσεων από αυτήν τη διεύθυνση χρήστη",
"highlight_posts": "Επισήμανση αναρτήσεων με αυτήν την ταυτότητα",
"display_name_too_long": "Το όνομα εμφάνισης είναι πολύ μεγάλο",
"title_too_long": "Το τίτλος είναι πολύ μεγάλος",
"1_post_by_this_id": "1 ανάρτηση με αυτό το ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Απόκρυψη των Gore Boards",
"hide_adult_boards": "Απόκρυψη των Adult Boards",
"static_gif": "Στατικό GIF",
"animated_gif": "Κινούμενο GIF"
"animated_gif": "Κινούμενο GIF",
"hide_avatars": "Απόκρυψη avatars",
"anon_mode": "Λειτουργία ανωνυμίας",
"anon_mode_description": "Χρησιμοποιήστε αυτόματα διαφορετικό αναγνωριστικό χρήστη σε κάθε νήμα",
"pending": "Σε εκκρεμότητα",
"failed": "Απέτυχε"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "by",
"last_reply_by": "Last reply by",
"showing_all_replies": "Showing all replies.",
"highlight_posts": "Highlight posts by this user address",
"highlight_posts": "Highlight posts by this ID",
"display_name_too_long": "display name too long",
"title_too_long": "title too long",
"1_post_by_this_id": "1 post by this ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Hide Gore Boards",
"hide_adult_boards": "Hide Adult Boards",
"static_gif": "Static GIF",
"animated_gif": "Animated GIF"
"animated_gif": "Animated GIF",
"hide_avatars": "Hide avatars",
"anon_mode": "Anon mode",
"anon_mode_description": "Automatically use a different user ID in each thread",
"pending": "Pending",
"failed": "Failed"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "por",
"last_reply_by": "Última respuesta de",
"showing_all_replies": "Mostrando todas las respuestas.",
"highlight_posts": "Resaltar publicaciones de esta dirección de usuario",
"highlight_posts": "Resaltar publicaciones por este ID",
"display_name_too_long": "nombre de visualización demasiado largo",
"title_too_long": "título demasiado largo",
"1_post_by_this_id": "1 publicación con este ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Ocultar tableros de gore",
"hide_adult_boards": "Ocultar tableros para adultos",
"static_gif": "GIF Estático",
"animated_gif": "GIF Animado"
"animated_gif": "GIF Animado",
"hide_avatars": "Ocultar avatares",
"anon_mode": "Modo anónimo",
"anon_mode_description": "Utiliza automáticamente un ID de usuario diferente en cada hilo",
"pending": "Pendiente",
"failed": "Fallido"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "توسط",
"last_reply_by": "آخرین پاسخ توسط",
"showing_all_replies": "نمایش تمام پاسخ‌ها.",
"highlight_posts": "برجسته سازی پست ها از این آدرس کاربر",
"highlight_posts": "برجسته کردن پستها با این شناسه",
"display_name_too_long": "نام نمایشی خیلی طولانی است",
"title_too_long": "عنوان خیلی طولانی است",
"1_post_by_this_id": "1 پست با این شناسه",
@@ -221,5 +221,10 @@
"hide_gore_boards": "پنهان کردن تخته های گور",
"hide_adult_boards": "پنهان کردن تخته های بزرگسالان",
"static_gif": "GIF ثابت",
"animated_gif": "GIF متحرک"
"animated_gif": "GIF متحرک",
"hide_avatars": "پنهان کردن آواتارها",
"anon_mode": "حالت ناشناس",
"anon_mode_description": "به طور خودکار از یک شناسه کاربری متفاوت در هر موضوع استفاده کنید",
"pending": "در انتظار",
"failed": "ناموفق"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "kirjoittanut",
"last_reply_by": "Viimeisin vastaus",
"showing_all_replies": "Näytetään kaikki vastaukset.",
"highlight_posts": "Korosta tämän käyttäjän osoitteen viestit",
"highlight_posts": "Korosta postauksia tällä ID:llä",
"display_name_too_long": "Näyttönimi liian pitkä",
"title_too_long": "Otsikko on liian pitkä",
"1_post_by_this_id": "1 viesti tällä tunnuksella",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Piilota Gore-laudat",
"hide_adult_boards": "Piilota Aikuisten lautat",
"static_gif": "Staattinen GIF",
"animated_gif": "Animoitu GIF"
"animated_gif": "Animoitu GIF",
"hide_avatars": "Piilota avatarit",
"anon_mode": "Anonyymi tila",
"anon_mode_description": "Käytä automaattisesti eri käyttäjä-ID:tä jokaisessa keskustelussa",
"pending": "Odottaa",
"failed": "Epäonnistui"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "ni",
"last_reply_by": "Huling sagot ni",
"showing_all_replies": "Nagpapakita ng lahat ng mga sagot.",
"highlight_posts": "I-highlight ang mga post mula sa user address na ito",
"highlight_posts": "I-highlight ang mga post gamit ang ID na ito",
"display_name_too_long": "ang display name ay masyadong mahaba",
"title_too_long": "ang pamagat ay masyadong mahaba",
"1_post_by_this_id": "1 post sa pamamagitan ng ID na ito",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Itago ang mga Gore Boards",
"hide_adult_boards": "Itago ang mga Adult Boards",
"static_gif": "Static GIF",
"animated_gif": "Animated GIF"
"animated_gif": "Animated GIF",
"hide_avatars": "Itago ang mga avatar",
"anon_mode": "Anong mode",
"anon_mode_description": "Awtomatikong gamitin ang ibang user ID sa bawat thread",
"pending": "Naghihintay",
"failed": "Nabigo"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "par",
"last_reply_by": "Dernière réponse par",
"showing_all_replies": "Affichage de toutes les réponses.",
"highlight_posts": "Mettre en évidence les messages de cette adresse utilisateur",
"highlight_posts": "Mettre en évidence les publications par cet ID",
"display_name_too_long": "nom d'affichage trop long",
"title_too_long": "titre trop long",
"1_post_by_this_id": "1 publication avec cet identifiant",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Masquer les tableaux Gore",
"hide_adult_boards": "Masquer les tableaux pour adultes",
"static_gif": "GIF Statique",
"animated_gif": "GIF Animé"
"animated_gif": "GIF Animé",
"hide_avatars": "Masquer les avatars",
"anon_mode": "Mode anonyme",
"anon_mode_description": "Utilisez automatiquement un identifiant utilisateur différent dans chaque fil",
"pending": "En attente",
"failed": "Échoué"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "על ידי",
"last_reply_by": "תגובה אחרונה מאת",
"showing_all_replies": "מציג את כל התגובות.",
"highlight_posts": "הדגשת הודעות מכתובת המשתמש הזו",
"highlight_posts": "הדגש פוסטים לפי מזהה זה",
"display_name_too_long": "שם התצוגה ארוך מדי",
"title_too_long": "הכותרת ארוכה מדי",
"1_post_by_this_id": "פוסט אחד עם המזהה הזה",
@@ -221,5 +221,10 @@
"hide_gore_boards": "הסתר לוחות Gore",
"hide_adult_boards": "הסתר לוחות המבוגרים",
"static_gif": "GIF סטטי",
"animated_gif": "GIF מונפש"
"animated_gif": "GIF מונפש",
"hide_avatars": "הסתר את התמונות האישיות",
"anon_mode": "מצב אנונימי",
"anon_mode_description": "השתמש אוטומטית במזהה משתמש שונה בכל שרשור",
"pending": "ממתין",
"failed": "נכשל"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "द्वारा",
"last_reply_by": "अंतिम उत्तर दिया गया है",
"showing_all_replies": "सभी उत्तर दिखा रहा है।",
"highlight_posts": "इस उपयोगकर्ता पते से पोस्ट्स को हाइलाइट करें",
"highlight_posts": "इस ID द्वारा पोस्ट को हाइलाइट करें",
"display_name_too_long": "प्रदर्शन नाम बहुत लंबा है",
"title_too_long": "शीर्षक बहुत लंबा है",
"1_post_by_this_id": "इस आईडी द्वारा 1 पोस्ट",
@@ -221,5 +221,10 @@
"hide_gore_boards": "गोर बोर्ड्स छिपाएं",
"hide_adult_boards": "वयस्क बोर्ड्स छिपाएं",
"static_gif": "स्थिर GIF",
"animated_gif": "एनिमेटेड GIF"
"animated_gif": "एनिमेटेड GIF",
"hide_avatars": "अवतार छिपाएँ",
"anon_mode": "अनाम मोड",
"anon_mode_description": "प्रत्येक थ्रेड में स्वचालित रूप से एक अलग उपयोगकर्ता आईडी का उपयोग करें",
"pending": "लंबित",
"failed": "असफल"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "által",
"last_reply_by": "Utolsó válasz írta",
"showing_all_replies": "Az összes válasz megjelenítése.",
"highlight_posts": "Kiemelt bejegyzések ebből a felhasználói címből",
"highlight_posts": "Kiemelés ezen ID által",
"display_name_too_long": "a megjelenített név túl hosszú",
"title_too_long": "a cím túl hosszú",
"1_post_by_this_id": "1 bejegyzés ezzel az azonosítóval",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Gore táblák elrejtése",
"hide_adult_boards": "Felnőtt táblák elrejtése",
"static_gif": "Statikus GIF",
"animated_gif": "Animált GIF"
"animated_gif": "Animált GIF",
"hide_avatars": "Avatarok elrejtése",
"anon_mode": "Anonim mód",
"anon_mode_description": "Automatikusan használjon más felhasználói azonosítót minden szálban",
"pending": "Függőben",
"failed": "Sikertelen"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "oleh",
"last_reply_by": "Balasan terakhir oleh",
"showing_all_replies": "Menampilkan semua balasan.",
"highlight_posts": "Sorot posting dari alamat pengguna ini",
"highlight_posts": "Sorot pos dengan ID ini",
"display_name_too_long": "nama tampilan terlalu panjang",
"title_too_long": "judul terlalu panjang",
"1_post_by_this_id": "1 pos dengan ID ini",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Sembunyikan Papan Gore",
"hide_adult_boards": "Sembunyikan Papan Dewasa",
"static_gif": "GIF Statis",
"animated_gif": "GIF Animasi"
"animated_gif": "GIF Animasi",
"hide_avatars": "Sembunyikan avatar",
"anon_mode": "Mode anonim",
"anon_mode_description": "Secara otomatis gunakan ID pengguna yang berbeda di setiap utas",
"pending": "Tertunda",
"failed": "Gagal"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "da",
"last_reply_by": "Ultima risposta da",
"showing_all_replies": "Mostrando tutte le risposte.",
"highlight_posts": "Evidenziare i post da questo indirizzo di utente",
"highlight_posts": "Evidenzia i post con questo ID",
"display_name_too_long": "nome visualizzato troppo lungo",
"title_too_long": "titolo troppo lungo",
"1_post_by_this_id": "1 post con questo ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Nascondi tavole Gore",
"hide_adult_boards": "Nascondi tavole per adulti",
"static_gif": "GIF Statica",
"animated_gif": "GIF Animata"
"animated_gif": "GIF Animata",
"hide_avatars": "Nascondi avatar",
"anon_mode": "Modalità anonima",
"anon_mode_description": "Usa automaticamente un ID utente diverso in ogni thread",
"pending": "In attesa",
"failed": "Fallito"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "によって",
"last_reply_by": "最後の返信者",
"showing_all_replies": "すべての返信を表示しています。",
"highlight_posts": "このユーザーアドレスによる投稿を強調表示する",
"highlight_posts": "このIDによる投稿を強調表示",
"display_name_too_long": "表示名が長すぎます",
"title_too_long": "タイトルが長すぎます",
"1_post_by_this_id": "このIDで1件の投稿",
@@ -221,5 +221,10 @@
"hide_gore_boards": "ゴアボードを非表示にする",
"hide_adult_boards": "アダルトボードを非表示にする",
"static_gif": "静的GIF",
"animated_gif": "アニメーションGIF"
"animated_gif": "アニメーションGIF",
"hide_avatars": "アバターを隠す",
"anon_mode": "匿名モード",
"anon_mode_description": "各スレッドで自動的に異なるユーザーIDを使用します",
"pending": "保留中",
"failed": "失敗"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "작성자:",
"last_reply_by": "마지막 답글 작성자:",
"showing_all_replies": "모든 답글을 표시합니다.",
"highlight_posts": "이 사용자 주소의 게시물 강조 표시",
"highlight_posts": "이 ID로 게시물 강조 표시",
"display_name_too_long": "표시 이름이 너무 깁니다",
"title_too_long": "제목이 너무 깁니다",
"1_post_by_this_id": "이 ID로 게시된 1개의 글",
@@ -221,5 +221,10 @@
"hide_gore_boards": "고어 게시판 숨기기",
"hide_adult_boards": "성인 게시판 숨기기",
"static_gif": "정적 GIF",
"animated_gif": "애니메이션 GIF"
"animated_gif": "애니메이션 GIF",
"hide_avatars": "아바타 숨기기",
"anon_mode": "익명 모드",
"anon_mode_description": "각 스레드에서 자동으로 다른 사용자 ID를 사용합니다",
"pending": "대기 중",
"failed": "실패"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "व्यक्ती",
"last_reply_by": "शेवटचा प्रतिसाद व्यक्ती",
"showing_all_replies": "सर्व प्रतिसाद दाखवत आहे.",
"highlight_posts": "या वापरकर्त्याच्या पत्त्यापासून पोस्ट्स हायलाइट करा",
"highlight_posts": "या ID द्वारे पोस्ट हायलाइट करा",
"display_name_too_long": "डिस्प्ले नाम खूप लांब आहे",
"title_too_long": "शीर्षक खूप लांब आहे",
"1_post_by_this_id": "या ID वर 1 पोस्ट",
@@ -221,5 +221,10 @@
"hide_gore_boards": "गोर बोर्ड्स लपवा",
"hide_adult_boards": "वयस्क बोर्ड्स लपवा",
"static_gif": "स्थिर GIF",
"animated_gif": "एनिमेटेड GIF"
"animated_gif": "एनिमेटेड GIF",
"hide_avatars": "अवतार लपवा",
"anon_mode": "अनाम मोड",
"anon_mode_description": "प्रत्येक थ्रेडमध्ये स्वयंचलितपणे वेगळा वापरकर्ता ID वापरा",
"pending": "प्रलंबित",
"failed": "असफल"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "door",
"last_reply_by": "Laatste reactie door",
"showing_all_replies": "Alle antwoorden weergeven.",
"highlight_posts": "Berichten van dit gebruikersadres markeren",
"highlight_posts": "Markeer berichten op basis van deze ID",
"display_name_too_long": "weergavenaam te lang",
"title_too_long": "titel te lang",
"1_post_by_this_id": "1 bericht met dit ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Gore Boards verbergen",
"hide_adult_boards": "Volwassenen Boards verbergen",
"static_gif": "Statische GIF",
"animated_gif": "Geanimeerde GIF"
"animated_gif": "Geanimeerde GIF",
"hide_avatars": "Avatars verbergen",
"anon_mode": "Anoniem modus",
"anon_mode_description": "Gebruik automatisch een ander gebruikers-ID in elk thread",
"pending": "In afwachting",
"failed": "Mislukt"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "av",
"last_reply_by": "Siste svar fra",
"showing_all_replies": "Viser alle svar.",
"highlight_posts": "Fremhev innlegg fra denne brukeradressen",
"highlight_posts": "Uthev innlegg med denne ID-en",
"display_name_too_long": "visningsnavn for langt",
"title_too_long": "tittel for lang",
"1_post_by_this_id": "1 post med denne ID-en",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Skjul Gore Boards",
"hide_adult_boards": "Skjul voksne Boards",
"static_gif": "Statisk GIF",
"animated_gif": "Animasjons GIF"
"animated_gif": "Animasjons GIF",
"hide_avatars": "Skjul avatarer",
"anon_mode": "Anonim modus",
"anon_mode_description": "Bruk automatisk en annen bruker-ID i hver tråd",
"pending": "Venter",
"failed": "Feilet"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "przez",
"last_reply_by": "Ostatnia odpowiedź od",
"showing_all_replies": "Wyświetlanie wszystkich odpowiedzi.",
"highlight_posts": "Wyróżnij posty z tego adresu użytkownika",
"highlight_posts": "Wyróżnij posty według tego ID",
"display_name_too_long": "nazwa wyświetlana jest zbyt długa",
"title_too_long": "tytuł jest zbyt długi",
"1_post_by_this_id": "1 post z tym identyfikatorem",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Ukryj Gore Boards",
"hide_adult_boards": "Ukryj Adult Boards",
"static_gif": "Statyczny GIF",
"animated_gif": "Animowany GIF"
"animated_gif": "Animowany GIF",
"hide_avatars": "Ukryj awatary",
"anon_mode": "Tryb anonimowy",
"anon_mode_description": "Automatycznie używaj innego identyfikatora użytkownika w każdym wątku",
"pending": "Oczekujące",
"failed": "Nieudane"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "por",
"last_reply_by": "Última resposta por",
"showing_all_replies": "Mostrando todas as respostas.",
"highlight_posts": "Destacar postagens deste endereço de usuário",
"highlight_posts": "Destaque posts por este ID",
"display_name_too_long": "nome de exibição muito longo",
"title_too_long": "título muito longo",
"1_post_by_this_id": "1 post com este ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Ocultar Quadros Gore",
"hide_adult_boards": "Ocultar Quadros para Adultos",
"static_gif": "GIF Estático",
"animated_gif": "GIF Animado"
"animated_gif": "GIF Animado",
"hide_avatars": "Ocultar avatares",
"anon_mode": "Modo anônimo",
"anon_mode_description": "Use automaticamente um ID de usuário diferente em cada thread",
"pending": "Pendente",
"failed": "Falhou"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "de către",
"last_reply_by": "Ultima răspuns de la",
"showing_all_replies": "Afișare toate răspunsurile.",
"highlight_posts": "Evidențiați mesajele de la această adresă de utilizator",
"highlight_posts": "Subliniați postările după acest ID",
"display_name_too_long": "numele afișat este prea lung",
"title_too_long": "titlul este prea lung",
"1_post_by_this_id": "1 post cu acest ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Ascundeți tablourile Gore",
"hide_adult_boards": "Ascundeți tablourile pentru adulți",
"static_gif": "GIF Static",
"animated_gif": "GIF Animat"
"animated_gif": "GIF Animat",
"hide_avatars": "Ascunde avatarele",
"anon_mode": "Mod anonim",
"anon_mode_description": "Utilizați automat un ID de utilizator diferit în fiecare fir",
"pending": "În așteptare",
"failed": "Eșuat"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "от",
"last_reply_by": "Последний ответ от",
"showing_all_replies": "Показываются все ответы.",
"highlight_posts": "Выделить сообщения с этого адреса пользователя",
"highlight_posts": "Выделить посты по этому ID",
"display_name_too_long": "отображаемое имя слишком длинное",
"title_too_long": "заголовок слишком длинный",
"1_post_by_this_id": "1 сообщение с этим идентификатором",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Скрыть доски Gore",
"hide_adult_boards": "Скрыть доски для взрослых",
"static_gif": "Статичный GIF",
"animated_gif": "Анимированный GIF"
"animated_gif": "Анимированный GIF",
"hide_avatars": "Скрыть аватары",
"anon_mode": "Анонимный режим",
"anon_mode_description": "Автоматически используйте другой идентификатор пользователя в каждом потоке",
"pending": "В ожидании",
"failed": "Не удалось"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "nga",
"last_reply_by": "Përgjigje e fundit nga",
"showing_all_replies": "Duke treguar të gjitha përgjigjet.",
"highlight_posts": "Shëno postime nga ky adresa e përdoruesit",
"highlight_posts": "Dallo postimet sipas këtij ID",
"display_name_too_long": "emri i shfaqur është shumë i gjatë",
"title_too_long": "titulli shumë i gjatë",
"1_post_by_this_id": "1 postim me këtë ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Fshihet Gore Boards",
"hide_adult_boards": "Fshihet Adult Boards",
"static_gif": "GIF Statik",
"animated_gif": "GIF i Animuar"
"animated_gif": "GIF i Animuar",
"hide_avatars": "Fsheh avatarët",
"anon_mode": "Mënyra anonime",
"anon_mode_description": "Përdorni automatikisht një ID përdoruesi të ndryshëm në çdo temë",
"pending": "Në pritje",
"failed": "Dështuar"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "av",
"last_reply_by": "Senaste svar av",
"showing_all_replies": "Visar alla svar.",
"highlight_posts": "Markera inlägg från denna användaradress",
"highlight_posts": "Markera inlägg med detta ID",
"display_name_too_long": "visningsnamn för långt",
"title_too_long": "titel för långt",
"1_post_by_this_id": "1 inlägg med detta ID",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Dölj Gore Boards",
"hide_adult_boards": "Dölj vuxna Boards",
"static_gif": "Statisk GIF",
"animated_gif": "Animerad GIF"
"animated_gif": "Animerad GIF",
"hide_avatars": "Dölj avatarer",
"anon_mode": "Anonymt läge",
"anon_mode_description": "Använd automatiskt ett annat användar-ID i varje tråd",
"pending": "Väntande",
"failed": "Misslyckades"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "ద్వారా",
"last_reply_by": "చివరి సమాధానం ఇచ్చింది",
"showing_all_replies": "అన్ని సమాధానాలను చూపుతుంది.",
"highlight_posts": "ఈ వాడుకరి చిరునామ నుండి పోస్టలను హైలైట్ చేయండి",
"highlight_posts": "ఈ ID ద్వారా పోస్ట్‌లను హైలైట్ చేయండి",
"display_name_too_long": "ప్రదర్శన పేరు చాలా నీటిగా ఉంది",
"title_too_long": "శీర్షిక చాలా పొడవుగా ఉంది",
"1_post_by_this_id": "ఈ ID ద్వారా 1 పోస్టు",
@@ -221,5 +221,10 @@
"hide_gore_boards": "గోర్ బోర్డ్స్ దాచు",
"hide_adult_boards": "పురుషులు బోర్డ్లు దాచు",
"static_gif": "స్టాటిక్ GIF",
"animated_gif": "అనిమేటెడ్ GIF"
"animated_gif": "అనిమేటెడ్ GIF",
"hide_avatars": "అవతార్లను దాచు",
"anon_mode": "అనానిమస్ మోడ్",
"anon_mode_description": "ప్రతి థ్రెడ్లో ఆటోమేటిక్‌గా ఒక వేరు వినియోగదారుడి ID ఉపయోగించండి",
"pending": "అనుమతించబడాలి",
"failed": "విజయవంతం కాలేదు"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "โดย",
"last_reply_by": "การตอบคำถามล่าสุดโดย",
"showing_all_replies": "กำลังแสดงคำตอบทั้งหมด",
"highlight_posts": "เน้นโพสต์โดยที่อยู่ผู้ใช้นี้",
"highlight_posts": "เน้นโพสต์โดย ID นี้",
"display_name_too_long": "ชื่อที่แสดงนามสกุลยาวเกินไป",
"title_too_long": "ชื่อเรื่องยาวเกินไป",
"1_post_by_this_id": "1 โพสต์โดย ID นี้",
@@ -221,5 +221,10 @@
"hide_gore_boards": "ซ่อนกระดาน Gore",
"hide_adult_boards": "ซ่อนกระดานสำหรับผู้ใหญ่",
"static_gif": "GIF แบบคงที่",
"animated_gif": "GIF ที่เคลื่อนไหว"
"animated_gif": "GIF ที่เคลื่อนไหว",
"hide_avatars": "ซ่อนอวาตาร์",
"anon_mode": "โหมดนิรนาม",
"anon_mode_description": "ใช้ ID ผู้ใช้ที่แตกต่างกันโดยอัตโนมัติในแต่ละเธรด",
"pending": "รอดำเนินการ",
"failed": "ล้มเหลว"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "tarafından",
"last_reply_by": "Son cevap",
"showing_all_replies": "Tüm yanıtlar gösteriliyor.",
"highlight_posts": "Bu kullanıcı adresinden gelen gönderileri vurgula",
"highlight_posts": "Bu ID ile gönderileri vurgula",
"display_name_too_long": "görünen adı çok uzun",
"title_too_long": "başlık çok uzun",
"1_post_by_this_id": "Bu ID ile 1 gönderi",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Gore Panolarını Gizle",
"hide_adult_boards": "Yetişkin Panolarını Gizle",
"static_gif": "Statik GIF",
"animated_gif": "Animasyonlu GIF"
"animated_gif": "Animasyonlu GIF",
"hide_avatars": "Avatarları gizle",
"anon_mode": "Gizli mod",
"anon_mode_description": "Her iplikte otomatik olarak farklı bir kullanıcı ID'si kullanın",
"pending": "Beklemede",
"failed": "Başarısız"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "від",
"last_reply_by": "Остання відповідь від",
"showing_all_replies": "Показуються всі відповіді.",
"highlight_posts": "Виділити повідомлення з цієї адреси користувача",
"highlight_posts": "Виділити повідомлення за цим ID",
"display_name_too_long": "ім'я відображається занадто довге",
"title_too_long": "заголовок відображається занадто довгий",
"1_post_by_this_id": "1 пост з цим ідентифікатором",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Сховати дошки Gore",
"hide_adult_boards": "Сховати дошки для дорослих",
"static_gif": "Статичний GIF",
"animated_gif": "Анімований GIF"
"animated_gif": "Анімований GIF",
"hide_avatars": "Сховати аватари",
"anon_mode": "Режим анонімності",
"anon_mode_description": "Автоматично використовуйте інший ідентифікатор користувача в кожній гілці",
"pending": "Очікує",
"failed": "Не вдалося"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "کے ذریعے",
"last_reply_by": "آخری جواب دیا گیا",
"showing_all_replies": "تمام جوابات دکھا رہا ہے۔",
"highlight_posts": "اس صارف ایڈریس کے ذریعے پوسٹس کو ہائی لائٹ کریں",
"highlight_posts": "اس ID کے ذریعہ پوسٹس کو نمایاں کریں",
"display_name_too_long": "ڈسپلے نام بہت لمبا ہے",
"title_too_long": "عنوان بہت لمبا ہے",
"1_post_by_this_id": "اس آئی ڈی پر 1 پوسٹ",
@@ -221,5 +221,10 @@
"hide_gore_boards": "گور بورڈز چھپائیں",
"hide_adult_boards": "بالغ بورڈز چھپائیں",
"static_gif": "اسٹیٹک GIF",
"animated_gif": "اینیمیٹڈ GIF"
"animated_gif": "اینیمیٹڈ GIF",
"hide_avatars": "اوٹار چھپائیں",
"anon_mode": "خفیہ موڈ",
"anon_mode_description": "ہر تھریڈ میں خود بخود مختلف صارف آئی ڈی کا استعمال کریں",
"pending": "منتظر",
"failed": "ناکام"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "bởi",
"last_reply_by": "Trả lời cuối cùng bởi",
"showing_all_replies": "Đang hiển thị tất cả các phản hồi.",
"highlight_posts": "Đánh dấu bài đăng từ địa chỉ người dùng này",
"highlight_posts": "Nổi bật các bài viết bằng ID này",
"display_name_too_long": "tên hiển thị quá dài",
"title_too_long": "tiêu đề quá dài",
"1_post_by_this_id": "1 bài đăng bởi ID này",
@@ -221,5 +221,10 @@
"hide_gore_boards": "Ẩn Gore Boards",
"hide_adult_boards": "Ẩn Adult Boards",
"static_gif": "GIF Tĩnh",
"animated_gif": "GIF Hoạt Hình"
"animated_gif": "GIF Hoạt Hình",
"hide_avatars": "Ẩn avatar",
"anon_mode": "Chế độ ẩn danh",
"anon_mode_description": "Tự động sử dụng ID người dùng khác nhau trong mỗi chủ đề",
"pending": "Đang chờ",
"failed": "Thất bại"
}
+7 -2
View File
@@ -204,7 +204,7 @@
"by": "由...发布",
"last_reply_by": "最后回复者",
"showing_all_replies": "显示所有回复。",
"highlight_posts": "突出显示此用户地址的帖子",
"highlight_posts": "高亮显示此 ID 的帖子",
"display_name_too_long": "显示名称太长",
"title_too_long": "标题太长",
"1_post_by_this_id": "此ID的1篇帖子",
@@ -221,5 +221,10 @@
"hide_gore_boards": "隐藏Gore板块",
"hide_adult_boards": "隐藏成人板块",
"static_gif": "静态GIF",
"animated_gif": "动画GIF"
"animated_gif": "动画GIF",
"hide_avatars": "隐藏头像",
"anon_mode": "匿名模式",
"anon_mode_description": "在每个线程中自动使用不同的用户 ID",
"pending": "待处理",
"failed": "失败"
}
@@ -62,6 +62,7 @@
.editTextarea {
width: calc(100% - 12px);
height: 100px;
margin-left: 3px;
font-family: inherit;
}
+12 -8
View File
@@ -11,6 +11,7 @@ import useIsMobile from '../../hooks/use-is-mobile';
import CommentMedia from '../comment-media';
import styles from './markdown.module.css';
import { useLocation, useParams } from 'react-router-dom';
import { canEmbed } from '../embed';
interface ContentLinkEmbedProps {
children: any;
@@ -86,13 +87,15 @@ const ContentLinkEmbed = ({ children, href, linkMediaInfo }: ContentLinkEmbedPro
<CommentMedia isReply={false} setShowThumbnail={setShowMedia} commentMediaInfo={linkMediaInfo} showThumbnail={false} />
</>
)}
<FloatingPortal>
{isOpen && !isMobile && (
<div className={styles.floatingEmbed} ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
<CommentMedia isReply={false} isFloatingEmbed={true} setShowThumbnail={setShowMedia} commentMediaInfo={linkMediaInfo} showThumbnail={true} />
</div>
)}
</FloatingPortal>
{getHasThumbnail(linkMediaInfo, href) && (
<FloatingPortal>
{isOpen && !isMobile && (
<div className={styles.floatingEmbed} ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
<CommentMedia isReply={false} isFloatingEmbed={true} setShowThumbnail={setShowMedia} commentMediaInfo={linkMediaInfo} showThumbnail={true} />
</div>
)}
</FloatingPortal>
)}
</>
);
};
@@ -172,7 +175,8 @@ const Markdown = ({ content, title }: MarkdownProps) => {
a: ({ href, children }) => {
if (href && !isInCatalogView) {
const linkMediaInfo = getLinkMediaInfo(href);
if (getHasThumbnail(linkMediaInfo, href)) {
const embedUrl = new URL(href);
if (canEmbed(embedUrl) || getHasThumbnail(linkMediaInfo, href)) {
return <ContentLinkEmbed children={children} href={href} linkMediaInfo={linkMediaInfo} />;
} else {
return (
+25 -22
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react';
import { useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Link, useLocation, useParams } from 'react-router-dom';
import { Comment, useAccount, useAuthorAvatar, useComment, useEditedComment } from '@plebbit/plebbit-react-hooks';
@@ -9,9 +9,13 @@ import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/po
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
import { isValidURL } from '../../lib/utils/url-utils';
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
import useAnonModeStore from '../../stores/use-anon-mode-store';
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
import useAnonMode from '../../hooks/use-anon-mode';
import useAuthorAddressClick from '../../hooks/use-author-address-click';
import useEditCommentPrivileges from '../../hooks/use-author-privileges';
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
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';
@@ -26,7 +30,6 @@ import Tooltip from '../tooltip';
import { PostProps } from '../../views/post/post';
import { create } from 'zustand';
import _ from 'lodash';
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
interface ShowOmittedRepliesState {
showOmittedReplies: Record<string, boolean>;
@@ -46,7 +49,7 @@ const useShowOmittedReplies = create<ShowOmittedRepliesState>((set) => ({
const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }: PostProps) => {
const { t } = useTranslation();
const { author, cid, deleted, locked, pinned, parentCid, postCid, removed, replyCount, shortCid, state, subplebbitAddress, timestamp } = post || {};
const { author, cid, deleted, locked, pinned, parentCid, postCid, removed, shortCid, state, subplebbitAddress, timestamp } = post || {};
const title = post?.title?.trim();
const replies = useReplies(post);
const { address, shortAddress } = author || {};
@@ -57,6 +60,7 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
const isReply = parentCid;
const { showOmittedReplies } = useShowOmittedReplies();
const { imageUrl: avatarImageUrl } = useAuthorAvatar({ author });
const { hideAvatars } = useAvatarVisibilityStore();
const params = useParams();
const location = useLocation();
@@ -64,15 +68,19 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
const isInPostPageView = isPostPageView(location.pathname, params);
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
// comment.author.shortAddress is undefined while the comment publishing state is pending, use account instead
// in anon mode, use the newly generated signer.address instead, which will be comment.author.address
const { anonMode } = useAnonMode();
const { currentAnonSignerAddress } = useAnonModeStore();
const account = useAccount();
const accountShortAddress = account?.author?.shortAddress; // if reply by account is pending, it doesn't have an author yet
const pendingShortAddress = anonMode ? currentAnonSignerAddress && Plebbit.getShortAddress(currentAnonSignerAddress) : account?.author?.shortAddress;
const { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor } = useEditCommentPrivileges({ commentAuthorAddress: address, subplebbitAddress });
const handleUserAddressClick = useAuthorAddressClick();
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
const userID = shortAddress || accountShortAddress;
const userID = shortAddress || pendingShortAddress;
const userIDBackgroundColor = hashStringToColor(userID);
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
@@ -110,7 +118,7 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
</span>
{!(isDescription || isRules) && (
<>
{author?.avatar && !(deleted || removed) ? (
{author?.avatar && !(deleted || removed) && !hideAvatars ? (
<span className={styles.authorAvatar}>
<img src={avatarImageUrl} alt='' />
</span>
@@ -166,7 +174,9 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
) : (
<>
<span>c/</span>
<span className={styles.pendingCid}>{state === 'failed' || stateString === 'Failed' ? 'Failed' : 'Pending'}</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
</>
))}
{pinned && (
@@ -184,7 +194,7 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
[
<Link
to={isInAllView && isDescription ? '/p/all/description' : `/p/${subplebbitAddress}/${isDescription ? 'description' : isRules ? 'rules' : `c/${postCid}`}`}
onClick={(e) => !cid && e.preventDefault()}
onClick={(e) => !cid && !isDescription && !isRules && e.preventDefault()}
>
{_.capitalize(t('reply'))}
</Link>
@@ -193,10 +203,12 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
)}
</span>
<PostMenuDesktop post={post} />
{replyCount > 0 &&
{cid &&
parentCid &&
replies &&
replies.map((reply: Comment, index: number) => reply?.parentCid === cid && <ReplyQuotePreview key={index} isBacklinkReply={true} backlinkReply={reply} />)}
replies.map(
(reply: Comment, index: number) => reply?.parentCid === cid && reply?.cid && <ReplyQuotePreview key={index} isBacklinkReply={true} backlinkReply={reply} />,
)}
</div>
);
};
@@ -290,7 +302,7 @@ const PostMessage = ({ post }: PostProps) => {
<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('reason'))}: "${reason}"`}</span>
</>
) : (
<span className={styles.grayEditMessage}>{_.capitalize(t('this_post_was_removed'))}.</span>
@@ -299,7 +311,7 @@ const PostMessage = ({ post }: PostProps) => {
reason ? (
<>
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>{' '}
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}.</span>
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
</>
) : (
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>
@@ -416,15 +428,6 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
const linksCount = pinned ? totalLinksCount : totalLinksCount - visiblelinksCount;
const { showOmittedReplies, setShowOmittedReplies } = useShowOmittedReplies();
// scroll to reply if pathname is reply permalink (backlink)
const replyRefs = useRef<(HTMLDivElement | null)[]>([]);
useEffect(() => {
const replyIndex = replies.findIndex((reply) => location.pathname === `/p/${subplebbitAddress}/c/${reply?.cid}`);
if (replyIndex !== -1 && replyRefs.current[replyIndex]) {
replyRefs.current[replyIndex]?.scrollIntoView();
}
}, [location.pathname, replies, subplebbitAddress]);
const stateString = useStateString(post);
return (
@@ -476,7 +479,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
replies &&
showReplies &&
(showAllReplies || showOmittedReplies[cid] ? replies : replies.slice(-5)).map((reply, index) => (
<div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}>
<div key={index} className={styles.replyContainer}>
<Reply openReplyModal={openReplyModal} reply={reply} roles={roles} postReplyCount={replyCount} />
</div>
))}
@@ -180,13 +180,13 @@ const PostMenuDesktop = ({ post }: { post: Comment }) => {
className={isInCatalogView ? styles.postMenuBtnCatalog : styles.postMenuBtn}
title='Post menu'
onClick={handleMenuClick}
style={{ transform: menuBtnRotated && cid ? 'rotate(90deg)' : 'rotate(0deg)' }}
style={{ transform: menuBtnRotated && (cid || isDescription || isRules) ? 'rotate(90deg)' : 'rotate(0deg)' }}
>
</span>
</span>
{menuBtnRotated &&
cid &&
(cid || isDescription || isRules) &&
createPortal(
<FloatingFocusManager context={context} modal={false}>
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
@@ -164,7 +164,7 @@ const PostMenuMobile = ({ post }: { post: Comment }) => {
...
</span>
{isMenuOpen &&
cid &&
(cid || isDescription || isRules) &&
createPortal(
<FloatingFocusManager context={context} modal={false}>
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
+26 -24
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react';
import { useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Link, useLocation, useParams } from 'react-router-dom';
import { Comment, useAccount, useAuthorAvatar, useComment, useEditedComment } from '@plebbit/plebbit-react-hooks';
@@ -8,6 +8,9 @@ import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-util
import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils';
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
import useAnonModeStore from '../../stores/use-anon-mode-store';
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
import useAnonMode from '../../hooks/use-anon-mode';
import useAuthorAddressClick from '../../hooks/use-author-address-click';
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useHide from '../../hooks/use-hide';
@@ -31,6 +34,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
const displayName = author?.displayName?.trim();
const authorRole = roles?.[address]?.role;
const { imageUrl: avatarImageUrl } = useAuthorAvatar({ author });
const { hideAvatars } = useAvatarVisibilityStore();
const params = useParams();
const location = useLocation();
@@ -44,16 +48,19 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
const isReply = parentCid;
// pending reply by account is not yet published
// comment.author.shortAddress is undefined while the comment publishing state is pending, use account instead
// in anon mode, use the newly generated signer.address instead, which will be comment.author.address
const { anonMode } = useAnonMode();
const { currentAnonSignerAddress } = useAnonModeStore();
const account = useAccount();
const accountShortAddress = account?.author?.shortAddress;
const pendingShortAddress = anonMode ? currentAnonSignerAddress && Plebbit.getShortAddress(currentAnonSignerAddress) : account?.author?.shortAddress;
const stateString = useStateString(post);
const handleUserAddressClick = useAuthorAddressClick();
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
const userIDBackgroundColor = hashStringToColor(shortAddress || accountShortAddress);
const userIDBackgroundColor = hashStringToColor(shortAddress || pendingShortAddress);
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
return (
@@ -82,7 +89,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
</span>
{!(isDescription || isRules) && (
<>
{author?.avatar && !(deleted || removed) ? (
{author?.avatar && !(deleted || removed) && !hideAvatars ? (
<span className={styles.authorAvatar}>
<img src={avatarImageUrl} alt='' />
</span>
@@ -100,10 +107,10 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
<span
title={t('highlight_posts')}
className={styles.userAddress}
onClick={() => handleUserAddressClick(shortAddress || accountShortAddress, postCid)}
onClick={() => handleUserAddressClick(shortAddress || pendingShortAddress, postCid)}
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
>
{shortAddress || accountShortAddress}
{shortAddress || pendingShortAddress}
</span>
}
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
@@ -154,7 +161,9 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
) : (
<>
<span>c/</span>
<span className={styles.pendingCid}>{state === 'failed' || stateString === 'Failed' ? 'Failed' : 'Pending'}</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
</>
))}
</span>
@@ -167,15 +176,17 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
};
const ReplyBacklinks = ({ post }: PostProps) => {
const { cid, parentCid, replyCount } = post || {};
const { cid, parentCid } = post || {};
const replies = useReplies(post);
return (
replyCount > 0 &&
cid &&
parentCid &&
replies && (
replies.length > 0 && (
<div className={styles.mobileReplyBacklinks}>
{replies.map((reply: Comment, index: number) => reply?.parentCid === cid && <ReplyQuotePreview key={index} isBacklinkReply={true} backlinkReply={reply} />)}
{replies.map(
(reply: Comment, index: number) => reply?.parentCid === cid && reply?.cid && <ReplyQuotePreview key={index} isBacklinkReply={true} backlinkReply={reply} />,
)}
</div>
)
);
@@ -214,7 +225,7 @@ const PostMessageMobile = ({ post }: PostProps) => {
<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('reason'))}: "${reason}"`}</span>
</>
) : (
<span className={styles.grayEditMessage}>{_.capitalize(t('this_post_was_removed'))}.</span>
@@ -223,7 +234,7 @@ const PostMessageMobile = ({ post }: PostProps) => {
reason ? (
<>
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>{' '}
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}.</span>
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
</>
) : (
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>
@@ -334,15 +345,6 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
const isInPostPageView = isPostPageView(location.pathname, params);
const { hidden, unhide } = useHide({ cid });
// scroll to reply if pathname is reply permalink (backlink)
const replyRefs = useRef<(HTMLDivElement | null)[]>([]);
useEffect(() => {
const replyIndex = replies.findIndex((reply) => location.pathname === `/p/${subplebbitAddress}/c/${reply?.cid}`);
if (replyIndex !== -1 && replyRefs.current[replyIndex]) {
replyRefs.current[replyIndex]?.scrollIntoView();
}
}, [location.pathname, replies, subplebbitAddress]);
const stateString = useStateString(post);
return (
@@ -391,7 +393,7 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
replies &&
showReplies &&
(showAllReplies ? replies : replies.slice(-5)).map((reply, index) => (
<div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}>
<div key={index} className={styles.replyContainer}>
<Reply openReplyModal={openReplyModal} postReplyCount={replyCount} reply={reply} roles={roles} />
</div>
))}
+15 -8
View File
@@ -15,6 +15,7 @@ import styles from './reply-modal.module.css';
import { LinkTypePreviewer } from '../post-form';
import _ from 'lodash';
import useAnonMode from '../../hooks/use-anon-mode';
import useAnonModeStore from '../../stores/use-anon-mode-store';
interface ReplyModalProps {
closeModal: () => void;
@@ -40,6 +41,8 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
const address = comment?.author?.address;
const hasCalledAnonAddressRef = useRef(false);
const { setCurrentAnonSignerAddress } = useAnonModeStore();
const getAnonAddressForReply = useCallback(async () => {
if (anonMode && !hasCalledAnonAddressRef.current) {
hasCalledAnonAddressRef.current = true;
@@ -52,18 +55,22 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
displayName: displayName || undefined,
},
});
setCurrentAnonSignerAddress(existingSigner.address);
} else {
const newSigner = await getNewSigner();
setPublishReplyOptions({
signer: newSigner,
author: {
address: newSigner.address,
displayName: displayName || undefined,
},
});
if (newSigner) {
setPublishReplyOptions({
signer: newSigner,
author: {
address: newSigner.address,
displayName: displayName || undefined,
},
});
setCurrentAnonSignerAddress(newSigner.address);
}
}
}
}, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, anonMode, displayName]);
}, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, anonMode, displayName, setCurrentAnonSignerAddress]);
const onPublishReply = () => {
const currentContent = textRef.current?.value.slice(contentPrefix.length).trim() || '';
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import { Comment, useAccount } from '@plebbit/plebbit-react-hooks';
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
import useIsMobile from '../../hooks/use-is-mobile';
@@ -88,6 +88,19 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
};
}, [update]);
const navigate = useNavigate();
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
e.preventDefault();
if (cid && subplebbitAddress) {
navigate(`/p/${subplebbitAddress}/c/${cid}`);
setTimeout(() => {
const element = document.querySelector(`[data-cid="${cid}"]`);
element?.scrollIntoView();
}, 100);
}
};
const handleMouseOver = (cid: string | undefined) => {
if (!cid) return;
@@ -114,6 +127,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
ref={refs.setReference}
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
onClick={(e) => handleClick(e, backlinkReply?.cid, backlinkReply?.subplebbitAddress)}
>
c/{backlinkReply?.shortCid}
</Link>
@@ -138,8 +152,9 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
className={styles.quoteLink}
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
onClick={(e) => handleClick(e, quotelinkReply?.cid, quotelinkReply?.subplebbitAddress)}
>
{`c/${quotelinkReply?.shortCid}`}
{quotelinkReply?.shortCid && `c/${quotelinkReply?.shortCid}`}
{quotelinkReply?.author?.address === account?.author?.address && ' (You)'}
</Link>
<br />
@@ -174,6 +189,19 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
};
}, [update]);
const navigate = useNavigate();
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
e.preventDefault();
if (cid && subplebbitAddress) {
navigate(`/p/${subplebbitAddress}/c/${cid}`);
setTimeout(() => {
const element = document.querySelector(`[data-cid="${cid}"]`);
element?.scrollIntoView();
}, 100);
}
};
const handleMouseOver = (cid: string | undefined) => {
if (!cid) return;
@@ -200,11 +228,18 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
>
c/{backlinkReply?.shortCid}{' '}
{backlinkReply?.shortCid && `c/${backlinkReply?.shortCid}`}
</span>
<Link to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} className={styles.backlinkHash}>
#
</Link>
{backlinkReply?.shortCid && (
<Link
to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`}
className={styles.backlinkHash}
onClick={(e) => handleClick(e, backlinkReply?.cid, backlinkReply?.subplebbitAddress)}
>
{' '}
#
</Link>
)}
{hoveredCid === backlinkReply?.cid &&
outOfViewCid === backlinkReply?.cid &&
createPortal(
@@ -226,14 +261,19 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
>
c/{quotelinkReply?.shortCid}
{quotelinkReply?.shortCid && `c/${quotelinkReply?.shortCid}`}
{quotelinkReply?.author?.address === account?.author?.address && ' (You)'}
</span>
<Link className={styles.quoteLink} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}>
{' '}
#
</Link>
<br />
{quotelinkReply?.shortCid && (
<Link
className={styles.quoteLink}
to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}
onClick={(e) => handleClick(e, quotelinkReply?.cid, quotelinkReply?.subplebbitAddress)}
>
{' '}
#
</Link>
)}
{hoveredCid === quotelinkReply?.cid &&
outOfViewCid === quotelinkReply?.cid &&
createPortal(
@@ -6,15 +6,16 @@ import styles from './account-settings.module.css';
import useAnonModeStore from '../../../stores/use-anon-mode-store';
const AnonMode = () => {
const { t } = useTranslation();
const anonMode = useAnonModeStore((state) => state.anonMode);
const setAnonMode = useAnonModeStore((state) => state.setAnonMode);
return (
<div className={styles.anonMode}>
<label>
<input type='checkbox' checked={anonMode} onChange={(e) => setAnonMode(e.target.checked)} /> anon mode
<input type='checkbox' checked={anonMode} onChange={(e) => setAnonMode(e.target.checked)} /> {t('anon_mode')}
</label>
<span className={styles.settingTip}>Automatically use a different user ID in each thread</span>
<span className={styles.settingTip}>{t('anon_mode_description')}</span>
</div>
);
};
@@ -117,7 +117,7 @@ const CryptoAddressSetting = () => {
</button>
{showCryptoAddressInfo && (
<div className={styles.cryptoAddressInfo}>
steps to set a .eth user address:
steps to set a .eth address as your ID:
<br />
<ol>
<li>
@@ -130,7 +130,7 @@ const CryptoAddressSetting = () => {
<li>once you own the address, go to its page, click on "records", then "edit records"</li>
<li>add a new text record with name "plebbit-author-address" and value: {account?.signer?.address}</li>
</ol>
steps to set a .sol user address:
steps to set a .sol address as your ID:
<br />
<ol>
<li>
@@ -3,7 +3,6 @@
}
.setting {
text-transform: capitalize;
margin-left: 10px;
margin-top: 10px;
}
@@ -24,4 +23,8 @@
.interfaceSettings {
margin-bottom: 10px;
}
.setting input[type="checkbox"] {
margin-right: 2px;
}
@@ -1,8 +1,10 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import useAvatarVisibilityStore from '../../../stores/use-avatar-visibility-store';
import useTheme from '../../../hooks/use-theme';
import styles from './interface-settings.module.css';
import packageJson from '../../../../package.json';
import styles from './interface-settings.module.css';
import _ from 'lodash';
const commitRef = process.env.REACT_APP_COMMIT_REF;
const isElectron = window.isElectron === true;
@@ -107,11 +109,16 @@ const InterfaceLanguage = () => {
const InterfaceSettings = () => {
const { t } = useTranslation();
const { hideAvatars, setHideAvatars } = useAvatarVisibilityStore();
const handleHideAvatarsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setHideAvatars(e.target.checked);
};
return (
<div className={styles.interfaceSettings}>
<div className={styles.version}>
{t('version')}:{' '}
{_.capitalize(t('version'))}:{' '}
<a href={`https://github.com/plebbit/plebchan/releases/tag/v${packageJson.version}`} target='_blank' rel='noopener noreferrer'>
{packageJson.version}
</a>
@@ -122,13 +129,18 @@ const InterfaceSettings = () => {
)}
</div>
<div className={styles.setting}>
{t('update')}: <CheckForUpdates />
{_.capitalize(t('update'))}: <CheckForUpdates />
</div>
<div className={styles.setting}>
{t('style')}: <Style />
{_.capitalize(t('style'))}: <Style />
</div>
<div className={styles.setting}>
{t('interface_language')}: <InterfaceLanguage />
{_.capitalize(t('interface_language'))}: <InterfaceLanguage />
</div>
<div className={styles.setting}>
<label>
<input type='checkbox' checked={hideAvatars} onChange={handleHideAvatarsChange} /> {_.capitalize(t('hide_avatars'))}
</label>
</div>
</div>
);
@@ -230,7 +230,7 @@ const PlebbitOptions = () => {
</span>
</div>
<div className={styles.category}>
<span className={styles.categoryTitle}>node rpc:</span>
<span className={styles.categoryTitle}>node RPC:</span>
<span className={styles.categorySettings}>
<PlebbitRPCSettings plebbitRpcRef={plebbitRpcRef} />
</span>
+3 -2
View File
@@ -85,7 +85,8 @@ const TopBarDesktop = () => {
{renderSubplebbits(projectsSubs)}
{renderSubplebbits(interestsSubs)}
{renderSubplebbits(randomSubs)}
{renderSubplebbits(internationalSubs)}[
{renderSubplebbits(internationalSubs)}
{/* [
<Link
to='boards/create'
onClick={(e) => {
@@ -105,7 +106,7 @@ const TopBarDesktop = () => {
>
Vote
</Link>
]
] */}
</span>
<span className={styles.navTopRight}>
[<Link to={!location.pathname.endsWith('settings') ? location.pathname.replace(/\/$/, '') + '/settings' : location.pathname}>{t('settings')}</Link>] [
+9 -2
View File
@@ -2,12 +2,13 @@ import { useAccount } from '@plebbit/plebbit-react-hooks';
import useAnonModeStore from '../stores/use-anon-mode-store';
const useAnonMode = (postCid?: string) => {
const { anonMode, threadSigners, setThreadSigner, setAddressSigner, getAddressSigner } = useAnonModeStore((state) => ({
const { anonMode, threadSigners, setThreadSigner, setAddressSigner, getAddressSigner, setCurrentAnonSignerAddress } = useAnonModeStore((state) => ({
anonMode: state.anonMode,
threadSigners: state.threadSigners,
setThreadSigner: state.setThreadSigner,
setAddressSigner: state.setAddressSigner,
getAddressSigner: state.getAddressSigner,
setCurrentAnonSignerAddress: state.setCurrentAnonSignerAddress,
}));
const threadSigner = postCid ? threadSigners[postCid] : undefined;
@@ -25,6 +26,7 @@ const useAnonMode = (postCid?: string) => {
} else {
setAddressSigner(signer);
}
setCurrentAnonSignerAddress(signer.address);
}
return signer;
} catch (error) {
@@ -33,6 +35,7 @@ const useAnonMode = (postCid?: string) => {
} else {
try {
const signer = await account?.plebbit.createSigner({ type: 'ed25519', privateKey: threadSigner?.privateKey });
setCurrentAnonSignerAddress(signer.address);
return signer;
} catch (error) {
console.error('Failed to retrieve anonymous signer:', error);
@@ -43,7 +46,11 @@ const useAnonMode = (postCid?: string) => {
};
const getExistingSigner = (address: string) => {
return getAddressSigner(address);
const signer = getAddressSigner(address);
if (signer) {
setCurrentAnonSignerAddress(signer.address);
}
return signer;
};
return { anonMode, getNewSigner, getExistingSigner };
+17 -28
View File
@@ -1,4 +1,4 @@
import { useMemo, useCallback, useState, useEffect } from 'react';
import { useMemo } from 'react';
import { Comment, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils';
@@ -9,37 +9,26 @@ const useReplies = (comment: Comment) => {
// generate a Set of CIDs from flattened replies for quick lookup
const replyCids = useMemo(() => new Set(flattenedReplies.map((reply) => reply?.cid)), [flattenedReplies]);
const [filteredAccountComments, setFilteredAccountComments] = useState<Comment[]>([]);
const getPostCid = useCallback(
(accountComment: Comment, allComments: Comment[]): string | null => {
if (accountComment.parentCid === comment?.cid) {
return comment?.cid;
}
const parent = allComments.find((c) => c.cid === accountComment.parentCid);
if (!parent) {
return null;
}
return getPostCid(parent, allComments);
},
[comment?.cid],
);
const { accountComments } = useAccountComments();
useEffect(() => {
const filterComments = (comments: Comment[]) => {
return comments.filter((accountComment) => {
const parentCid = accountComment.parentCid;
if (parentCid === (comment?.cid || 'n/a') || replyCids.has(parentCid)) {
const filteredAccountComments = useMemo(() => {
const commentMap = new Map(accountComments.map((c) => [c.cid, c]));
return accountComments.filter((accountComment) => {
let currentCid = accountComment.parentCid;
while (currentCid && currentCid !== comment?.cid) {
if (replyCids.has(currentCid)) {
return true;
}
return getPostCid(accountComment, comments) === comment?.cid;
});
};
setFilteredAccountComments(filterComments(accountComments));
}, [accountComments, comment?.cid, replyCids, getPostCid]);
const parent = commentMap.get(currentCid);
if (!parent) {
return false;
}
currentCid = parent.parentCid;
}
return currentCid === comment?.cid;
});
}, [accountComments, comment?.cid, replyCids]);
// the account's replies have a delay before getting published, so get them locally from accountComments instead
const accountRepliesNotYetPublished = useMemo(() => {
+10 -2
View File
@@ -10,6 +10,8 @@ interface AnonModeState {
getThreadSigner: (postCid: string) => any | undefined;
setAddressSigner: (signer: any) => void;
getAddressSigner: (address: string) => any | undefined;
currentAnonSignerAddress: string | null;
setCurrentAnonSignerAddress: (address: string | null) => void;
}
const anonModeStore = localForageLru.createInstance({
@@ -39,6 +41,11 @@ const useAnonModeStore = create<AnonModeState>((set, get) => ({
anonModeStore.setItem(signer.address, signer);
},
getAddressSigner: (address: string) => get().addressSigners[address],
currentAnonSignerAddress: null,
setCurrentAnonSignerAddress: (address: string | null) => {
set({ currentAnonSignerAddress: address });
anonModeStore.setItem('currentAnonSignerAddress', address);
},
}));
const initializeAnonModeStore = async () => {
@@ -57,15 +64,16 @@ const initializeAnonModeStore = async () => {
}
});
const currentAnonSignerAddress = await anonModeStore.getItem('currentAnonSignerAddress');
useAnonModeStore.setState((state) => ({
anonMode, // Set the retrieved anonMode state
threadSigners: { ...threadSigners, ...state.threadSigners },
addressSigners: { ...addressSigners, ...state.addressSigners },
currentAnonSignerAddress: currentAnonSignerAddress || null,
}));
};
initializeAnonModeStore();
initializeAnonModeStore();
export default useAnonModeStore;
+21
View File
@@ -0,0 +1,21 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface AvatarVisibilityState {
hideAvatars: boolean;
setHideAvatars: (hide: boolean) => void;
}
const useAvatarVisibilityStore = create<AvatarVisibilityState>()(
persist(
(set) => ({
hideAvatars: false,
setHideAvatars: (hide) => set({ hideAvatars: hide }),
}),
{
name: 'avatar-visibility-storage',
},
),
);
export default useAvatarVisibilityStore;
+4 -3
View File
@@ -7,6 +7,7 @@ const BoxModal = ({ isBoardsBoxModal }: { isBoardsBoxModal: boolean }) => {
const { t } = useTranslation();
const [showFilterModal, setShowFilterModal] = useState(false);
const modalRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLSpanElement>(null);
const {
showNsfwBoardsOnly,
@@ -23,11 +24,11 @@ const BoxModal = ({ isBoardsBoxModal }: { isBoardsBoxModal: boolean }) => {
const handleClickOutside = useCallback(
(event: MouseEvent) => {
if (modalRef.current && !modalRef.current.contains(event.target as Node)) {
if (modalRef.current && !modalRef.current.contains(event.target as Node) && buttonRef.current && !buttonRef.current.contains(event.target as Node)) {
setShowFilterModal(false);
}
},
[modalRef, setShowFilterModal],
[modalRef, buttonRef, setShowFilterModal],
);
useEffect(() => {
@@ -39,7 +40,7 @@ const BoxModal = ({ isBoardsBoxModal }: { isBoardsBoxModal: boolean }) => {
return (
<>
<span ref={modalRef} onClick={() => setShowFilterModal(true)}>
<span ref={buttonRef} onClick={() => !showFilterModal && setShowFilterModal(true)}>
{isBoardsBoxModal ? t('filter') : t('options')}
</span>
{showFilterModal && (