diff --git a/public/translations/ar/default.json b/public/translations/ar/default.json index 61418c8f..d840bc07 100644 --- a/public/translations/ar/default.json +++ b/public/translations/ar/default.json @@ -314,5 +314,12 @@ "show_all_instead": "عرض المشاركات منذ {{timeFilterName}} ، <1>عرض الكل بدلاً من ذلك", "subplebbit_offline_info": "قد يكون الرد على الرسائل غير متاح حالياً وقد تفشل النشر.", "posts_last_synced_info": "آخر تزامن الرسائل {{time}}، قد يكون الرد على الرسائل غير متاح حالياً وقد تفشل النشر.", - "stored_locally": "مخزنة محليًا ({{location}})، ليست متزامنة عبر الأجهزة" + "stored_locally": "مخزنة محليًا ({{location}})، ليست متزامنة عبر الأجهزة", + "import_account_backup": "<1>استيراد نسخة احتياطية للحساب", + "export_account_backup": "<1>تصدير نسخة احتياطية للحساب", + "save_reset_changes": "<1>حفظ أو <2>إعادة تعيين التغييرات", + "delete_this_account": "<1>حذف هذا الحساب", + "create_new_account": "<1>إنشاء حساب جديد", + "wallet_number": "المحفظة #{{index}}", + "view_more": "عرض المزيد" } \ No newline at end of file diff --git a/public/translations/bn/default.json b/public/translations/bn/default.json index fb367b21..8235c1e0 100644 --- a/public/translations/bn/default.json +++ b/public/translations/bn/default.json @@ -314,5 +314,12 @@ "show_all_instead": "আপনি {{timeFilterName}} থেকে পোস্টগুলি দেখছেন, <1>তার পরিবর্তে সব দেখান", "subplebbit_offline_info": "সাবপ্লেবিট অফলাইন হতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে।", "posts_last_synced_info": "পোস্টগুলি সর্বশেষ সিঙ্ক হয়েছে {{time}}, সাবপ্লেবিট অফলাইন হতে পারে এবং প্রকাশনা ব্যর্থ হতে পারে।", - "stored_locally": "স্থানীয়ভাবে সংরক্ষিত ({{location}}), ডিভাইসের মধ্যে সিঙ্ক করা হয়নি" + "stored_locally": "স্থানীয়ভাবে সংরক্ষিত ({{location}}), ডিভাইসের মধ্যে সিঙ্ক করা হয়নি", + "import_account_backup": "<1>আমদানি অ্যাকাউন্ট ব্যাকআপ", + "export_account_backup": "<1>রপ্তানি অ্যাকাউন্ট ব্যাকআপ", + "save_reset_changes": "<1>সংরক্ষণ করুন অথবা <2>রিসেট করুন পরিবর্তনগুলি", + "delete_this_account": "<1>মুছুন এই অ্যাকাউন্ট", + "create_new_account": "<1>নতুন তৈরি করুন অ্যাকাউন্ট", + "wallet_number": "ওয়ালেট #{{index}}", + "view_more": "আরও দেখুন" } \ No newline at end of file diff --git a/public/translations/cs/default.json b/public/translations/cs/default.json index 77922c57..bdea70f0 100644 --- a/public/translations/cs/default.json +++ b/public/translations/cs/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Zobrazujeme příspěvky od {{timeFilterName}}, <1>zobrazit vše místo toho", "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.", - "stored_locally": "Uloženo lokálně ({{location}}), není synchronizováno mezi zařízeními" + "stored_locally": "Uloženo lokálně ({{location}}), není synchronizováno mezi zařízeními", + "import_account_backup": "<1>importovat zálohu účtu", + "export_account_backup": "<1>exportovat zálohu účtu", + "save_reset_changes": "<1>uložit nebo <2>resetovat změny", + "delete_this_account": "<1>smazat tento účet", + "create_new_account": "<1>vytvořit nový účet", + "wallet_number": "peněženka #{{index}}", + "view_more": "zobrazit více" } \ No newline at end of file diff --git a/public/translations/da/default.json b/public/translations/da/default.json index bf3bd4e2..0de038a9 100644 --- a/public/translations/da/default.json +++ b/public/translations/da/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Viser indlæg siden {{timeFilterName}}, <1>vis alle i stedet", "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.", - "stored_locally": "Lager lokalt ({{location}}), ikke synkroniseret på tværs af enheder" + "stored_locally": "Lager lokalt ({{location}}), ikke synkroniseret på tværs af enheder", + "import_account_backup": "<1>importere kontosikkerhedskopi", + "export_account_backup": "<1>eksportere kontosikkerhedskopi", + "save_reset_changes": "<1>gem eller <2>nulstil ændringer", + "delete_this_account": "<1>slet denne konto", + "create_new_account": "<1>oprette en ny konto", + "wallet_number": "tegneboks #{{index}}", + "view_more": "se mere" } \ No newline at end of file diff --git a/public/translations/de/default.json b/public/translations/de/default.json index 941d7f7e..19fe4825 100644 --- a/public/translations/de/default.json +++ b/public/translations/de/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Zeigt Beiträge seit {{timeFilterName}}, <1>stattdessen alles anzeigen", "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.", - "stored_locally": "Lokal gespeichert ({{location}}), nicht geräteübergreifend synchronisiert" + "stored_locally": "Lokal gespeichert ({{location}}), nicht geräteübergreifend synchronisiert", + "import_account_backup": "<1>importieren Sie die Kontosicherung", + "export_account_backup": "<1>exportieren Sie die Kontosicherung", + "save_reset_changes": "<1>speichern oder <2>zurücksetzen Änderungen", + "delete_this_account": "<1>löschen Sie dieses Konto", + "create_new_account": "<1>erstelle ein neues Konto", + "wallet_number": "Wallet #{{index}}", + "view_more": "mehr anzeigen" } \ No newline at end of file diff --git a/public/translations/el/default.json b/public/translations/el/default.json index 1a4fcc88..711dd820 100644 --- a/public/translations/el/default.json +++ b/public/translations/el/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Εμφανίζονται αναρτήσεις από {{timeFilterName}}, <1>εμφάνιση όλων αντί αυτού", "subplebbit_offline_info": "Το subplebbit ενδέχεται να είναι εκτός σύνδεσης και η δημοσίευση μπορεί να αποτύχει.", "posts_last_synced_info": "Τελευταία συγχρονισμένες αναρτήσεις {{time}}, το subplebbit ενδέχεται να είναι εκτός σύνδεσης και η δημοσίευση μπορεί να αποτύχει.", - "stored_locally": "Αποθηκευμένο τοπικά ({{location}}), δεν συγχρονίζεται σε όλες τις συσκευές" + "stored_locally": "Αποθηκευμένο τοπικά ({{location}}), δεν συγχρονίζεται σε όλες τις συσκευές", + "import_account_backup": "<1>εισαγωγή αντιγράφου ασφαλείας λογαριασμού", + "export_account_backup": "<1>εξαγωγή αντιγράφου ασφαλείας λογαριασμού", + "save_reset_changes": "<1>αποθήκευση ή <2>επανεκκίνηση αλλαγών", + "delete_this_account": "<1>διαγραφή αυτού του λογαριασμού", + "create_new_account": "<1>δημιουργία νέου λογαριασμού", + "wallet_number": "πορτοφόλι #{{index}}", + "view_more": "δείτε περισσότερα" } \ No newline at end of file diff --git a/public/translations/en/default.json b/public/translations/en/default.json index 31808564..bac05670 100644 --- a/public/translations/en/default.json +++ b/public/translations/en/default.json @@ -62,7 +62,7 @@ "challenge_for_reply": "for reply to u/{{parentAddress}}: \"{{publicationContent}}\"", "challenge_counter": "{{index}} of {{total}}", "cancel": "Cancel", - "previous": "Previous", + "previous": "prev", "next": "Next", "loading": "Loading", "pending": "Pending", @@ -314,5 +314,12 @@ "show_all_instead": "Showing posts since {{timeFilterName}}, <1>show all instead", "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.", - "stored_locally": "Stored locally ({{location}}), not synced across devices" + "stored_locally": "Stored locally ({{location}}), not synced across devices", + "import_account_backup": "<1>import account backup", + "export_account_backup": "<1>export account backup", + "save_reset_changes": "<1>save or <2>reset changes", + "delete_this_account": "<1>delete this account", + "create_new_account": "<1>create a new account", + "wallet_number": "wallet #{{index}}", + "view_more": "view more" } \ No newline at end of file diff --git a/public/translations/es/default.json b/public/translations/es/default.json index 1a945e51..6c4b4a5c 100644 --- a/public/translations/es/default.json +++ b/public/translations/es/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Mostrando publicaciones desde {{timeFilterName}}, <1>mostrar todo en su lugar", "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.", - "stored_locally": "Almacenado localmente ({{location}}), no sincronizado entre dispositivos" + "stored_locally": "Almacenado localmente ({{location}}), no sincronizado entre dispositivos", + "import_account_backup": "<1>importar copia de seguridad de la cuenta", + "export_account_backup": "<1>exportar copia de seguridad de la cuenta", + "save_reset_changes": "<1>guardar o <2>restablecer cambios", + "delete_this_account": "<1>eliminar esta cuenta", + "create_new_account": "<1>crear una nueva cuenta", + "wallet_number": "billetera #{{index}}", + "view_more": "ver más" } \ No newline at end of file diff --git a/public/translations/fa/default.json b/public/translations/fa/default.json index d3595105..6364a5cd 100644 --- a/public/translations/fa/default.json +++ b/public/translations/fa/default.json @@ -314,5 +314,12 @@ "show_all_instead": "نمایش پست‌ها از {{timeFilterName}}، <1>به‌جای آن همه را نشان بده", "subplebbit_offline_info": "زیرپلبیت ممکن است آفلاین باشد و انتشار ممکن است شکست خورده باشد.", "posts_last_synced_info": "آخرین پست‌ها همگام‌سازی شده‌اند {{time}}، زیرپلبیت ممکن است آفلاین باشد و انتشار ممکن است شکست خورده باشد.", - "stored_locally": "محلی ذخیره شده ({{location}})، با دستگاه‌ها همگام‌سازی نشده است" + "stored_locally": "محلی ذخیره شده ({{location}})، با دستگاه‌ها همگام‌سازی نشده است", + "import_account_backup": "<1>وارد کردن پشتیبان حساب", + "export_account_backup": "<1>خروجی پشتیبان حساب", + "save_reset_changes": "<1>ذخیره یا <2>بازنشانی تغییرات", + "delete_this_account": "<1>حذف این حساب", + "create_new_account": "<1>ایجاد یک حساب جدید", + "wallet_number": "کیف پول #{{index}}", + "view_more": "مشاهده بیشتر" } \ No newline at end of file diff --git a/public/translations/fi/default.json b/public/translations/fi/default.json index 4d74f727..84aace9f 100644 --- a/public/translations/fi/default.json +++ b/public/translations/fi/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Näytetään viestejä ajasta {{timeFilterName}}, <1>näytä kaikki sen sijaan", "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.", - "stored_locally": "Tallennettu paikallisesti ({{location}}), ei synkronoitu laitteiden välillä" + "stored_locally": "Tallennettu paikallisesti ({{location}}), ei synkronoitu laitteiden välillä", + "import_account_backup": "<1>tuoda tilin varmuuskopio", + "export_account_backup": "<1>viedä tilin varmuuskopio", + "save_reset_changes": "<1>tallenna tai <2>nollaa muutokset", + "delete_this_account": "<1>poista tämä tili", + "create_new_account": "<1>luo uusi tili", + "wallet_number": "lompakko #{{index}}", + "view_more": "näytä lisää" } \ No newline at end of file diff --git a/public/translations/fil/default.json b/public/translations/fil/default.json index a0b97df2..e7e7e248 100644 --- a/public/translations/fil/default.json +++ b/public/translations/fil/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Ipinapakita ang mga post mula {{timeFilterName}}, <1>ipakita ang lahat sa halip", "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.", - "stored_locally": "Nakaimbak nang lokal ({{location}}), hindi naka-sync sa iba pang device" + "stored_locally": "Nakaimbak nang lokal ({{location}}), hindi naka-sync sa iba pang device", + "import_account_backup": "<1>i-import ang backup ng account", + "export_account_backup": "<1>ilabas ang backup ng account", + "save_reset_changes": "<1>i-save o <2>i-reset ang mga pagbabago", + "delete_this_account": "<1>tanggalin ang account na ito", + "create_new_account": "<1>lumikha ng bagong account", + "wallet_number": "wallet #{{index}}", + "view_more": "tingnan pa" } \ No newline at end of file diff --git a/public/translations/fr/default.json b/public/translations/fr/default.json index c245f831..6917c604 100644 --- a/public/translations/fr/default.json +++ b/public/translations/fr/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Affichage des publications depuis {{timeFilterName}}, <1>afficher tout à la place", "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.", - "stored_locally": "Stocké localement ({{location}}), non synchronisé entre les appareils" + "stored_locally": "Stocké localement ({{location}}), non synchronisé entre les appareils", + "import_account_backup": "<1>importer la sauvegarde du compte", + "export_account_backup": "<1>exporter la sauvegarde du compte", + "save_reset_changes": "<1>enregistrer ou <2>réinitialiser les modifications", + "delete_this_account": "<1>supprimer ce compte", + "create_new_account": "<1>créer un nouveau compte", + "wallet_number": "portefeuille #{{index}}", + "view_more": "voir plus" } \ No newline at end of file diff --git a/public/translations/he/default.json b/public/translations/he/default.json index 5c8b88f3..86573081 100644 --- a/public/translations/he/default.json +++ b/public/translations/he/default.json @@ -314,5 +314,12 @@ "show_all_instead": "מראה פוסטים מאז {{timeFilterName}}, <1>הצג הכל במקום זאת", "subplebbit_offline_info": "הסאבפלביט עשוי להיות לא מקוון והפרסום עשוי להכשל.", "posts_last_synced_info": "הפוסטים סונכרנו לאחרונה {{time}}, הסאבפלביט עשוי להיות לא מקוון והפרסום עשוי להכשל.", - "stored_locally": "מאוחסן מקומית ({{location}}), לא מסונכרן בין מכשירים" + "stored_locally": "מאוחסן מקומית ({{location}}), לא מסונכרן בין מכשירים", + "import_account_backup": "<1>יבוא גיבוי חשבון", + "export_account_backup": "<1>ייצוא גיבוי חשבון", + "save_reset_changes": "<1>שמור או <2>אפס שינויים", + "delete_this_account": "<1>מחק את החשבון הזה", + "create_new_account": "<1>צור חשבון חדש", + "wallet_number": "ארנק #{{index}}", + "view_more": "ראה עוד" } \ No newline at end of file diff --git a/public/translations/hi/default.json b/public/translations/hi/default.json index 56f10461..ac822629 100644 --- a/public/translations/hi/default.json +++ b/public/translations/hi/default.json @@ -314,5 +314,12 @@ "show_all_instead": "आप {{timeFilterName}} से पोस्ट देख रहे हैं, <1>इसके बजाय सभी दिखाएं", "subplebbit_offline_info": "सबप्लेबिट ऑफलाइन हो सकता है और प्रकाशन विफल हो सकता है।", "posts_last_synced_info": "आखिरी बार सिंक की गई पोस्ट {{time}}, सबप्लेबिट ऑफलाइन हो सकता है और प्रकाशन विफल हो सकता है।", - "stored_locally": "स्थानीय रूप से संग्रहीत ({{location}}), उपकरणों के बीच समन्वयित नहीं" + "stored_locally": "स्थानीय रूप से संग्रहीत ({{location}}), उपकरणों के बीच समन्वयित नहीं", + "import_account_backup": "<1>आयात खाता बैकअप", + "export_account_backup": "<1>निर्यात खाता बैकअप", + "save_reset_changes": "<1>सहेजें या <2>रीसेट परिवर्तन", + "delete_this_account": "<1>हटाएँ यह खाता", + "create_new_account": "<1>नया बनाएं खाता", + "wallet_number": "वॉलेट #{{index}}", + "view_more": "और देखें" } \ No newline at end of file diff --git a/public/translations/hu/default.json b/public/translations/hu/default.json index f3b30f67..de50b5f5 100644 --- a/public/translations/hu/default.json +++ b/public/translations/hu/default.json @@ -314,5 +314,12 @@ "show_all_instead": "A {{timeFilterName}} óta látható bejegyzések, <1>helyette mindent mutass", "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.", - "stored_locally": "Helyben tárolva ({{location}}), nem szinkronizálva eszközök között" + "stored_locally": "Helyben tárolva ({{location}}), nem szinkronizálva eszközök között", + "import_account_backup": "<1>importálás fiók biztonsági másolat", + "export_account_backup": "<1>exportálás fiók biztonsági másolat", + "save_reset_changes": "<1>mentés vagy <2>visszaállítás a változtatásokat", + "delete_this_account": "<1>törölni ezt a fiókot", + "create_new_account": "<1>hozzon létre egy új fiókot", + "wallet_number": "tárca #{{index}}", + "view_more": "több megtekintése" } \ No newline at end of file diff --git a/public/translations/id/default.json b/public/translations/id/default.json index 6069829c..367efe34 100644 --- a/public/translations/id/default.json +++ b/public/translations/id/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Menampilkan pos sejak {{timeFilterName}}, <1>tampilkan semua sebagai gantinya", "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.", - "stored_locally": "Disimpan secara lokal ({{location}}), tidak disinkronkan antar perangkat" + "stored_locally": "Disimpan secara lokal ({{location}}), tidak disinkronkan antar perangkat", + "import_account_backup": "<1>impor cadangan akun", + "export_account_backup": "<1>ekspor cadangan akun", + "save_reset_changes": "<1>simpan atau <2>reset perubahan", + "delete_this_account": "<1>hapus akun ini", + "create_new_account": "<1>buat akun baru", + "wallet_number": "dompet #{{index}}", + "view_more": "lihat lebih banyak" } \ No newline at end of file diff --git a/public/translations/it/default.json b/public/translations/it/default.json index 7a04bd27..843d608b 100644 --- a/public/translations/it/default.json +++ b/public/translations/it/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Stai visualizzando post da {{timeFilterName}}, <1>visualizza tutto invece", "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.", - "stored_locally": "Memorizzato localmente ({{location}}), non sincronizzato tra i dispositivi" + "stored_locally": "Memorizzato localmente ({{location}}), non sincronizzato tra i dispositivi", + "import_account_backup": "<1>importa backup dell'account", + "export_account_backup": "<1>esporta backup dell'account", + "save_reset_changes": "<1>salva o <2>ripristina modifiche", + "delete_this_account": "<1>elimina questo account", + "create_new_account": "<1>crea un nuovo account", + "wallet_number": "wallet #{{index}}", + "view_more": "altri" } \ No newline at end of file diff --git a/public/translations/ja/default.json b/public/translations/ja/default.json index 0c89e637..18c11f0d 100644 --- a/public/translations/ja/default.json +++ b/public/translations/ja/default.json @@ -314,5 +314,12 @@ "show_all_instead": "{{timeFilterName}} からの投稿を表示しています。<1>その代わりにすべて表示", "subplebbit_offline_info": "サブプレビットがオフラインになっている可能性があり、公開が失敗することがあります。", "posts_last_synced_info": "最後に同期された投稿 {{time}}, サブプレビットがオフラインになっている可能性があり、公開が失敗することがあります。", - "stored_locally": "ローカルに保存されています ({{location}})、デバイス間で同期されていません" + "stored_locally": "ローカルに保存されています ({{location}})、デバイス間で同期されていません", + "import_account_backup": "<1>インポート アカウントバックアップ", + "export_account_backup": "<1>エクスポート アカウントバックアップ", + "save_reset_changes": "<1>保存または<2>リセット変更", + "delete_this_account": "<1>削除このアカウント", + "create_new_account": "<1>新しいアカウントを作成", + "wallet_number": "ウォレット #{{index}}", + "view_more": "もっと見る" } \ No newline at end of file diff --git a/public/translations/ko/default.json b/public/translations/ko/default.json index d2a81bec..207dae4e 100644 --- a/public/translations/ko/default.json +++ b/public/translations/ko/default.json @@ -314,5 +314,12 @@ "show_all_instead": "{{timeFilterName}} 이후의 게시물이 표시됩니다. <1>대신 모두 표시", "subplebbit_offline_info": "서브플레빗이 오프라인 일 수 있으며 게시가 실패할 수 있습니다.", "posts_last_synced_info": "최근 동기화된 게시물 {{time}}, 서브플레빗이 오프라인 일 수 있으며 게시가 실패할 수 있습니다.", - "stored_locally": "로컬에 저장됨 ({{location}}), 장치 간에 동기화되지 않음" + "stored_locally": "로컬에 저장됨 ({{location}}), 장치 간에 동기화되지 않음", + "import_account_backup": "<1>가져오기 계정 백업", + "export_account_backup": "<1>내보내기 계정 백업", + "save_reset_changes": "<1>저장하거나 <2>재설정 변경 사항", + "delete_this_account": "<1>삭제 이 계정", + "create_new_account": "<1>새로 만들기 계정", + "wallet_number": "지갑 #{{index}}", + "view_more": "더보기" } \ No newline at end of file diff --git a/public/translations/mr/default.json b/public/translations/mr/default.json index a898b261..b9e55a57 100644 --- a/public/translations/mr/default.json +++ b/public/translations/mr/default.json @@ -314,5 +314,12 @@ "show_all_instead": "{{timeFilterName}} पासून पोस्ट दर्शवित आहेत, <1>त्याऐवजी सर्व दाखवा", "subplebbit_offline_info": "सबप्लेबिट मोबाइल असून प्रकाशन अयशस्वी होऊ शकतो.", "posts_last_synced_info": "शेवटच्या बारीस सिन्क केलेले पोस्ट {{time}}, सबप्लेबिट मोबाइल असून प्रकाशन अयशस्वी होऊ शकतो.", - "stored_locally": "स्थानिकपणे संग्रहित ({{location}}), उपकरणांमध्ये समन्वयित केलेले नाही" + "stored_locally": "स्थानिकपणे संग्रहित ({{location}}), उपकरणांमध्ये समन्वयित केलेले नाही", + "import_account_backup": "<1>आयात खातीचा बॅकअप", + "export_account_backup": "<1>निर्यात खातीचा बॅकअप", + "save_reset_changes": "<1>जतन करा किंवा <2>रीसेट करा बदल", + "delete_this_account": "<1>हटवा हा खाता", + "create_new_account": "<1>नवीन तयार करा खाता", + "wallet_number": "वॉलेट #{{index}}", + "view_more": "अधिक पाहा" } \ No newline at end of file diff --git a/public/translations/nl/default.json b/public/translations/nl/default.json index 33ddf8f7..f04370fe 100644 --- a/public/translations/nl/default.json +++ b/public/translations/nl/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Berichten sinds {{timeFilterName}}, <1>toon in plaats daarvan alles", "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.", - "stored_locally": "Lokaal opgeslagen ({{location}}), niet gesynchroniseerd tussen apparaten" + "stored_locally": "Lokaal opgeslagen ({{location}}), niet gesynchroniseerd tussen apparaten", + "import_account_backup": "<1>importeer accountback-up", + "export_account_backup": "<1>exporteer accountback-up", + "save_reset_changes": "<1>opslaan of <2>resetten wijzigingen", + "delete_this_account": "<1>verwijder dit account", + "create_new_account": "<1>maak een nieuw account aan", + "wallet_number": "portemonnee #{{index}}", + "view_more": "meer bekijken" } \ No newline at end of file diff --git a/public/translations/no/default.json b/public/translations/no/default.json index 8beb0ed8..69db57a6 100644 --- a/public/translations/no/default.json +++ b/public/translations/no/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Viser innlegg siden {{timeFilterName}}, <1>vis alt i stedet", "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.", - "stored_locally": "Lagring lokalt ({{location}}), ikke synkronisert på tvers av enheter" + "stored_locally": "Lagring lokalt ({{location}}), ikke synkronisert på tvers av enheter", + "import_account_backup": "<1>importere konto sikkerhetskopi", + "export_account_backup": "<1>eksportere konto sikkerhetskopi", + "save_reset_changes": "<1>lagre eller <2>nullstille endringer", + "delete_this_account": "<1>slett denne kontoen", + "create_new_account": "<1>opprett en ny konto", + "wallet_number": "lommebok #{{index}}", + "view_more": "vis mer" } \ No newline at end of file diff --git a/public/translations/pl/default.json b/public/translations/pl/default.json index 86933fd4..9aa2b3bf 100644 --- a/public/translations/pl/default.json +++ b/public/translations/pl/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Pokazuje posty od {{timeFilterName}}, <1>pokaż wszystko zamiast tego", "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ść.", - "stored_locally": "Przechowywane lokalnie ({{location}}), nie synchronizowane między urządzeniami" + "stored_locally": "Przechowywane lokalnie ({{location}}), nie synchronizowane między urządzeniami", + "import_account_backup": "<1>importuj kopię zapasową konta", + "export_account_backup": "<1>eksportuj kopię zapasową konta", + "save_reset_changes": "<1>zapisz lub <2>zresetuj zmiany", + "delete_this_account": "<1>usuń to konto", + "create_new_account": "<1>stwórz nowe konto", + "wallet_number": "portfel #{{index}}", + "view_more": "zobacz więcej" } \ No newline at end of file diff --git a/public/translations/pt/default.json b/public/translations/pt/default.json index e36c6ec5..97ece8ec 100644 --- a/public/translations/pt/default.json +++ b/public/translations/pt/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Exibindo postagens desde {{timeFilterName}}, <1>mostrar tudo em vez disso", "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.", - "stored_locally": "Armazenado localmente ({{location}}), não sincronizado entre dispositivos" + "stored_locally": "Armazenado localmente ({{location}}), não sincronizado entre dispositivos", + "import_account_backup": "<1>importar backup da conta", + "export_account_backup": "<1>exportar backup da conta", + "save_reset_changes": "<1>salvar ou <2>resetar alterações", + "delete_this_account": "<1>excluir esta conta", + "create_new_account": "<1>criar uma nova conta", + "wallet_number": "carteira #{{index}}", + "view_more": "ver mais" } \ No newline at end of file diff --git a/public/translations/ro/default.json b/public/translations/ro/default.json index 703dbb4e..43a961cb 100644 --- a/public/translations/ro/default.json +++ b/public/translations/ro/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Afișând postări din {{timeFilterName}}, <1>afișați totul în schimb", "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.", - "stored_locally": "Stocat local ({{location}}), nu este sincronizat între dispozitive" + "stored_locally": "Stocat local ({{location}}), nu este sincronizat între dispozitive", + "import_account_backup": "<1>importați backup-ul contului", + "export_account_backup": "<1>exportați backup-ul contului", + "save_reset_changes": "<1>salvează sau <2>resetează modificările", + "delete_this_account": "<1>șterge acest cont", + "create_new_account": "<1>creați un cont nou", + "wallet_number": "portofel #{{index}}", + "view_more": "vezi mai mult" } \ No newline at end of file diff --git a/public/translations/ru/default.json b/public/translations/ru/default.json index 400bea2e..d386f992 100644 --- a/public/translations/ru/default.json +++ b/public/translations/ru/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Показаны записи с {{timeFilterName}}, <1>показать все вместо этого", "subplebbit_offline_info": "Сабплеббит может быть офлайн, и публикация может не удалиться.", "posts_last_synced_info": "Последние синхронизированные сообщения {{time}}, сабплеббит может быть офлайн, и публикация может не удалиться.", - "stored_locally": "Сохранено локально ({{location}}), не синхронизировано между устройствами" + "stored_locally": "Сохранено локально ({{location}}), не синхронизировано между устройствами", + "import_account_backup": "<1>импортировать резервную копию аккаунта", + "export_account_backup": "<1>экспортировать резервную копию аккаунта", + "save_reset_changes": "<1>сохранить или <2>сбросить изменения", + "delete_this_account": "<1>удалить эту учетную запись", + "create_new_account": "<1>создать новую учетную запись", + "wallet_number": "кошелек #{{index}}", + "view_more": "смотреть больше" } \ No newline at end of file diff --git a/public/translations/sq/default.json b/public/translations/sq/default.json index 45e2471e..08829d1f 100644 --- a/public/translations/sq/default.json +++ b/public/translations/sq/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Duke treguar postimet që nga {{timeFilterName}}, <1>tregoni gjithçka në vend", "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ë.", - "stored_locally": "Ruajtur lokalmente ({{location}}), nuk është sinkronizuar ndërmjet pajisjeve" + "stored_locally": "Ruajtur lokalmente ({{location}}), nuk është sinkronizuar ndërmjet pajisjeve", + "import_account_backup": "<1>importoni kopjen e llogarisë", + "export_account_backup": "<1>eksportoni kopjen e llogarisë", + "save_reset_changes": "<1>ruaj ose <2>rivendos ndryshimet", + "delete_this_account": "<1>fshi këtë llogari", + "create_new_account": "<1>krijo një llogari të re", + "wallet_number": "portofol #{{index}}", + "view_more": "shiko më shumë" } \ No newline at end of file diff --git a/public/translations/sv/default.json b/public/translations/sv/default.json index 1f929053..539acb6f 100644 --- a/public/translations/sv/default.json +++ b/public/translations/sv/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Visar inlägg sedan {{timeFilterName}}, <1>visa allt istället", "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.", - "stored_locally": "Lagrad lokalt ({{location}}), inte synkroniserad mellan enheter" + "stored_locally": "Lagrad lokalt ({{location}}), inte synkroniserad mellan enheter", + "import_account_backup": "<1>importera kontots säkerhetskopiering", + "export_account_backup": "<1>exportera kontots säkerhetskopiering", + "save_reset_changes": "<1>spara eller <2>återställ ändringar", + "delete_this_account": "<1>ta bort det här kontot", + "create_new_account": "<1>skapa ett nytt konto", + "wallet_number": "plånbok #{{index}}", + "view_more": "visa mer" } \ No newline at end of file diff --git a/public/translations/te/default.json b/public/translations/te/default.json index 2187ec89..99cbd356 100644 --- a/public/translations/te/default.json +++ b/public/translations/te/default.json @@ -314,5 +314,12 @@ "show_all_instead": "{{timeFilterName}} నుండి పోస్టులు చూపిస్తున్నాయి, <1>అదకు బదులు అన్నీ చూపించు", "subplebbit_offline_info": "సబ్ప్లెబిట్ ఆఫ్‌లైన్ ఉండవచ్చు మరియు ప్రచురణ విఫలమైనా ఉంటుంది.", "posts_last_synced_info": "ఇటీవలే సింక్ చేసిన పోస్ట్లు {{time}}, సబ్‌ప్లెబిట్ ఆఫ్‌లైన్ ఉండవచ్చు, మరియు ప్రకటన విఫలమవుతుంది.", - "stored_locally": "స్థానికంగా నిల్వ ({{location}}), పరికరాల మధ్య సమన్వయించడం లేదు" + "stored_locally": "స్థానికంగా నిల్వ ({{location}}), పరికరాల మధ్య సమన్వయించడం లేదు", + "import_account_backup": "<1>కోరి ఖాతా బాకప్", + "export_account_backup": "<1>ఎగుమతి ఖాతా బాకప్", + "save_reset_changes": "<1>సేవ్ లేదా <2>రీసెట్ మార్పులు", + "delete_this_account": "<1>తొలగించు ఈ ఖాతాను", + "create_new_account": "<1>తరువాత కొత్త ఖాతా", + "wallet_number": "వాలెట్ #{{index}}", + "view_more": "మరింత చూడండి" } \ No newline at end of file diff --git a/public/translations/th/default.json b/public/translations/th/default.json index baf051b1..3582000d 100644 --- a/public/translations/th/default.json +++ b/public/translations/th/default.json @@ -314,5 +314,12 @@ "show_all_instead": "แสดงโพสต์ตั้งแต่ {{timeFilterName}} <1>แสดงทั้งหมดแทน", "subplebbit_offline_info": "เซ็บเพล็บบิทอาจออฟไลน์และการเผยแพร่อาจล้มเหลว", "posts_last_synced_info": "โพสต์ล่าสุดที่ซิงค์ {{time}}, ซับเพลบบิทอาจออฟไลน์และการเผยแพร่อาจล้มเหลว", - "stored_locally": "จัดเก็บในเครื่อง ({{location}}) ไม่ได้ซิงค์ข้ามอุปกรณ์" + "stored_locally": "จัดเก็บในเครื่อง ({{location}}) ไม่ได้ซิงค์ข้ามอุปกรณ์", + "import_account_backup": "<1>นำเข้า สำรองข้อมูลบัญชี", + "export_account_backup": "<1>ส่งออก สำรองข้อมูลบัญชี", + "save_reset_changes": "<1>บันทึก หรือ <2>รีเซ็ต การเปลี่ยนแปลง", + "delete_this_account": "<1>ลบ บัญชีนี้", + "create_new_account": "<1>สร้าง บัญชีใหม่", + "wallet_number": "กระเป๋าเงิน #{{index}}", + "view_more": "ดูเพิ่มเติม" } \ No newline at end of file diff --git a/public/translations/tr/default.json b/public/translations/tr/default.json index 1585fd7d..f5892871 100644 --- a/public/translations/tr/default.json +++ b/public/translations/tr/default.json @@ -314,5 +314,12 @@ "show_all_instead": "{{timeFilterName}} tarihinden itibaren gönderiler gösteriliyor, <1>bunun yerine hepsini göster", "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.", - "stored_locally": "Yerel olarak saklanıyor ({{location}}), cihazlar arasında senkronize edilmedi" + "stored_locally": "Yerel olarak saklanıyor ({{location}}), cihazlar arasında senkronize edilmedi", + "import_account_backup": "<1>içeri aktarma hesap yedeği", + "export_account_backup": "<1>dışa aktarma hesap yedeği", + "save_reset_changes": "<1>kaydet veya <2>sıfırla değişiklikleri", + "delete_this_account": "<1>sil bu hesabı", + "create_new_account": "<1>oluştur yeni bir hesap", + "wallet_number": "cüzdan #{{index}}", + "view_more": "daha fazla görüntüle" } \ No newline at end of file diff --git a/public/translations/uk/default.json b/public/translations/uk/default.json index e011ec21..24e2082a 100644 --- a/public/translations/uk/default.json +++ b/public/translations/uk/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Показані пости з {{timeFilterName}}, <1>показати все замість цього", "subplebbit_offline_info": "Сабплебіт може бути офлайн, а публікація може не вдастися.", "posts_last_synced_info": "Останні синхронізовані повідомлення {{time}}, сабплебіт може бути офлайн, а публікація може не вдастися.", - "stored_locally": "Збережено локально ({{location}}), не синхронізується між пристроями" + "stored_locally": "Збережено локально ({{location}}), не синхронізується між пристроями", + "import_account_backup": "<1>імпортувати резервну копію облікового запису", + "export_account_backup": "<1>експортувати резервну копію облікового запису", + "save_reset_changes": "<1>зберегти або <2>скинути зміни", + "delete_this_account": "<1>видалити цей обліковий запис", + "create_new_account": "<1>створити новий обліковий запис", + "wallet_number": "гаманець #{{index}}", + "view_more": "переглянути більше" } \ No newline at end of file diff --git a/public/translations/ur/default.json b/public/translations/ur/default.json index 8e5490c1..de842f44 100644 --- a/public/translations/ur/default.json +++ b/public/translations/ur/default.json @@ -314,5 +314,12 @@ "show_all_instead": "{{timeFilterName}} سے پوسٹ دکھا رہا ہے، <1>اس کے بجائے سب کچھ دکھائیں", "subplebbit_offline_info": "سب پلیبٹ آف لائن ہوسکتا ہے اور شائع ہونے میں ناکام ہوسکتا ہے۔", "posts_last_synced_info": "آخری بار پوسٹ سنک کی گئی {{time}}, سب پلیبٹ آف لائن ہوسکتا ہے اور شائع ہونے میں ناکام ہوسکتا ہے۔", - "stored_locally": "مقامی طور پر محفوظ ({{location}})، آلات کے درمیان ہم وقت سازی نہیں کی گئی" + "stored_locally": "مقامی طور پر محفوظ ({{location}})، آلات کے درمیان ہم وقت سازی نہیں کی گئی", + "import_account_backup": "<1>درآمد اکاؤنٹ کا بیک اپ", + "export_account_backup": "<1>برآمد اکاؤنٹ کا بیک اپ", + "save_reset_changes": "<1>محفوظ کریں یا <2>ری سیٹ کریں تبدیلیاں", + "delete_this_account": "<1>حذف کریں یہ اکاؤنٹ", + "create_new_account": "<1>نیا بنائیں اکاؤنٹ", + "wallet_number": "والٹ #{{index}}", + "view_more": "مزید دیکھیں" } \ No newline at end of file diff --git a/public/translations/vi/default.json b/public/translations/vi/default.json index 1a0db6da..a77ef737 100644 --- a/public/translations/vi/default.json +++ b/public/translations/vi/default.json @@ -314,5 +314,12 @@ "show_all_instead": "Đang hiển thị bài viết từ {{timeFilterName}}, <1>hiển thị tất cả thay vào đó", "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.", - "stored_locally": "Lưu trữ cục bộ ({{location}}), không được đồng bộ qua các thiết bị" + "stored_locally": "Lưu trữ cục bộ ({{location}}), không được đồng bộ qua các thiết bị", + "import_account_backup": "<1>nhập sao lưu tài khoản", + "export_account_backup": "<1>xuất sao lưu tài khoản", + "save_reset_changes": "<1>lưu hoặc <2>đặt lại thay đổi", + "delete_this_account": "<1>xóa tài khoản này", + "create_new_account": "<1>tạo tài khoản mới", + "wallet_number": "ví #{{index}}", + "view_more": "xem thêm" } \ No newline at end of file diff --git a/public/translations/zh/default.json b/public/translations/zh/default.json index 4ba74ccb..d5ba2db4 100644 --- a/public/translations/zh/default.json +++ b/public/translations/zh/default.json @@ -314,5 +314,12 @@ "show_all_instead": "显示自 {{timeFilterName}} 以来的帖子,<1>显示所有帖子", "subplebbit_offline_info": "子维基可能离线,发布可能失败。", "posts_last_synced_info": "最后同步的帖子 {{time}}, 子维基可能离线,发布可能失败。", - "stored_locally": "本地存储 ({{location}}),未在设备之间同步" + "stored_locally": "本地存储 ({{location}}),未在设备之间同步", + "import_account_backup": "<1>导入账户备份", + "export_account_backup": "<1>导出账户备份", + "save_reset_changes": "<1>保存或<2>重置更改", + "delete_this_account": "<1>删除此账户", + "create_new_account": "<1>创建新账户", + "wallet_number": "钱包 #{{index}}", + "view_more": "查看更多" } \ No newline at end of file diff --git a/src/app.tsx b/src/app.tsx index f5c50150..268a0e25 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -85,12 +85,14 @@ const App = () => { } /> - } /> - } /> - } /> - } /> - } /> - } /> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> diff --git a/src/components/post/embed/embed.tsx b/src/components/post/embed/embed.tsx index 3885a89d..ce33fd2b 100644 --- a/src/components/post/embed/embed.tsx +++ b/src/components/post/embed/embed.tsx @@ -306,6 +306,11 @@ const canEmbedHosts = new Set([ ]); export const canEmbed = (parsedUrl: URL): boolean => { + if (redditHosts.has(parsedUrl.host)) { + // Reddit posts are not embeddable if the URL does not include '/comments/' + return parsedUrl.pathname.includes('/comments/'); + } + return canEmbedHosts.has(parsedUrl.host) || (parsedUrl.host.startsWith('yt.') && parsedUrl.searchParams.has('v')); }; diff --git a/src/components/post/post.tsx b/src/components/post/post.tsx index 55727f4f..c2195bb2 100644 --- a/src/components/post/post.tsx +++ b/src/components/post/post.tsx @@ -132,7 +132,7 @@ const Post = ({ index, post = {} }: PostProps) => { fetchThumbnail(); }, [fetchThumbnail]); - const [isExpanded, setIsExpanded] = useState(isInPostView && commentMediaInfo?.type !== 'webpage'); + const [isExpanded, setIsExpanded] = useState(isInPostView); const toggleExpanded = () => setIsExpanded(!isExpanded); const [isEditing, setIsEditing] = useState(false); @@ -141,7 +141,15 @@ const Post = ({ index, post = {} }: PostProps) => { const [upvoted, upvote] = useUpvote(post); const [downvoted, downvote] = useDownvote(post); - const postScore = upvoteCount === 0 && downvoteCount === 0 ? '•' : upvoteCount - downvoteCount || '?'; + const getPostScore = () => { + if ((upvoteCount === 0 && downvoteCount === 0) || state !== 'succeeded') { + return '•'; + } else if (upvoteCount === undefined || downvoteCount === undefined) { + return '?'; + } + return upvoteCount - downvoteCount; + }; + const postTitle = (title?.length > 300 ? title?.slice(0, 300) + '...' : title) || (content?.length > 300 ? content?.slice(0, 300) + '...' : content); const hasThumbnail = getHasThumbnail(commentMediaInfo, link); @@ -181,7 +189,7 @@ const Post = ({ index, post = {} }: PostProps) => {
cid && upvote()} />
-
{postScore}
+
{getPostScore()}
cid && downvote()} />
@@ -232,7 +240,7 @@ const Post = ({ index, post = {} }: PostProps) => { { authorEditReason={edit?.reason} commentMediaInfo={commentMediaInfo} content={removed ? `[${_.lowerCase(t('removed'))}]` : deleted ? `[${_.lowerCase(t('deleted'))}]` : content} - expanded={isExpanded} + expanded={commentMediaInfo?.type === 'webpage' ? false : isExpanded} link={link} modEditReason={reason} deleted={deleted} diff --git a/src/hooks/use-fetch-gif-first-frame.ts b/src/hooks/use-fetch-gif-first-frame.ts index 97c86cba..a7f21054 100644 --- a/src/hooks/use-fetch-gif-first-frame.ts +++ b/src/hooks/use-fetch-gif-first-frame.ts @@ -1,16 +1,14 @@ import { useEffect, useState } from 'react'; +import localForageLru from '@plebbit/plebbit-react-hooks/dist/lib/localforage-lru/index.js'; -const GIF_FRAME_CACHE_KEY = 'gifFrameCache'; +const gifFrameDb = localForageLru.createInstance({ name: 'seeditGifFrames', size: 500 }); -const getCachedGifFrame = (url: string): string | null => { - const cache = JSON.parse(localStorage.getItem(GIF_FRAME_CACHE_KEY) || '{}'); - return cache[url] || null; +const getCachedGifFrame = async (url: string): Promise => { + return await gifFrameDb.getItem(url); }; -const setCachedGifFrame = (url: string, frameUrl: string): void => { - const cache = JSON.parse(localStorage.getItem(GIF_FRAME_CACHE_KEY) || '{}'); - cache[url] = frameUrl; - localStorage.setItem(GIF_FRAME_CACHE_KEY, JSON.stringify(cache)); +const setCachedGifFrame = async (url: string, frameUrl: string): Promise => { + await gifFrameDb.setItem(url, frameUrl); }; export const fetchImage = (url: string): Promise => { @@ -75,7 +73,7 @@ const useFetchGifFirstFrame = (url: string | undefined) => { const fetchFrame = async () => { try { - const cachedFrame = getCachedGifFrame(url); + const cachedFrame = await getCachedGifFrame(url); if (cachedFrame) { if (isActive) setFrameUrl(cachedFrame); return; @@ -85,7 +83,7 @@ const useFetchGifFirstFrame = (url: string | undefined) => { const objectUrl = URL.createObjectURL(blob); if (isActive) { setFrameUrl(objectUrl); - setCachedGifFrame(url, objectUrl); + await setCachedGifFrame(url, objectUrl); } } catch (error) { console.error('Failed to load GIF frame:', error); @@ -95,7 +93,6 @@ const useFetchGifFirstFrame = (url: string | undefined) => { fetchFrame(); - // Cleanup function to avoid setting state on unmounted component return () => { isActive = false; }; diff --git a/src/lib/utils/media-utils.ts b/src/lib/utils/media-utils.ts index 5e30f7f2..ee327922 100644 --- a/src/lib/utils/media-utils.ts +++ b/src/lib/utils/media-utils.ts @@ -1,3 +1,4 @@ +import localForageLru from '@plebbit/plebbit-react-hooks/dist/lib/localforage-lru/index.js'; import { Comment } from '@plebbit/plebbit-react-hooks'; import extName from 'ext-name'; import { canEmbed } from '../../components/post/embed'; @@ -60,7 +61,7 @@ export const getLinkMediaInfo = memoize( } try { - mime = extName(new URL(link).pathname.toLowerCase().replace('/', ''))[0]?.mime; + mime = extName(url.pathname.toLowerCase().replace('/', ''))[0]?.mime; if (mime) { if (mime.startsWith('image')) { type = mime === 'image/gif' ? 'gif' : 'image'; @@ -162,29 +163,27 @@ const fetchWebpageThumbnail = async (url: string): Promise = } }; +const thumbnailUrlsDb = localForageLru.createInstance({ name: 'seeditThumbnailUrls', size: 500 }); + +export const getCachedThumbnail = async (url: string): Promise => { + return await thumbnailUrlsDb.getItem(url); +}; + +export const setCachedThumbnail = async (url: string, thumbnail: string): Promise => { + await thumbnailUrlsDb.setItem(url, thumbnail); +}; + export const fetchWebpageThumbnailIfNeeded = async (commentMediaInfo: CommentMediaInfo): Promise => { if (commentMediaInfo.type === 'webpage' && !commentMediaInfo.thumbnail) { - const cachedThumbnail = getCachedThumbnail(commentMediaInfo.url); + const cachedThumbnail = await getCachedThumbnail(commentMediaInfo.url); if (cachedThumbnail) { return { ...commentMediaInfo, thumbnail: cachedThumbnail }; } const thumbnail = await fetchWebpageThumbnail(commentMediaInfo.url); if (thumbnail) { - setCachedThumbnail(commentMediaInfo.url, thumbnail); + await setCachedThumbnail(commentMediaInfo.url, thumbnail); } return { ...commentMediaInfo, thumbnail }; } return commentMediaInfo; }; -const THUMBNAIL_CACHE_KEY = 'webpageThumbnailCache'; - -export const getCachedThumbnail = (url: string): string | null => { - const cache = JSON.parse(localStorage.getItem(THUMBNAIL_CACHE_KEY) || '{}'); - return cache[url] || null; -}; - -export const setCachedThumbnail = (url: string, thumbnail: string): void => { - const cache = JSON.parse(localStorage.getItem(THUMBNAIL_CACHE_KEY) || '{}'); - cache[url] = thumbnail; - localStorage.setItem(THUMBNAIL_CACHE_KEY, JSON.stringify(cache)); -}; diff --git a/src/themes.css b/src/themes.css index 182d201e..6cc6760d 100644 --- a/src/themes.css +++ b/src/themes.css @@ -1,139 +1,136 @@ -:root .light { - --blue: blue; - --orange: #FF7500; - --green: #228822; - --green-bright: #3bc54c; - --yellow: goldenrod; - --yellow-box-contrast: #ffd634; - --yellow-box-background: #fff7d7; - --yellow-box-icon: #ffd634; - --yellow-table: #ffff99; - --code-background: #fcfcfb; - --code-border: #e6e6de; - --red: red; - --gray: #c0c0c0; - --gray-footer: dimgray; +:root .dark { + --account-dropdown-arrow: url("/public/assets/buttons/droparrowgray.gif"); + --background: #0f0f0f; + --background-contrast: #141414; + --background-markdown: #1f1f1f; + --background-primary: #1f1f1f; + --background-secondary: #3e3e3e; + --background-text: #0f0f0f; + --background-thumbnail: rgba(255, 255, 255, 0.01); + --border-contrast: #6a6a6a; + --border-orange: #a76d00; + --border-primary: #1f1f1f; + --border-text: #3e3e3e; + --button-border-disabled: #6f6f6f34; + --button-border-primary: #1f1f1f; + --button-border-primary-hover: #3e3e3e; + --button-large: url('/public/assets/buttons/button-large-dark.png'); + --button-large-disabled: url('/public/assets/buttons/button-large-disabled-dark.png'); + --button-large-hover: url('/public/assets/buttons/button-large-hover-dark.png'); + --button-large-hover-nub: url('/public/assets/buttons/button-large-nub-hover-dark.png'); + --button-large-nub: url('/public/assets/buttons/button-large-nub-dark.png'); + --button-large-nub-disabled: url('/public/assets/buttons/button-large-nub-disabled-dark.png'); + --close-button: url("/public/assets/buttons/close-button-dark.png"); + --close-button-hover: url("/public/assets/buttons/close-button-hover.png"); + --continue-thread-arrow: url('/public/assets/buttons/continue-this-thread-arrow-dark.png'); + --code-background: rgb(19, 19, 13); + --code-border: rgb(52, 58, 60); + --filter80: brightness(80%); + --filter90: brightness(90%); + --gray: #3e3e3e; + --gray-border: #3e3e3e; --gray-button-text: #aaa; - --gray-footer-separator: rgb(151, 151, 151); - --gray-contrast: #888; - --gray-overlay: #F7F7F7; - --gray-overlay-border: #E9E9E9; - --gray-border: #ddd; - --border-contrast: black; - --gray-light: #ccc; - --box-shadow-modal: 4px 4px 4px #ccc; - --box-shadow-input: inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6); - --filter80: brightness(100%); - --filter90: brightness(100%); + --gray-contrast: #c7c7c7; + --gray-footer: rgb(168, 160, 147); + --gray-footer-separator: #6a6a6a; + --gray-light: #3e3e3e9d; + --gray-overlay: #1f1f1f; + --gray-overlay-border: #3e3e3e; + --green: #228822; + --green-bright: rgb(76, 207, 92); + --icon: #c6c6c6; + --link: #bfbfbf; + --link-primary: rgb(125, 175, 216); + --link-visited: #757575; + --markdown-blockquote: rgb(185, 178, 168); + --markdown-blockquote-border: rgb(65, 70, 73); + --markdown-link: rgb(74, 183, 255); + --pagination-button-background: rgb(29, 31, 34); + --pagination-button-border: 1px solid rgb(55, 59, 62); + --pagination-button-border-hover: 1px solid #5a728a; + --play-button: url("/public/assets/buttons/play-button-dark.png"); + --play-button-hover: url("/public/assets/buttons/play-button-hover.png"); + --red: rgb(200, 0, 0); + --text: #bfbfbf; + --text-button: url("/public/assets/buttons/text-button-dark.png"); + --text-button-hover: url("/public/assets/buttons/text-button-hover.png"); + --text-input: white; + --text-info: #757575; + --text-markdown: #f0f0f0; + --text-primary: #c7c7c7; + --yellow: rgb(200, 171, 0); + --yellow-box-background: rgb(56, 45, 0); + --yellow-box-contrast: rgb(163, 130, 0); + --yellow-box-icon: rgb(130, 103, 0); + --yellow-highlight: rgb(58, 50, 0); + --yellow-table: rgb(130, 103, 0); +} + +:root .light { + --account-dropdown-arrow: url("/public/assets/buttons/droparrowblue.gif"); --background: white; + --background-contrast: #E4F2FB; + --background-markdown: #fafafa; + --background-orange: #f6e69f; --background-primary: #cee3f8; --background-secondary: #eff7ff; --background-text: #f0f0f0; --background-thumbnail: rgba(0, 0, 0, 0.05); - --background-markdown: #fafafa; - --background-contrast: #E4F2FB; - --background-orange: #f6e69f; - --yellow-highlight: #ffc; - --text: black; - --text-input: black; - --text-markdown: #222222; - --markdown-link: #0079d3; - --markdown-blockquote: #4f4f4f; - --markdown-blockquote-border: #c5c1ad; - --text-primary: #369; - --button-border-primary: #c4dbf1; - --button-border-primary-hover: #879eb4; - --button-border-disabled: #dadada; - --text-info: #888; + --border-contrast: black; + --border-orange: #ffa500; --border-primary: #5f99cf; --border-text: gray; - --border-orange: #ffa500; - --link: #0000ff; - --link-primary: #369; - --link-visited: #551a8b; - --icon: #c6c6c6; - --text-button: url("/public/assets/buttons/text-button.png"); - --text-button-hover: url("/public/assets/buttons/text-button-hover.png"); - --play-button: url("/public/assets/buttons/play-button.png"); - --play-button-hover: url("/public/assets/buttons/play-button-hover.png"); - --close-button: url("/public/assets/buttons/close-button.png"); - --close-button-hover: url("/public/assets/buttons/close-button-hover.png"); + --button-border-disabled: #dadada; + --button-border-primary: #c4dbf1; + --button-border-primary-hover: #879eb4; --button-large: url('/public/assets/buttons/button-large.png'); + --button-large-disabled: url('/public/assets/buttons/button-large-disabled.png'); --button-large-hover: url('/public/assets/buttons/button-large-hover.png'); - --button-large-nub: url('/public/assets/buttons/button-large-nub.png'); --button-large-hover-nub: url('/public/assets/buttons/button-large-nub-hover.png'); - --button-large-disabled: url('/public/assets/buttons/button-large-disabled.png'); + --button-large-nub: url('/public/assets/buttons/button-large-nub.png'); --button-large-nub-disabled: url('/public/assets/buttons/button-large-nub-disabled.png'); - --account-dropdown-arrow: url("/public/assets/buttons/droparrowblue.gif"); + --close-button: url("/public/assets/buttons/close-button.png"); + --close-button-hover: url("/public/assets/buttons/close-button-hover.png"); --continue-thread-arrow: url('/public/assets/buttons/continue-this-thread-arrow.png'); -} - -:root .dark { - --blue: rgb(47, 125, 255); - --orange: #FF7500; - --green: #228822; - --green-bright: rgb(76, 207, 92); - --yellow: rgb(200, 171, 0); - --yellow-highlight: rgb(58, 50, 0); - --yellow-box-contrast: rgb(163, 130, 0); - --yellow-box-background: rgb(56, 45, 0); - --yellow-box-icon: rgb(130, 103, 0); - --yellow-table: rgb(130, 103, 0); - --code-background: rgb(19, 19, 13); - --code-border: rgb(52, 58, 60); - --red: rgb(200, 0, 0); - --gray: #3e3e3e; + --code-background: #fcfcfb; + --code-border: #e6e6de; + --filter80: brightness(100%); + --filter90: brightness(100%); + --gray: #c0c0c0; + --gray-border: #ddd; --gray-button-text: #aaa; - --gray-footer: rgb(168, 160, 147); - --gray-footer-separator: #6a6a6a; - --gray-contrast: #c7c7c7; - --gray-overlay: #1f1f1f; - --gray-overlay-border: #3e3e3e; - --gray-border: #3e3e3e; - --border-contrast: #6a6a6a; - --gray-light: #3e3e3e9d; - --box-shadow-modal: 4px 4px 4px #000; - --box-shadow-input: none; - --filter80: brightness(80%); - --filter90: brightness(90%); - --background: #0f0f0f; - --background-primary: #1f1f1f; - --background-secondary: #3e3e3e; - --background-text: #0f0f0f; - --background-thumbnail: rgba(255, 255, 255, 0.01); - --background-markdown: #1f1f1f; - --background-contrast: #141414; - --background-orange: #4a3700; - --text: #bfbfbf; - --text-input: white; - --text-markdown: #f0f0f0; - --markdown-link: rgb(74, 183, 255); - --markdown-blockquote: rgb(185, 178, 168); - --markdown-blockquote-border: rgb(65, 70, 73); - --text-primary: #c7c7c7; - --button-border-primary: #1f1f1f; - --button-border-primary-hover: #3e3e3e; - --button-border-disabled: #6f6f6f34; - --text-info: #757575; - --border-primary: #1f1f1f; - --border-text: #3e3e3e; - --border-orange: #a76d00; - --link: #bfbfbf; - --link-primary: rgb(125, 175, 216); - --link-visited: #757575; + --gray-contrast: #888; + --gray-footer: dimgray; + --gray-footer-separator: rgb(151, 151, 151); + --gray-light: #ccc; + --gray-overlay: #F7F7F7; + --gray-overlay-border: #E9E9E9; + --green: #228822; + --green-bright: #3bc54c; --icon: #c6c6c6; - --text-button: url("/public/assets/buttons/text-button-dark.png"); - --text-button-hover: url("/public/assets/buttons/text-button-hover.png"); - --play-button: url("/public/assets/buttons/play-button-dark.png"); + --link: #0000ff; + --link-primary: #369; + --link-visited: #551a8b; + --markdown-blockquote: #4f4f4f; + --markdown-blockquote-border: #c5c1ad; + --markdown-link: #0079d3; + --pagination-button-background: #eee; + --pagination-button-border: 1px solid #ddd; + --pagination-button-border-hover: 1px solid #82A6C9; + --play-button: url("/public/assets/buttons/play-button.png"); --play-button-hover: url("/public/assets/buttons/play-button-hover.png"); - --close-button: url("/public/assets/buttons/close-button-dark.png"); - --close-button-hover: url("/public/assets/buttons/close-button-hover.png"); - --button-large: url('/public/assets/buttons/button-large-dark.png'); - --button-large-hover: url('/public/assets/buttons/button-large-hover-dark.png'); - --button-large-nub: url('/public/assets/buttons/button-large-nub-dark.png'); - --button-large-hover-nub: url('/public/assets/buttons/button-large-nub-hover-dark.png'); - --button-large-disabled: url('/public/assets/buttons/button-large-disabled-dark.png'); - --button-large-nub-disabled: url('/public/assets/buttons/button-large-nub-disabled-dark.png'); - --account-dropdown-arrow: url("/public/assets/buttons/droparrowgray.gif"); - --continue-thread-arrow: url('/public/assets/buttons/continue-this-thread-arrow-dark.png'); -} \ No newline at end of file + --red: red; + --text: black; + --text-button: url("/public/assets/buttons/text-button.png"); + --text-button-hover: url("/public/assets/buttons/text-button-hover.png"); + --text-input: black; + --text-info: #888; + --text-markdown: #222222; + --text-primary: #369; + --yellow: goldenrod; + --yellow-box-background: #fff7d7; + --yellow-box-contrast: #ffd634; + --yellow-box-icon: #ffd634; + --yellow-highlight: #ffc; + --yellow-table: #ffff99; +} diff --git a/src/views/all/all.tsx b/src/views/all/all.tsx index 7809da55..6d30d546 100644 --- a/src/views/all/all.tsx +++ b/src/views/all/all.tsx @@ -1,5 +1,5 @@ -import { useEffect, useRef } from 'react'; -import { useParams } from 'react-router-dom'; +import { useEffect, useRef, useState } from 'react'; +import { Link, useParams } from 'react-router-dom'; import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso'; import { useFeed } from '@plebbit/plebbit-react-hooks'; import { Trans, useTranslation } from 'react-i18next'; @@ -20,26 +20,32 @@ const All = () => { const sortType = params?.sortType || 'hot'; const timeFilterName = params.timeFilterName; const { timeFilterSeconds } = useTimeFilter(); - const { feed, hasMore, loadMore } = useFeed({ subplebbitAddresses, sortType, newerThan: timeFilterSeconds }); + const { feed, hasMore, loadMore, reset, subplebbitAddressesWithNewerPosts } = useFeed({ subplebbitAddresses, sortType, newerThan: timeFilterSeconds }); const { t } = useTranslation(); - let loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading'); - - const loadingString = ( -
- {subplebbitAddresses.length === 0 ? ( -
- https://github.com/plebbit/temporary-default-subplebbits]} - /> -
- {t('connect_community_notice')} -
- ) : ( - - )} -
- ); + + // suggest the user to change time filter if there aren't enough posts + const { feed: weeklyFeed } = useFeed({ subplebbitAddresses, sortType, newerThan: 60 * 60 * 24 * 7 }); + const { feed: monthlyFeed } = useFeed({ subplebbitAddresses, sortType, newerThan: 60 * 60 * 24 * 30 }); + + const loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading'); + + const handleNewerPostsButtonClick = () => { + window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); + setTimeout(() => { + reset(); + }, 300); + }; + + const currentTimeFilterName = params.timeFilterName || timeFilterName; + + const [showMorePostsSuggestion, setShowMorePostsSuggestion] = useState(false); + useEffect(() => { + const timer = setTimeout(() => { + setShowMorePostsSuggestion(true); + }, 5000); + + return () => clearTimeout(timer); + }, []); const documentTitle = _.capitalize(t('all')) + ' - Seedit'; useEffect(() => { @@ -52,11 +58,60 @@ const All = () => { if (feed.length === 0) { footerContent = t('no_posts'); } - - if (hasMore || subplebbitAddresses.length === 0) { - footerContent = loadingString; + if (hasMore || (subplebbitAddresses && subplebbitAddresses.length === 0)) { + footerContent = ( + <> + {subplebbitAddressesWithNewerPosts.length > 0 ? ( +
+ , + }} + /> +
+ ) : ( + showMorePostsSuggestion && + monthlyFeed.length > feed.length && + (weeklyFeed.length > feed.length ? ( +
+ , + }} + /> +
+ ) : ( +
+ , + }} + /> +
+ )) + )} +
+ {subplebbitAddresses.length === 0 ? ( +
+ https://github.com/plebbit/temporary-default-subplebbits]} + /> +
+ {t('connect_community_notice')} +
+ ) : ( + + )} +
+ + ); } - return
{footerContent}
; }; diff --git a/src/views/profile/profile.module.css b/src/views/profile/profile.module.css index 13454df8..7665bd0e 100644 --- a/src/views/profile/profile.module.css +++ b/src/views/profile/profile.module.css @@ -99,4 +99,31 @@ div[data-viewport-type="window"] { .dropChoicesVisible { display: block; +} + +.pagination { + font-size: 12px; + margin-top: 10px; +} + +.pagination .button { + padding: 1px 4px; + background: var(--pagination-button-background); + border: var(--pagination-button-border); + border-radius: 3px; + font-weight: bold; + cursor: pointer; + text-transform: lowercase; + color: var(--link-primary); +} + +.pagination .button:hover { + border: var(--pagination-button-border-hover); +} + +.pagination .separator { + margin: 0; + margin-left: .5em; + padding-left: .5em; + border-left: 1px solid var(--text-info); } \ No newline at end of file diff --git a/src/views/profile/profile.tsx b/src/views/profile/profile.tsx index 20a46b19..17d148f8 100644 --- a/src/views/profile/profile.tsx +++ b/src/views/profile/profile.tsx @@ -1,17 +1,17 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import { Link, useLocation, useParams } from 'react-router-dom'; +import { Link, Outlet, useParams } from 'react-router-dom'; import { StateSnapshot, Virtuoso, VirtuosoHandle } from 'react-virtuoso'; -import { useAccount, useAccountComments, useAccountVotes, useComments } from '@plebbit/plebbit-react-hooks'; -import { isProfileDownvotedView, isProfileUpvotedView, isProfileCommentsView, isProfileSubmittedView, isProfileHiddenView } from '../../lib/utils/view-utils'; +import { useAccount, useAccountComments, useAccountVotes, useComment } from '@plebbit/plebbit-react-hooks'; import useWindowWidth from '../../hooks/use-window-width'; import AuthorSidebar from '../../components/author-sidebar'; import Post from '../../components/post'; import Reply from '../../components/reply'; import styles from './profile.module.css'; -const lastVirtuosoStates: { [key: string]: StateSnapshot } = {}; +const pageSize = 10; const sortTypes: string[] = ['new', 'old']; +const lastVirtuosoStates: { [key: string]: StateSnapshot } = {}; type SortDropdownProps = { onSortChange: (sortType: string) => void; @@ -67,142 +67,180 @@ const SortDropdown = ({ onSortChange }: SortDropdownProps) => { ); }; -const pageSize = 10; - -const Profile = () => { +const PaginationControls = ({ currentPage, hasMore, onPageChange }: { currentPage: number; hasMore: boolean; onPageChange: (page: number) => void }) => { const { t } = useTranslation(); + return ( + (hasMore || currentPage > 1) && ( +
+ {t('view_more')}:{' '} + {currentPage > 1 && ( + onPageChange(currentPage - 1)}> + ‹ {t('previous')} + + )} + {hasMore && ( + <> + {currentPage > 1 && } + onPageChange(currentPage + 1)}> + {t('next')} › + + + )} +
+ ) + ); +}; + +const CommentItem = ({ cid }: { cid: string }) => { + const comment = useComment({ commentCid: cid }); + + if (!comment) return null; + + return comment.parentCid ? : ; +}; + +const VirtualizedCommentList = ({ comments }: { comments: any[] }) => { const account = useAccount(); - const location = useLocation(); const params = useParams(); - const isMobile = useWindowWidth() < 640; + // save last virtuoso state on each scroll + const virtuosoRef = useRef(null); + const lastVirtuosoState = lastVirtuosoStates?.[account?.shortAddress + params.sortType]; + useEffect(() => { + const setLastVirtuosoState = () => + virtuosoRef.current?.getState((snapshot: StateSnapshot) => { + if (snapshot?.ranges?.length) { + lastVirtuosoStates[account?.shortAddress + params.sortType] = snapshot; + } + }); + window.addEventListener('scroll', setLastVirtuosoState); + return () => window.removeEventListener('scroll', setLastVirtuosoState); + }, [account?.shortAddress, params.sortType]); - const [activeTab, setActiveTab] = useState('overview'); - const [currentPage, setCurrentPage] = useState(1); + return ( + + post?.parentCid ? : + } + useWindowScroll={true} + ref={virtuosoRef} + restoreStateFrom={lastVirtuosoState} + initialScrollTop={lastVirtuosoState?.scrollTop} + /> + ); +}; - const isInProfileUpvotedView = isProfileUpvotedView(location.pathname); - const isInProfileDownvotedView = isProfileDownvotedView(location.pathname); - const isInProfileHiddenView = isProfileHiddenView(location.pathname); - const isInCommentsView = isProfileCommentsView(location.pathname); - const isInSubmittedView = isProfileSubmittedView(location.pathname); +const Overview = () => { + const { t } = useTranslation(); + const { accountComments } = useAccountComments(); + const [sortType, setSortType] = useState('new'); - useEffect(() => { - if (isInProfileUpvotedView) setActiveTab('upvoted'); - else if (isInProfileDownvotedView) setActiveTab('downvoted'); - else if (isInProfileHiddenView) setActiveTab('hidden'); - else if (isInCommentsView) setActiveTab('comments'); - else if (isInSubmittedView) setActiveTab('submitted'); - else setActiveTab('overview'); + const sortedComments = useMemo(() => { + return [...accountComments].sort((a, b) => (sortType === 'new' ? b.timestamp - a.timestamp : a.timestamp - b.timestamp)); + }, [accountComments, sortType]); - setCurrentPage(1); // Reset page when changing tabs - }, [isInProfileUpvotedView, isInProfileDownvotedView, isInProfileHiddenView, isInCommentsView, isInSubmittedView]); + return ( +
+ + {sortedComments.length === 0 ?
{t('no_posts')}
: } +
+ ); +}; +const Comments = () => { + const { t } = useTranslation(); const { accountComments } = useAccountComments(); - const { accountVotes } = useAccountVotes(); + const [sortType, setSortType] = useState('new'); - const postComments = useMemo(() => accountComments?.filter((comment) => !comment.parentCid) || [], [accountComments]); const replyComments = useMemo(() => accountComments?.filter((comment) => comment.parentCid) || [], [accountComments]); - const upvotedCommentCids = useMemo(() => { - const allUpvotedCids = accountVotes?.filter((vote) => vote.vote === 1).map((vote) => vote.commentCid) || []; - return allUpvotedCids.slice(0, currentPage * pageSize); - }, [accountVotes, currentPage]); + const sortedComments = useMemo(() => { + return [...replyComments].sort((a, b) => (sortType === 'new' ? b.timestamp - a.timestamp : a.timestamp - b.timestamp)); + }, [replyComments, sortType]); - const downvotedCommentCids = useMemo(() => { - const allDownvotedCids = accountVotes?.filter((vote) => vote.vote === -1).map((vote) => vote.commentCid) || []; - return allDownvotedCids.slice(0, currentPage * pageSize); - }, [accountVotes, currentPage]); - - const hiddenCommentCids = useMemo(() => { - const allHiddenCids = Object.keys(account?.blockedCids ?? {}); - return allHiddenCids.slice(0, currentPage * pageSize); - }, [account?.blockedCids, currentPage]); + return ( +
+ + {sortedComments.length === 0 ?
{t('no_comments')}
: } +
+ ); +}; - const { hasMoreUpvoted, hasMoreDownvoted, hasMoreHidden } = useMemo(() => { - const allUpvotedCids = accountVotes?.filter((vote) => vote.vote === 1).map((vote) => vote.commentCid) || []; - const allDownvotedCids = accountVotes?.filter((vote) => vote.vote === -1).map((vote) => vote.commentCid) || []; - const allHiddenCids = Object.keys(account?.blockedCids ?? {}); +const Submitted = () => { + const { t } = useTranslation(); + const { accountComments } = useAccountComments(); + const [sortType, setSortType] = useState('new'); - return { - hasMoreUpvoted: currentPage * pageSize < allUpvotedCids.length, - hasMoreDownvoted: currentPage * pageSize < allDownvotedCids.length, - hasMoreHidden: currentPage * pageSize < allHiddenCids.length, - }; - }, [accountVotes, account?.blockedCids, currentPage]); + const postComments = useMemo(() => accountComments?.filter((comment) => !comment.parentCid) || [], [accountComments]); - const hasMore = useMemo(() => { - if (isInProfileUpvotedView) return hasMoreUpvoted; - if (isInProfileDownvotedView) return hasMoreDownvoted; - if (isInProfileHiddenView) return hasMoreHidden; - return false; - }, [hasMoreUpvoted, hasMoreDownvoted, hasMoreHidden, isInProfileUpvotedView, isInProfileDownvotedView, isInProfileHiddenView]); + const sortedComments = useMemo(() => { + return [...postComments].sort((a, b) => (sortType === 'new' ? b.timestamp - a.timestamp : a.timestamp - b.timestamp)); + }, [postComments, sortType]); - const { comments: upvotedComments } = useComments({ commentCids: upvotedCommentCids }); - const { comments: downvotedComments } = useComments({ commentCids: downvotedCommentCids }); - const { comments: hiddenComments } = useComments({ commentCids: hiddenCommentCids }); + return ( +
+ + {sortedComments.length === 0 ?
{t('no_posts')}
: } +
+ ); +}; +const VotedComments = ({ voteType }: { voteType: 1 | -1 }) => { + const { t } = useTranslation(); + const { accountVotes } = useAccountVotes(); + const [currentPage, setCurrentPage] = useState(1); const [sortType, setSortType] = useState('new'); - const handleSortChange = (newSortType: string) => { - setSortType(newSortType); - setCurrentPage(1); - }; - const comments = useMemo(() => { - let selectedComments; - switch (activeTab) { - case 'upvoted': - selectedComments = upvotedComments; - break; - case 'downvoted': - selectedComments = downvotedComments; - break; - case 'hidden': - selectedComments = hiddenComments; - break; - case 'comments': - selectedComments = replyComments; - break; - case 'submitted': - selectedComments = postComments; - break; - case 'overview': - default: - selectedComments = [...postComments, ...replyComments]; - } + const votedCommentCids = useMemo(() => { + const filteredVotes = accountVotes?.filter((vote) => vote.vote === voteType) || []; + const sortedVotes = filteredVotes.sort((a, b) => (sortType === 'new' ? b.timestamp - a.timestamp : a.timestamp - b.timestamp)); + return sortedVotes.map((vote) => vote.commentCid); + }, [accountVotes, voteType, sortType]); - // Sort comments - selectedComments.sort((a, b) => (sortType === 'new' ? b!.timestamp - a!.timestamp : a!.timestamp - b!.timestamp)); + const paginatedCids = votedCommentCids.slice((currentPage - 1) * pageSize, currentPage * pageSize); + const hasMore = currentPage * pageSize < votedCommentCids.length; - return selectedComments; - }, [activeTab, upvotedComments, downvotedComments, hiddenComments, replyComments, postComments, sortType]); + return ( +
+ + {paginatedCids.length === 0 ?
{t('no_posts')}
: paginatedCids.map((cid) => )} + +
+ ); +}; - const loadMore = useCallback(() => { - console.log('LoadMore called, current page:', currentPage); - setCurrentPage((prevPage) => { - const newPage = prevPage + 1; - console.log('Setting new page:', newPage); - return newPage; - }); - }, [currentPage]); +const HiddenComments = () => { + const { t } = useTranslation(); + const account = useAccount(); + const [currentPage, setCurrentPage] = useState(1); + + const hiddenCommentCids = useMemo(() => { + const allHiddenCids = Object.keys(account?.blockedCids ?? {}); + return allHiddenCids.slice(0, currentPage * pageSize); + }, [account?.blockedCids, currentPage]); + + const hasMore = (account?.blockedCids && Object.keys(account.blockedCids).length > currentPage * pageSize) || false; + + return ( +
+ {hiddenCommentCids.length === 0 ?
{t('no_hidden_posts')}
: hiddenCommentCids.map((cid) => )} + +
+ ); +}; + +const Profile = () => { + const { t } = useTranslation(); + const account = useAccount(); + const isMobile = useWindowWidth() < 640; const profileTitle = account?.author?.displayName ? `${account?.author?.displayName} (u/${account?.author?.shortAddress})` : `u/${account?.author?.shortAddress}`; useEffect(() => { document.title = profileTitle + ' - Seedit'; }, [t, profileTitle]); - // save last virtuoso state on each scroll - const virtuosoRef = useRef(null); - const lastVirtuosoState = lastVirtuosoStates?.[account?.shortAddress + params.sortType]; - useEffect(() => { - const setLastVirtuosoState = () => - virtuosoRef.current?.getState((snapshot: StateSnapshot) => { - if (snapshot?.ranges?.length) { - lastVirtuosoStates[account?.shortAddress + params.sortType] = snapshot; - } - }); - window.addEventListener('scroll', setLastVirtuosoState); - return () => window.removeEventListener('scroll', setLastVirtuosoState); - }, [account?.shortAddress, params.sortType]); - // only show infobar on first profile access and if the current account wasn't imported const showInfobarRef = useRef(false); useEffect(() => { @@ -228,26 +266,15 @@ const Profile = () => { {!isMobile && infobar}
- - {account && comments.length === 0 ? ( -
{t('no_posts')}
- ) : ( - - post?.parentCid ? : - } - endReached={hasMore ? loadMore : undefined} - useWindowScroll={true} - ref={virtuosoRef} - restoreStateFrom={lastVirtuosoState} - initialScrollTop={lastVirtuosoState?.scrollTop} - /> - )} +
); }; +Profile.Overview = Overview; +Profile.Comments = Comments; +Profile.Submitted = Submitted; +Profile.VotedComments = VotedComments; +Profile.HiddenComments = HiddenComments; + export default Profile; diff --git a/src/views/settings/account-settings/account-settings.tsx b/src/views/settings/account-settings/account-settings.tsx index 6585c539..c0a97837 100644 --- a/src/views/settings/account-settings/account-settings.tsx +++ b/src/views/settings/account-settings/account-settings.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { createAccount, deleteAccount, exportAccount, importAccount, setAccount, setActiveAccount, useAccount, useAccounts } from '@plebbit/plebbit-react-hooks'; import stringify from 'json-stringify-pretty-compact'; -import { useTranslation } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import styles from './account-settings.module.css'; import { Capacitor } from '@capacitor/core'; @@ -184,7 +184,12 @@ const AccountSettings = () => { {t('is_current_account')}
- {t('a_new_account')} + , + }} + />
{t('stored_locally', { @@ -197,16 +202,37 @@ const AccountSettings = () => {