Merge pull request #585 from plebbit/development

Development
This commit is contained in:
Tom (plebeius.eth)
2024-11-05 12:49:19 +01:00
committed by GitHub
62 changed files with 942 additions and 161 deletions
+1
View File
@@ -38,6 +38,7 @@ dependencies {
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation project(':capacitor-android')
implementation project(':capacitor-cordova-android-plugins')
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
+3 -4
View File
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
@@ -33,8 +36,4 @@
android:resource="@xml/file_paths"></meta-data>
</provider>
</application>
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
@@ -6,6 +6,12 @@
"plugins": {
"CapacitorHttp": {
"enabled": true
},
"FileUploader": {
"enabled": true
}
},
"server": {
"androidScheme": "https"
}
}
@@ -0,0 +1,110 @@
package plebchan.android;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.ActivityCallback;
import com.getcapacitor.PluginCall;
import androidx.activity.result.ActivityResult;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
@CapacitorPlugin(name = "FileUploader")
public class FileUploaderPlugin extends Plugin {
private static final String TAG = "FileUploaderPlugin";
@PluginMethod
public void pickAndUploadMedia(PluginCall call) {
Log.d(TAG, "pickAndUploadMedia called");
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
String[] mimeTypes = {"image/jpeg", "image/png", "video/mp4", "video/webm"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
startActivityForResult(call, intent, "pickFileResult");
}
@ActivityCallback
private void pickFileResult(PluginCall call, ActivityResult result) {
Log.d(TAG, "pickFileResult callback received");
if (call == null) {
return;
}
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
if (data != null) {
Uri uri = data.getData();
uploadToCatbox(uri, call);
} else {
call.reject("No data received");
}
} else {
call.reject("File selection cancelled");
}
}
private void uploadToCatbox(Uri fileUri, PluginCall call) {
new Thread(() -> {
try {
Log.d(TAG, "Starting file conversion from URI");
File file = FileUtils.getFileFromUri(getContext(), fileUri);
Log.d(TAG, "File name: " + file.getName());
JSObject statusUpdate = new JSObject();
statusUpdate.put("status", "Uploading to catbox.moe...");
notifyListeners("uploadStatus", statusUpdate);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("reqtype", "fileupload")
.addFormDataPart("fileToUpload", file.getName(),
RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
Request request = new Request.Builder()
.url("https://catbox.moe/user/api.php")
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected response " + response);
String url = response.body().string();
Log.d(TAG, "Upload successful. URL: " + url);
JSObject ret = new JSObject();
ret.put("url", url);
ret.put("fileName", file.getName());
ret.put("status", "Upload complete!");
call.resolve(ret);
}
} catch (Exception e) {
Log.e(TAG, "Upload failed", e);
call.reject("Upload failed: " + e.getMessage());
}
}).start();
}
}
@@ -0,0 +1,50 @@
package plebchan.android;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
public class FileUtils {
public static File getFileFromUri(Context context, Uri uri) throws Exception {
String fileName = getFileName(context, uri);
File file = new File(context.getCacheDir(), fileName);
try (InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file)) {
byte[] buffer = new byte[4096];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
outputStream.flush();
return file;
}
}
private static String getFileName(Context context, Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (columnIndex != -1) {
result = cursor.getString(columnIndex);
}
}
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
}
@@ -1,5 +1,12 @@
package plebchan.android;
import android.os.Bundle;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {}
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
registerPlugin(FileUploaderPlugin.class);
super.onCreate(savedInstanceState);
}
}
+7 -1
View File
@@ -9,7 +9,13 @@ const config: CapacitorConfig = {
CapacitorHttp: {
enabled: true,
},
FileUploader: {
enabled: true
}
},
server: {
androidScheme: 'https'
}
};
export default config;
export default config;
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "حذف المحفظة",
"loading_subplebbit": "جارٍ تحميل subplebbit",
"avatar_warning": "لا يمكنك النشر بصورة رمزية أثناء تفعيل وضع المجهول. يمكنك إيقافه في إعدادات حساب Plebbit الخاص بك.",
"last_bumped": "آخر رفع"
"last_bumped": "آخر رفع",
"threads_without_images_tip": "لا تعرض المشاركات بدون صور",
"hide_gore_boards_tip": "لا تعرض المشاركات من اللوحات ذات علامة \"دموية\"",
"hide_adult_boards_tip": "لا تعرض المشاركات من اللوحات ذات علامة \"بالغ\"",
"fit_expanded_images_to_screen": "تغيير حجم الصور الموسعة لتناسب الشاشة",
"fit_expanded_images_to_screen_tip": "حدد الصور الموسعة لكل من عرض وارتفاع المتصفح",
"hide_avatars_tip": "لا تعرض الصور الرمزية بجانب أسماء المستخدمين",
"choose_file": "اختر ملف",
"uploading": "جاري التحميل...",
"no_file_chosen": "لم يتم اختيار أي ملف",
"error": "خطأ",
"vote": "تصويت"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "ওয়ালেট মুছুন",
"loading_subplebbit": "সাবপ্লেবিট লোড হচ্ছে",
"avatar_warning": "অ্যানন মোড চালু থাকা অবস্থায় আপনি অ্যানিমেশন সহ পোস্ট করতে পারেন না। আপনি এটি আপনার Plebbit অ্যাকাউন্টের সেটিংসে বন্ধ করতে পারেন।",
"last_bumped": "শেষ.bump"
"last_bumped": "শেষ.bump",
"threads_without_images_tip": "ছবিহীন পোস্টগুলি প্রদর্শন করবেন না",
"hide_gore_boards_tip": "“গোর” ট্যাগ সহ বোর্ডের পোস্টগুলি প্রদর্শন করবেন না",
"hide_adult_boards_tip": "“বয়স্ক” ট্যাগযুক্ত বোর্ডের পোস্টগুলি প্রদর্শন করবেন না",
"fit_expanded_images_to_screen": "প্রসারিত ছবিগুলি স্ক্রীনে ফিট করুন",
"fit_expanded_images_to_screen_tip": "প্রসারিত ছবিগুলি ব্রাউজারের প্রস্থ এবং উচ্চতায় সীমাবদ্ধ করুন",
"hide_avatars_tip": "ব্যবহারকারীর প্রদর্শন নামের পাশে অ্যাভাটারগুলি দেখান না",
"choose_file": "ফাইল নির্বাচন করুন",
"uploading": "আপলোড হচ্ছে...",
"no_file_chosen": "কোন ফাইল নির্বাচিত নয়",
"error": "ত্রুটি",
"vote": "ভোট"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Smazat peněženku",
"loading_subplebbit": "Načítání subplebbit",
"avatar_warning": "Nemůžete zveřejňovat s avatarem, když je zapnutý anonymní režim. Můžete ho vypnout v nastavení svého účtu Plebbit.",
"last_bumped": "Poslední bump"
"last_bumped": "Poslední bump",
"threads_without_images_tip": "Nezobrazovat příspěvky bez obrázků",
"hide_gore_boards_tip": "Nezobrazovat příspěvky z desek s tagem \"gore\"",
"hide_adult_boards_tip": "Nezobrazovat příspěvky z desek s tagem \"adult\"",
"fit_expanded_images_to_screen": "Přizpůsobit rozšířené obrázky obrazovce",
"fit_expanded_images_to_screen_tip": "Omezení rozšířených obrázků na šířku a výšku prohlížeče",
"hide_avatars_tip": "Nezobrazovat avatary vedle jmen uživatelů",
"choose_file": "Vyberte soubor",
"uploading": "nahrávání...",
"no_file_chosen": "Žádný soubor není vybrán",
"error": "Chyba",
"vote": "hlasování"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Slet tegnebog",
"loading_subplebbit": "Indlæser subplebbit",
"avatar_warning": "Du kan ikke poste med et avatar, mens anonym tilstand er tændt. Du kan slukke det i dine Plebbit-kontoindstillinger.",
"last_bumped": "Sidste bumpet"
"last_bumped": "Sidste bumpet",
"threads_without_images_tip": "Vis ikke indlæg uden billeder",
"hide_gore_boards_tip": "Vis ikke indlæg fra boards med tagget \"gore\"",
"hide_adult_boards_tip": "Vis ikke indlæg fra boards med tagget \"adult\"",
"fit_expanded_images_to_screen": "Tilpas udvidede billeder til skærmen",
"fit_expanded_images_to_screen_tip": "Begræns udvidede billeder til både browserens bredde og højde",
"hide_avatars_tip": "Vis ikke avatarer ved siden af brugernes visningsnavne",
"choose_file": "Vælg fil",
"uploading": "uploading...",
"no_file_chosen": "Ingen fil valgt",
"error": "Fejl",
"vote": "stem"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Wallet löschen",
"loading_subplebbit": "Lade subplebbit",
"avatar_warning": "Sie können nicht mit einem Avatar posten, während der Anonymmodus aktiviert ist. Sie können ihn in den Einstellungen Ihres Plebbit-Kontos deaktivieren.",
"last_bumped": "Zuletzt hochgeladen"
"last_bumped": "Zuletzt hochgeladen",
"threads_without_images_tip": "Keine Beiträge ohne Bilder anzeigen",
"hide_gore_boards_tip": "Keine Beiträge von Boards mit dem Tag \"Gore\" anzeigen",
"hide_adult_boards_tip": "Keine Beiträge von Boards mit dem Tag \"adult\" anzeigen",
"fit_expanded_images_to_screen": "Erweiterte Bilder an den Bildschirm anpassen",
"fit_expanded_images_to_screen_tip": "Erweiterte Bilder auf die Breite und Höhe des Browsers beschränken",
"hide_avatars_tip": "Keine Avatare neben den Benutzernamen anzeigen",
"choose_file": "Datei auswählen",
"uploading": "Hochladen...",
"no_file_chosen": "Keine Datei ausgewählt",
"error": "Fehler",
"vote": "Abstimmung"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Διαγραφή πορτοφολιού",
"loading_subplebbit": "Φόρτωση subplebbit",
"avatar_warning": "Δεν μπορείτε να δημοσιεύσετε με avatar ενώ είναι ενεργοποιημένη η ανώνυμη λειτουργία. Μπορείτε να το απενεργοποιήσετε στις ρυθμίσεις του λογαριασμού σας Plebbit.",
"last_bumped": "Τελευταία ανύψωση"
"last_bumped": "Τελευταία ανύψωση",
"threads_without_images_tip": "Μην εμφανίζετε αναρτήσεις χωρίς εικόνες",
"hide_gore_boards_tip": "Μην εμφανίζετε αναρτήσεις από πίνακες με την ετικέτα \"gore\"",
"hide_adult_boards_tip": "Μην εμφανίζετε αναρτήσεις από πίνακες με την ετικέτα \"adult\"",
"fit_expanded_images_to_screen": "Προσαρμόστε τις επεκταμένες εικόνες στην οθόνη",
"fit_expanded_images_to_screen_tip": "Περιορίστε τις επεκταμένες εικόνες τόσο στο πλάτος όσο και στο ύψος του προγράμματος περιήγησης",
"hide_avatars_tip": "Μην εμφανίζετε τα avatar δίπλα στα ονόματα εμφάνισης χρηστών",
"choose_file": "Επιλέξτε αρχείο",
"uploading": "ανέβασμα...",
"no_file_chosen": "Δεν έχει επιλεγεί αρχείο",
"error": "Σφάλμα",
"vote": "ψηφοφορία"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Delete Wallet",
"loading_subplebbit": "Loading subplebbit",
"avatar_warning": "You can't post with an avatar while anon mode is turned on. You can turn it off in your Plebbit Account settings.",
"last_bumped": "Last Bumped"
"last_bumped": "Last Bumped",
"threads_without_images_tip": "Don't display posts without images",
"hide_gore_boards_tip": "Don't display posts from boards with the \"gore\" tag",
"hide_adult_boards_tip": "Don't display posts from boards with the \"adult\" tag",
"fit_expanded_images_to_screen": "Fit expanded images to screen",
"fit_expanded_images_to_screen_tip": "Limit expanded images to both browser width and height",
"hide_avatars_tip": "Don't display avatars next to user display names",
"choose_file": "Choose File",
"uploading": "uploading...",
"no_file_chosen": "No file chosen",
"error": "Error",
"vote": "vote"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Eliminar billetera",
"loading_subplebbit": "Cargando subplebbit",
"avatar_warning": "No puedes publicar con un avatar mientras el modo anónimo esté activado. Puedes desactivarlo en la configuración de tu cuenta Plebbit.",
"last_bumped": "Último bump"
"last_bumped": "Último bump",
"threads_without_images_tip": "No mostrar publicaciones sin imágenes",
"hide_gore_boards_tip": "No mostrar publicaciones de los tableros con la etiqueta \"gore\"",
"hide_adult_boards_tip": "No mostrar publicaciones de los tableros con la etiqueta \"adult\"",
"fit_expanded_images_to_screen": "Ajustar imágenes ampliadas a la pantalla",
"fit_expanded_images_to_screen_tip": "Limitar imágenes ampliadas tanto al ancho como a la altura del navegador",
"hide_avatars_tip": "No mostrar avatares junto a los nombres de usuario",
"choose_file": "Elige archivo",
"uploading": "subiendo...",
"no_file_chosen": "Ningún archivo elegido",
"error": "Error",
"vote": "voto"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "حذف کیف پول",
"loading_subplebbit": "در حال بارگذاری subplebbit",
"avatar_warning": "شما نمی‌توانید با آواتار پست بگذارید در حالی که حالت ناشناس فعال است. می‌توانید آن را در تنظیمات حساب Plebbit خود خاموش کنید.",
"last_bumped": "آخرین افزایش"
"last_bumped": "آخرین افزایش",
"threads_without_images_tip": "پست‌های بدون تصویر را نمایش ندهید",
"hide_gore_boards_tip": "پست‌های مربوط به تابلوهای با برچسب \"گور\" را نمایش ندهید",
"hide_adult_boards_tip": "پست‌های مربوط به تابلوهای با برچسب \"بزرگسال\" را نمایش ندهید",
"fit_expanded_images_to_screen": "اندازه تصاویر بزرگ شده را به صفحه نمایش بکنید",
"fit_expanded_images_to_screen_tip": "اندازه تصاویر بزرگ شده را به عرض و ارتفاع مرورگر محدود کنید",
"hide_avatars_tip": "تصاویر پروفایل را در کنار نام‌های نمایش کاربر نمایش ندهید",
"choose_file": "فایل را انتخاب کنید",
"uploading": "در حال بارگذاری...",
"no_file_chosen": "فایلی انتخاب نشده است",
"error": "خطا",
"vote": "رای"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Poista lompakko",
"loading_subplebbit": "Ladataan subplebbit",
"avatar_warning": "Et voi julkaista avatarilla, kun anonyymi tila on päällä. Voit poistaa sen käytöstä Plebbit-tilisi asetuksissa.",
"last_bumped": "Viimeisin bump"
"last_bumped": "Viimeisin bump",
"threads_without_images_tip": "Älä näytä viestejä ilman kuvia",
"hide_gore_boards_tip": "Älä näytä viestejä tauluista, joissa on \"gore\" -tagi",
"hide_adult_boards_tip": "Älä näytä viestejä tauluista, joissa on \"adult\" -tagi",
"fit_expanded_images_to_screen": "Sovita laajennettuja kuvia näyttöön",
"fit_expanded_images_to_screen_tip": "Rajoita laajennettuja kuvia sekä selaimen leveyteen että korkeuteen",
"hide_avatars_tip": "Älä näytä avatareita käyttäjänäyttönimien vieressä",
"choose_file": "Valitse tiedosto",
"uploading": "lataaminen...",
"no_file_chosen": "Ei tiedostoa valittu",
"error": "Virhe",
"vote": "äänestä"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Tanggalin ang Wallet",
"loading_subplebbit": "Naglo-load ng subplebbit",
"avatar_warning": "Hindi ka makakapag-post gamit ang avatar habang naka-on ang anon mode. Maaari mo itong i-off sa iyong mga setting ng Plebbit Account.",
"last_bumped": "Huling bump"
"last_bumped": "Huling bump",
"threads_without_images_tip": "Huwag ipakita ang mga post na walang mga imahe",
"hide_gore_boards_tip": "Huwag ipakita ang mga post mula sa mga board na may \"gore\" tag",
"hide_adult_boards_tip": "Huwag ipakita ang mga post mula sa mga board na may \"adult\" tag",
"fit_expanded_images_to_screen": "I-adjust ang mga pinalawak na larawan sa screen",
"fit_expanded_images_to_screen_tip": "Limitahan ang mga pinalawak na larawan sa parehong lapad at taas ng browser",
"hide_avatars_tip": "Huwag ipakita ang mga avatar sa tabi ng mga display name ng gumagamit",
"choose_file": "Pumili ng File",
"uploading": "ina-upload...",
"no_file_chosen": "Walang napiling file",
"error": "Error",
"vote": "bumoto"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Supprimer le portefeuille",
"loading_subplebbit": "Chargement de subplebbit",
"avatar_warning": "Vous ne pouvez pas publier avec un avatar pendant que le mode anonyme est activé. Vous pouvez le désactiver dans les paramètres de votre compte Plebbit.",
"last_bumped": "Dernière élévation"
"last_bumped": "Dernière élévation",
"threads_without_images_tip": "Ne pas afficher les publications sans images",
"hide_gore_boards_tip": "Ne pas afficher les publications des forums avec le tag \"gore\"",
"hide_adult_boards_tip": "Ne pas afficher les publications des forums avec le tag \"adult\"",
"fit_expanded_images_to_screen": "Ajuster les images agrandies à l'écran",
"fit_expanded_images_to_screen_tip": "Limiter les images agrandies à la fois à la largeur et à la hauteur du navigateur",
"hide_avatars_tip": "Ne pas afficher les avatars à côté des noms d'affichage des utilisateurs",
"choose_file": "Choisissez un fichier",
"uploading": "téléchargement...",
"no_file_chosen": "Aucun fichier choisi",
"error": "Erreur",
"vote": "vote"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "מחק ארנק",
"loading_subplebbit": "טוען subplebbit",
"avatar_warning": "אין באפשרותך לפרסם עם תמונת פרופיל בזמן שמצב אנונימי מופעל. תוכל לבטל זאת בהגדרות חשבון Plebbit שלך.",
"last_bumped": "הבום האחרון"
"last_bumped": "הבום האחרון",
"threads_without_images_tip": "אל תציג פוסטים ללא תמונות",
"hide_gore_boards_tip": "אל תציג פוסטים מלוחות עם תווית \"דם\"",
"hide_adult_boards_tip": "אל תציג פוסטים מלוחות עם תווית \"מבוגר\"",
"fit_expanded_images_to_screen": "התאם את התמונות המורחבות למסך",
"fit_expanded_images_to_screen_tip": "מגביל את התמונות המורחבות גם לרוחב וגם לגובה של הדפדפן",
"hide_avatars_tip": "אל תציג תמונות פרופיל לצד שמות המשתמשים",
"choose_file": "בחר קובץ",
"uploading": "מעלה...",
"no_file_chosen": "לא נבחר קובץ",
"error": "שגיאה",
"vote": "הצבעה"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "वॉलेट हटाएं",
"loading_subplebbit": "सबप्लेबिट लोड हो रहा है",
"avatar_warning": "जब अज्ञात मोड चालू होता है, तो आप अवतार के साथ पोस्ट नहीं कर सकते। आप इसे अपने Plebbit खाते की सेटिंग में बंद कर सकते हैं।",
"last_bumped": "अंतिम बंप"
"last_bumped": "अंतिम बंप",
"threads_without_images_tip": "बिना छवियों के पोस्ट प्रदर्शित न करें",
"hide_gore_boards_tip": "“गोर” टैग वाले बोर्डों से पोस्ट न दिखाएं",
"hide_adult_boards_tip": "“एडल्ट” टैग वाले बोर्डों से पोस्ट न दिखाएं",
"fit_expanded_images_to_screen": "विस्तृत चित्रों को स्क्रीन के अनुसार ढालें",
"fit_expanded_images_to_screen_tip": "विस्तृत चित्रों को ब्राउज़र की चौड़ाई और ऊंचाई दोनों तक सीमित करें",
"hide_avatars_tip": "उपयोगकर्ता प्रदर्शित नामों के बगल में अवतार न दिखाएं",
"choose_file": "फाइल चुनें",
"uploading": "अपलोड हो रहा है...",
"no_file_chosen": "कोई फ़ाइल नहीं चुनी गई",
"error": "त्रुटि",
"vote": "मत डालें"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Tárca törlése",
"loading_subplebbit": "Subplebbit betöltése",
"avatar_warning": "Nem posztolhatsz avatarral, míg az anon mód be van kapcsolva. Kikapcsolhatod a Plebbit-fiókod beállításaiban.",
"last_bumped": "Utolsó bump"
"last_bumped": "Utolsó bump",
"threads_without_images_tip": "Ne jelenjen meg képek nélküli bejegyzések",
"hide_gore_boards_tip": "Ne jelenjen meg a \"gore\" címkével rendelkező táblák bejegyzéseit",
"hide_adult_boards_tip": "Ne jelenjen meg a \"felnőtt\" címkével rendelkező táblák bejegyzéseit",
"fit_expanded_images_to_screen": "Illeszkedjen a kibővített képekhez a képernyőhöz",
"fit_expanded_images_to_screen_tip": "A kibővített képeket korlátozza a böngésző szélességére és magasságára",
"hide_avatars_tip": "Ne jelenjen meg az avatárok a felhasználói megjelenítési nevek mellett",
"choose_file": "Válassza ki a fájlt",
"uploading": "feltöltés...",
"no_file_chosen": "Nincs fájl kiválasztva",
"error": "Hiba",
"vote": "szavazás"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Hapus Dompet",
"loading_subplebbit": "Memuat subplebbit",
"avatar_warning": "Anda tidak bisa memposting dengan avatar saat mode anonim diaktifkan. Anda bisa mematikan ini di pengaturan Akun Plebbit Anda.",
"last_bumped": "Terakhir bump"
"last_bumped": "Terakhir bump",
"threads_without_images_tip": "Jangan tampilkan pos tanpa gambar",
"hide_gore_boards_tip": "Jangan tampilkan pos dari papan dengan tag \"gore\"",
"hide_adult_boards_tip": "Jangan tampilkan pos dari papan dengan tag \"adult\"",
"fit_expanded_images_to_screen": "Sesuaikan gambar yang diperluas ke layar",
"fit_expanded_images_to_screen_tip": "Batasi gambar yang diperluas baik pada lebar maupun tinggi browser",
"hide_avatars_tip": "Jangan tampilkan avatar di sebelah nama pengguna",
"choose_file": "Pilih Berkas",
"uploading": "mengupload...",
"no_file_chosen": "Tidak ada file yang dipilih",
"error": "Kesalahan",
"vote": "suara"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Elimina Wallet",
"loading_subplebbit": "Caricamento subplebbit",
"avatar_warning": "Non puoi postare con un avatar mentre la modalità anonima è attiva. Puoi disattivarla nelle impostazioni del tuo account Plebbit.",
"last_bumped": "Ultimo Bump"
"last_bumped": "Ultimo Bump",
"threads_without_images_tip": "Non mostrare i post senza immagini",
"hide_gore_boards_tip": "Non mostrare i post provenienti da bacheche con l'etichetta \"gore\"",
"hide_adult_boards_tip": "Non mostrare i post provenienti da bacheche con l'etichetta \"adult\"",
"fit_expanded_images_to_screen": "Adatta le immagini espanse allo schermo",
"fit_expanded_images_to_screen_tip": "Limita le immagini espanse sia alla larghezza che all'altezza del browser",
"hide_avatars_tip": "Non mostrare gli avatar accanto ai nomi visualizzati degli utenti",
"choose_file": "Scegli File",
"uploading": "caricamento...",
"no_file_chosen": "Nessun file scelto",
"error": "Errore",
"vote": "vota"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "ウォレットを削除",
"loading_subplebbit": "subplebbitを読み込んでいます",
"avatar_warning": "アバターを使用して投稿することはできません。匿名モードがオンになっている間は、Plebbitアカウントの設定でオフにできます。",
"last_bumped": "最後のバンプ"
"last_bumped": "最後のバンプ",
"threads_without_images_tip": "画像のない投稿を表示しない",
"hide_gore_boards_tip": "\"gore\" タグのあるボードからの投稿を表示しない",
"hide_adult_boards_tip": "\"adult\" タグのあるボードからの投稿を表示しない",
"fit_expanded_images_to_screen": "拡張された画像を画面に合わせる",
"fit_expanded_images_to_screen_tip": "拡張された画像をブラウザの幅と高さの両方に制限します",
"hide_avatars_tip": "ユーザーの表示名の横にアバターを表示しない",
"choose_file": "ファイルを選択",
"uploading": "アップロード中...",
"no_file_chosen": "ファイルが選択されていません",
"error": "エラー",
"vote": "投票"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "지갑 삭제",
"loading_subplebbit": "subplebbit 로딩 중",
"avatar_warning": "익명 모드가 켜져 있는 동안 아바타로 게시할 수 없습니다. Plebbit 계정 설정에서 끌 수 있습니다.",
"last_bumped": "마지막 bump"
"last_bumped": "마지막 bump",
"threads_without_images_tip": "이미지 없는 게시물을 표시하지 않음",
"hide_gore_boards_tip": "\"gore\" 태그가 있는 게시판의 게시물을 표시하지 않음",
"hide_adult_boards_tip": "\"adult\" 태그가 있는 게시판의 게시물을 표시하지 않음",
"fit_expanded_images_to_screen": "확장된 이미지를 화면에 맞추기",
"fit_expanded_images_to_screen_tip": "확장된 이미지를 브라우저의 너비와 높이로 제한합니다",
"hide_avatars_tip": "사용자 표시 이름 옆에 아바타를 표시하지 않음",
"choose_file": "파일 선택",
"uploading": "업로드 중...",
"no_file_chosen": "선택된 파일이 없습니다",
"error": "오류",
"vote": "투표"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "वॉलेट हटवा",
"loading_subplebbit": "subplebbit लोड करीत आहे",
"avatar_warning": "आपण अज्ञात मोड चालू असताना अवतारसह पोस्ट करू शकत नाही. आपण ते आपल्या Plebbit खात्याच्या सेटिंग्जमध्ये बंद करू शकता.",
"last_bumped": "अंतिम बंप"
"last_bumped": "अंतिम बंप",
"threads_without_images_tip": "चित्रांश न दर्शविणारे पोस्ट दर्शवू नका",
"hide_gore_boards_tip": "“गोर” टॅग असलेल्या बोर्डवरील पोस्ट दर्शवू नका",
"hide_adult_boards_tip": "“एडल्ट” टॅग असलेल्या बोर्डवरील पोस्ट दर्शवू नका",
"fit_expanded_images_to_screen": "विस्तृत प्रतिमा स्क्रीनवर फिट करा",
"fit_expanded_images_to_screen_tip": "विस्तृत प्रतिमांना ब्राउझरच्या रुंदी आणि उंचीवर मर्यादित करा",
"hide_avatars_tip": "युजर डिस्प्ले नावेच्या बरोबर अवतार दर्शवू नका",
"choose_file": "फाइल निवडा",
"uploading": "अपलोड करत आहे...",
"no_file_chosen": "कोणताही फाइल निवडलेली नाही",
"error": "त्रुटी",
"vote": "मत"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Verwijder portemonnee",
"loading_subplebbit": "Subplebbit laden",
"avatar_warning": "Je kunt niet met een avatar posten terwijl de anonieme modus aan staat. Je kunt het uitschakelen in de instellingen van je Plebbit-account.",
"last_bumped": "Laatste bump"
"last_bumped": "Laatste bump",
"threads_without_images_tip": "Toon geen berichten zonder afbeeldingen",
"hide_gore_boards_tip": "Toon geen berichten van borden met de tag \"gore\"",
"hide_adult_boards_tip": "Toon geen berichten van borden met de tag \"adult\"",
"fit_expanded_images_to_screen": "Pas uitgebreide afbeeldingen aan het scherm aan",
"fit_expanded_images_to_screen_tip": "Beperk uitgebreide afbeeldingen tot zowel de breedte als de hoogte van de browser",
"hide_avatars_tip": "Toon geen avatar naast de weergavenamen van gebruikers",
"choose_file": "Kies een bestand",
"uploading": "uploaden...",
"no_file_chosen": "Geen bestand gekozen",
"error": "Fout",
"vote": "stem"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Slett lommebok",
"loading_subplebbit": "Laster subplebbit",
"avatar_warning": "Du kan ikke poste med en avatar mens anonym modus er aktivert. Du kan slå den av i innstillingene for Plebbit-kontoen din.",
"last_bumped": "Siste bumpet"
"last_bumped": "Siste bumpet",
"threads_without_images_tip": "Vis ikke innlegg uten bilder",
"hide_gore_boards_tip": "Vis ikke innlegg fra tavler med \"gore\"-taggen",
"hide_adult_boards_tip": "Vis ikke innlegg fra tavler med \"adult\"-taggen",
"fit_expanded_images_to_screen": "Tilpass utvidede bilder til skjermen",
"fit_expanded_images_to_screen_tip": "Begrens utvidede bilder til både nettleserens bredde og høyde",
"hide_avatars_tip": "Vis ikke avatarer ved siden av brukernes visningsnavn",
"choose_file": "Velg fil",
"uploading": "laster opp...",
"no_file_chosen": "Ingen fil valgt",
"error": "Feil",
"vote": "stemme"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Usuń portfel",
"loading_subplebbit": "Ładowanie subplebbit",
"avatar_warning": "Nie możesz publikować z awatarem, gdy tryb anonimowy jest włączony. Możesz go wyłączyć w ustawieniach swojego konta Plebbit.",
"last_bumped": "Ostatni bump"
"last_bumped": "Ostatni bump",
"threads_without_images_tip": "Nie wyświetlaj postów bez obrazów",
"hide_gore_boards_tip": "Nie wyświetlaj postów z tablic z tagiem \"gore\"",
"hide_adult_boards_tip": "Nie wyświetlaj postów z tablic z tagiem \"adult\"",
"fit_expanded_images_to_screen": "Dopasuj rozszerzone obrazy do ekranu",
"fit_expanded_images_to_screen_tip": "Ogranicz rozszerzone obrazy do szerokości i wysokości przeglądarki",
"hide_avatars_tip": "Nie wyświetlaj avatarów obok nazw wyświetlających użytkowników",
"choose_file": "Wybierz plik",
"uploading": "ładowanie...",
"no_file_chosen": "Nie wybrano żadnego pliku",
"error": "Błąd",
"vote": "głos"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Excluir carteira",
"loading_subplebbit": "Carregando subplebbit",
"avatar_warning": "Você não pode postar com um avatar enquanto o modo anônimo estiver ativado. Você pode desativá-lo nas configurações da sua Conta Plebbit.",
"last_bumped": "Último bump"
"last_bumped": "Último bump",
"threads_without_images_tip": "Não exiba postagens sem imagens",
"hide_gore_boards_tip": "Não exiba postagens de quadros com a tag \"gore\"",
"hide_adult_boards_tip": "Não exiba postagens de quadros com a tag \"adult\"",
"fit_expanded_images_to_screen": "Ajustar imagens expandidas à tela",
"fit_expanded_images_to_screen_tip": "Limite imagens expandidas tanto à largura quanto à altura do navegador",
"hide_avatars_tip": "Não exiba avatares ao lado dos nomes de exibição dos usuários",
"choose_file": "Escolher arquivo",
"uploading": "carregando...",
"no_file_chosen": "Nenhum arquivo escolhido",
"error": "Erro",
"vote": "voto"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Șterge portofelul",
"loading_subplebbit": "Se încarcă subplebbit",
"avatar_warning": "Nu poți publica cu un avatar în timp ce modul anonim este activat. Poți să-l dezactivezi în setările contului tău Plebbit.",
"last_bumped": "Ultima creștere"
"last_bumped": "Ultima creștere",
"threads_without_images_tip": "Nu afișa postările fără imagini",
"hide_gore_boards_tip": "Nu afișa postări de la panouri cu eticheta \"gore\"",
"hide_adult_boards_tip": "Nu afișa postări de la panouri cu eticheta \"adult\"",
"fit_expanded_images_to_screen": "Se potrivesc imaginile extinse pe ecran",
"fit_expanded_images_to_screen_tip": "Limitați imaginile extinse atât la lățimea cât și la înălțimea browserului",
"hide_avatars_tip": "Nu afișa avatare lângă numele de afișare ale utilizatorilor",
"choose_file": "Alegeți fișierul",
"uploading": "încărcare...",
"no_file_chosen": "Niciun fișier ales",
"error": "Eroare",
"vote": "vot"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Удалить кошелек",
"loading_subplebbit": "Загрузка subplebbit",
"avatar_warning": "Вы не можете публиковать с аватаром, когда режим анонимности включен. Вы можете отключить его в настройках своей учетной записи Plebbit.",
"last_bumped": "Последний бамп"
"last_bumped": "Последний бамп",
"threads_without_images_tip": "Не показывать сообщения без изображений",
"hide_gore_boards_tip": "Не показывать сообщения с досок с тегом \"gore\"",
"hide_adult_boards_tip": "Не показывать сообщения с досок с тегом \"adult\"",
"fit_expanded_images_to_screen": "Подогнать расширенные изображения под экран",
"fit_expanded_images_to_screen_tip": "Ограничить расширенные изображения как по ширине, так и по высоте браузера",
"hide_avatars_tip": "Не показывать аватары рядом с именами пользователей",
"choose_file": "Выбрать файл",
"uploading": "загрузка...",
"no_file_chosen": "Файл не выбран",
"error": "Ошибка",
"vote": "голосовать"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Fshi portofolin",
"loading_subplebbit": "Po ngarkohet subplebbit",
"avatar_warning": "Nuk mund të postoni me një avatar ndërsa është aktivizuar moda anonime. Mund ta çaktivizoni në cilësimet e llogarisë tuaj Plebbit.",
"last_bumped": "Bumping i fundit"
"last_bumped": "Bumping i fundit",
"threads_without_images_tip": "Mos e tregoni postimet pa imazhe",
"hide_gore_boards_tip": "Mos e tregoni postimet nga bordet me etiketën \"gore\"",
"hide_adult_boards_tip": "Mos e tregoni postimet nga bordet me etiketën \"adult\"",
"fit_expanded_images_to_screen": "Përshtatni imazhet e zgjeruara në ekran",
"fit_expanded_images_to_screen_tip": "Kufizoni imazhet e zgjeruara si në gjerësi ashtu edhe në lartësi të shfletuesit",
"hide_avatars_tip": "Mos e tregoni avatarët pranë emrave të shfaqjes së përdoruesve",
"choose_file": "Zgjidhni skedarin",
"uploading": "duke ngarkuar...",
"no_file_chosen": "Nuk është zgjedhur asnjë skedar",
"error": "Gabim",
"vote": "votim"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Ta bort plånbok",
"loading_subplebbit": "Laddar subplebbit",
"avatar_warning": "Du kan inte posta med en avatar när anonym läge är aktiverat. Du kan stänga av det i inställningarna för ditt Plebbit-konto.",
"last_bumped": "Senaste bump"
"last_bumped": "Senaste bump",
"threads_without_images_tip": "Visa inte inlägg utan bilder",
"hide_gore_boards_tip": "Visa inte inlägg från tavlor med taggen \"gore\"",
"hide_adult_boards_tip": "Visa inte inlägg från tavlor med taggen \"adult\"",
"fit_expanded_images_to_screen": "Anpassa utvidgade bilder till skärmen",
"fit_expanded_images_to_screen_tip": "Begränsa utvidgade bilder till både webbläsarens bredd och höjd",
"hide_avatars_tip": "Visa inte avatarer bredvid användarnas visningsnamn",
"choose_file": "Välj fil",
"uploading": "laddar upp...",
"no_file_chosen": "Ingen fil vald",
"error": "Fel",
"vote": "rösta"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "వాలెట్ తొలగించండి",
"loading_subplebbit": "సబ్‌ప్లెబిట్‌లో లోడింగ్",
"avatar_warning": "మీరు అను మోడ్ ఆన్ ఉండగా అవతార్‌తో పోస్ట్ చేయలేరు. మీరు మీ Plebbit ఖాతా సెట్టింగ్స్‌లో దీన్ని ఆఫ్ చేయవచ్చు.",
"last_bumped": "చివరి బంప్"
"last_bumped": "చివరి బంప్",
"threads_without_images_tip": "చిత్రాలు లేని పోస్టులు ప్రదర్శించవద్దు",
"hide_gore_boards_tip": "“గోర్” ట్యాగ్ ఉన్న బోర్డుల నుండి పోస్టులు ప్రదర్శించవద్దు",
"hide_adult_boards_tip": "“ఎడల్ట్” ట్యాగ్ ఉన్న బోర్డుల నుండి పోస్టులు ప్రదర్శించవద్దు",
"fit_expanded_images_to_screen": "విస్తృత చిత్రాలను స్క్రీన్‌కు సరిపోల్చండి",
"fit_expanded_images_to_screen_tip": "విస్తృత చిత్రాలను బ్రౌజర్ వెడల్పు మరియు ఎత్తు రెండింటికీ పరిమితం చేయండి",
"hide_avatars_tip": "వాడుకరి ప్రదర్శన పేర్ల పక్కన అవతార్లు ప్రదర్శించవద్దు",
"choose_file": "ఫైల్ ఎంపిక చేసుకోండి",
"uploading": "అప్‌లోడ్ అవుతోంది...",
"no_file_chosen": "ఎటువంటి ఫైల్ ఎంపిక చేయబడలేదు",
"error": "దోషం",
"vote": "ఐదు"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "ลบกระเป๋าเงิน",
"loading_subplebbit": "กำลังโหลด subplebbit",
"avatar_warning": "คุณไม่สามารถโพสต์ด้วยอวาตาร์ในขณะที่โหมดอนาโนเป็นเปิดอยู่ คุณสามารถปิดได้ในการตั้งค่าบัญชี Plebbit ของคุณ",
"last_bumped": "เพิ่มล่าสุด"
"last_bumped": "เพิ่มล่าสุด",
"threads_without_images_tip": "ไม่แสดงโพสต์ที่ไม่มีรูปภาพ",
"hide_gore_boards_tip": "ไม่แสดงโพสต์จากกระดานที่มีแท็ก \"gore\"",
"hide_adult_boards_tip": "ไม่แสดงโพสต์จากกระดานที่มีแท็ก \"adult\"",
"fit_expanded_images_to_screen": "ปรับขนาดภาพที่ขยายให้พอดีกับหน้าจอ",
"fit_expanded_images_to_screen_tip": "จำกัดภาพที่ขยายให้พอดีกับทั้งความกว้างและความสูงของเบราว์เซอร์",
"hide_avatars_tip": "ไม่แสดงอวาตาร์ข้างชื่อผู้ใช้",
"choose_file": "เลือกไฟล์",
"uploading": "กำลังอัปโหลด...",
"no_file_chosen": "ไม่มีไฟล์ที่เลือก",
"error": "ข้อผิดพลาด",
"vote": "โหวต"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Cüzdanı Sil",
"loading_subplebbit": "Subplebbit Yükleniyor",
"avatar_warning": "Anonim mod açıken avatar ile paylaşım yapamazsınız. Bunu Plebbit Hesap ayarlarınızdan kapatabilirsiniz.",
"last_bumped": "Son bump"
"last_bumped": "Son bump",
"threads_without_images_tip": "Görüntü olmayan gönderileri gösterme",
"hide_gore_boards_tip": "\"gore\" etiketi olan panolardan gelen gönderileri gösterme",
"hide_adult_boards_tip": "\"adult\" etiketi olan panolardan gelen gönderileri gösterme",
"fit_expanded_images_to_screen": "Genişletilmiş resimleri ekrana sığdır",
"fit_expanded_images_to_screen_tip": "Genişletilmiş resimleri hem tarayıcı genişliğine hem de yüksekliğine sınırlayın",
"hide_avatars_tip": "Kullanıcı görünüm adlarının yanında avatarları gösterme",
"choose_file": "Dosya Seç",
"uploading": "yükleniyor...",
"no_file_chosen": "Hiçbir dosya seçilmedi",
"error": "Hata",
"vote": "oy"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Видалити гаманець",
"loading_subplebbit": "Завантаження subplebbit",
"avatar_warning": "Ви не можете публікувати з аватаром, коли увімкнено анонімний режим. Ви можете вимкнути його в налаштуваннях свого облікового запису Plebbit.",
"last_bumped": "Останній бамп"
"last_bumped": "Останній бамп",
"threads_without_images_tip": "Не показувати пости без зображень",
"hide_gore_boards_tip": "Не показувати пости з дошок з тегом \"gore\"",
"hide_adult_boards_tip": "Не показувати пости з дошок з тегом \"adult\"",
"fit_expanded_images_to_screen": "Підлаштувати розширені зображення під екран",
"fit_expanded_images_to_screen_tip": "Обмежити розширені зображення як за шириною, так і за висотою браузера",
"hide_avatars_tip": "Не показувати аватари поряд із іменами користувачів",
"choose_file": "Виберіть файл",
"uploading": "завантаження...",
"no_file_chosen": "Не вибрано жодного файлу",
"error": "Помилка",
"vote": "голос"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "والٹ حذف کریں",
"loading_subplebbit": "سب پلبیٹ لوڈ ہو رہا ہے",
"avatar_warning": "آپ اَنون موڈ آن ہونے پر اوتار کے ساتھ پوسٹ نہیں کر سکتے۔ آپ اسے اپنے Plebbit اکاؤنٹ کی ترتیبات میں بند کر سکتے ہیں۔",
"last_bumped": "آخری بمپر"
"last_bumped": "آخری بمپر",
"threads_without_images_tip": "بغیر تصویر کے پوسٹ نہ دکھائیں",
"hide_gore_boards_tip": "“گور” ٹیگ کے ساتھ بورڈز سے پوسٹ نہ دکھائیں",
"hide_adult_boards_tip": "“ایڈلٹ” ٹیگ کے ساتھ بورڈز سے پوسٹ نہ دکھائیں",
"fit_expanded_images_to_screen": "پھیلائی ہوئی تصاویر کو اسکرین پر فٹ کریں",
"fit_expanded_images_to_screen_tip": "پھیلائی ہوئی تصاویر کو براؤزر کی چوڑائی اور اونچائی دونوں تک محدود کریں",
"hide_avatars_tip": "صارف کے ڈسپلے ناموں کے ساتھ اوتار نہ دکھائیں",
"choose_file": "فائل منتخب کریں",
"uploading": "اپ لوڈ ہو رہا ہے...",
"no_file_chosen": "کوئی فائل منتخب نہیں کی گئی",
"error": "غلطی",
"vote": "ووٹ"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "Xóa ví",
"loading_subplebbit": "Đang tải subplebbit",
"avatar_warning": "Bạn không thể đăng với hình đại diện khi chế độ ẩn danh đang bật. Bạn có thể tắt nó trong cài đặt Tài khoản Plebbit của mình.",
"last_bumped": "Bump gần đây nhất"
"last_bumped": "Bump gần đây nhất",
"threads_without_images_tip": "Không hiển thị bài viết không có hình ảnh",
"hide_gore_boards_tip": "Không hiển thị bài viết từ các bảng có thẻ \"gore\"",
"hide_adult_boards_tip": "Không hiển thị bài viết từ các bảng có thẻ \"adult\"",
"fit_expanded_images_to_screen": "Phù hợp hình ảnh mở rộng với màn hình",
"fit_expanded_images_to_screen_tip": "Hạn chế hình ảnh mở rộng cả chiều rộng và chiều cao của trình duyệt",
"hide_avatars_tip": "Không hiển thị hình đại diện bên cạnh tên hiển thị của người dùng",
"choose_file": "Chọn tệp",
"uploading": "đang tải lên...",
"no_file_chosen": "Không có tệp nào được chọn",
"error": "Lỗi",
"vote": "bỏ phiếu"
}
+12 -1
View File
@@ -250,5 +250,16 @@
"delete_wallet": "删除钱包",
"loading_subplebbit": "加载 subplebbit",
"avatar_warning": "在匿名模式开启时,您无法使用头像进行发布。您可以在 Plebbit 账户设置中将其关闭。",
"last_bumped": "最后提升"
"last_bumped": "最后提升",
"threads_without_images_tip": "不显示没有图片的帖子",
"hide_gore_boards_tip": "不显示来自带有“gore”标签的板块的帖子",
"hide_adult_boards_tip": "不显示来自带有“adult”标签的板块的帖子",
"fit_expanded_images_to_screen": "适应扩展图像到屏幕",
"fit_expanded_images_to_screen_tip": "将扩展图像限制为浏览器的宽度和高度",
"hide_avatars_tip": "不显示用户显示名称旁边的头像",
"choose_file": "选择文件",
"uploading": "正在上传...",
"no_file_chosen": "未选择任何文件",
"error": "错误",
"vote": "投票"
}
+2 -2
View File
@@ -20,7 +20,7 @@ import PostForm from './components/post-form';
import SubplebbitStats from './components/subplebbit-stats';
import TopBar from './components/topbar';
const CheckRouteParams = () => {
const ValidateRouteParams = () => {
const { accountCommentIndex, timeFilterName } = useParams();
const { timeFilterNames, lastVisitTimeFilterName } = useTimeFilter();
const { accountComments } = useAccountComments();
@@ -125,7 +125,7 @@ const App = () => {
<Route path='/' element={<Home />} />
<Route path='/faq' element={<FAQ />} />
<Route path='*' element={<NotFound />} />
<Route element={<CheckRouteParams />}>
<Route element={<ValidateRouteParams />}>
<Route element={<BoardLayout />}>
<Route path='/p/:subplebbitAddress' element={<Board />} />
<Route path='/p/:subplebbitAddress/settings' element={<Board />} />
+1 -1
View File
@@ -44,7 +44,7 @@ const BoardHeader = () => {
</div>
)}
<div className={styles.boardTitle}>
{title || `p/${shortAddress || subplebbitAddress}`}
{title || (shortAddress ? (shortAddress.endsWith('.eth') || shortAddress.endsWith('.sol') ? shortAddress.slice(0, -4) : shortAddress) : subplebbitAddress)}
{(isOffline || isOnlineStatusLoading) && !isInAllView && !isInSubscriptionsView && (
<span className={`${styles.offlineIcon} ${offlineIconClass}`} title={offlineTitle} />
)}
@@ -149,4 +149,15 @@
.content {
line-height: 0; /* Ensure no extra space due to line-height */
}
}
.fitToScreen {
max-width: 100vw;
max-height: 100vh;
}
.fitToScreen img,
.fitToScreen video {
max-width: 100%;
max-height: 100vh;
}
@@ -1,11 +1,12 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Comment } from '@plebbit/plebbit-react-hooks';
import styles from './comment-media.module.css';
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
import { getHostname } from '../../lib/utils/url-utils';
import useExpandedMediaStore from '../../stores/use-expanded-media-store';
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
import useIsMobile from '../../hooks/use-is-mobile';
import styles from './comment-media.module.css';
import Embed, { canEmbed } from '../embed';
interface MediaProps {
@@ -108,7 +109,10 @@ const Media = ({ commentMediaInfo, isReply, setShowThumbnail }: MediaProps) => {
const { t } = useTranslation();
const { thumbnail, type, url } = commentMediaInfo || {};
const isMobile = useIsMobile();
const mediaClass = isMobile ? styles.mediaMobile : isReply ? styles.mediaDesktopReply : styles.mediaDesktopOp;
const { fitExpandedImagesToScreen } = useExpandedMediaStore();
const mediaClass = `${isMobile ? styles.mediaMobile : isReply ? styles.mediaDesktopReply : styles.mediaDesktopOp} ${
fitExpandedImagesToScreen ? styles.fitToScreen : ''
}`;
const mediaDimensions = getMediaDimensions(commentMediaInfo);
return (
+4 -4
View File
@@ -76,7 +76,7 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
return (
<div className={styles.postInfo}>
{!isHidden && <EditMenu post={post} />}
{isHidden ? parentCid && <span className={styles.hiddenReplyEditMenuSpacer} /> : <EditMenu post={post} />}
<span className={(hidden || ((removed || deleted) && !reason)) && parentCid ? styles.postDesktopHidden : ''}>
{title &&
(title.length <= 75 ? (
@@ -403,7 +403,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
<div className={styles.replyDesktop}>
<div className={styles.sideArrows}>{'>>'}</div>
<div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight}`} data-cid={cid} data-author-address={author?.shortAddress} data-post-cid={postCid}>
<PostInfo openReplyModal={openReplyModal} post={post} postReplyCount={postReplyCount} roles={roles} />
<PostInfo openReplyModal={openReplyModal} post={post} postReplyCount={postReplyCount} roles={roles} isHidden={hidden} />
{link && !hidden && !(deleted || removed) && isValidURL(link) && <PostMedia post={post} />}
{!hidden && (!(removed || deleted) || ((removed || deleted) && reason)) && <PostMessage post={post} />}
</div>
@@ -413,7 +413,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies = true }: PostProps) => {
const { t } = useTranslation();
const { author, cid, content, deleted, link, parentCid, pinned, postCid, removed, state, subplebbitAddress } = post || {};
const { author, cid, content, deleted, link, pinned, postCid, removed, state, subplebbitAddress } = post || {};
const { isDescription, isRules } = post || {}; // custom properties, not from api
const params = useParams();
const location = useLocation();
@@ -464,7 +464,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
{link && !isHidden && !(deleted || removed) && isValidURL(link) && <PostMedia post={post} />}
<PostInfo isHidden={hidden} openReplyModal={openReplyModal} post={post} postReplyCount={replyCount} roles={roles} />
{!isHidden && !content && !(deleted || removed) && <div className={styles.spacer} />}
{!(isHidden && parentCid) && <PostMessage post={post} />}
{!isHidden && <PostMessage post={post} />}
</div>
{!isHidden && !isDescription && !isRules && !isInPendingPostView && (replyCount > 5 || (pinned && repliesCount > 0)) && !isInPostPageView && (
<span className={styles.summary}>
+17 -2
View File
@@ -101,6 +101,7 @@
margin: 0 3px;
vertical-align: middle;
transform: translateY(-2px);
cursor: pointer;
}
.spoilerButton td {
@@ -113,6 +114,10 @@
font-weight: normal;
}
.spoilerButton label {
cursor: pointer;
}
@media (max-width: 640px) {
.postFormDesktop {
display: none;
@@ -125,13 +130,13 @@
.postFormTable td input {
height: 20px;
}
.postFormTable td textarea {
height: 80px;
}
.postFormTable button {
padding: 4px 8px;
padding: 3px 6px;
}
}
@@ -139,4 +144,14 @@
.postFormMobile {
display: none;
}
}
.uploadButton button {
position: relative;
margin: 0;
margin-right: 5px;
}
.uploadButton span {
font-weight: normal;
}
+51 -1
View File
@@ -14,6 +14,10 @@ import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
import useAnonMode from '../../hooks/use-anon-mode';
import usePublishPostStore from '../../stores/use-publish-post-store';
import FileUploader from '../../plugins/file-uploader';
import { Capacitor } from '@capacitor/core';
const isAndroid = Capacitor.getPlatform() === 'android';
export const LinkTypePreviewer = ({ link }: { link: string }) => {
const { t } = useTranslation();
@@ -214,6 +218,36 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
}
}, [anonMode, getAnonAddressForPost, getAnonAddressForReply, isInPostView]);
// on android, auto upload file to image hosting sites with open api
const [isUploading, setIsUploading] = useState(false);
const [uploadedFileName, setUploadedFileName] = useState<string | null>(null);
const handleUpload = async () => {
try {
setIsUploading(true);
const result = await FileUploader.pickAndUploadMedia();
console.log('Upload result:', result);
if (result.url) {
setUrl(result.url);
if (urlRef.current) {
urlRef.current.value = result.url;
}
isInPostView ? setPublishReplyOptions({ link: result.url || undefined }) : setPublishPostStore({ link: result.url || undefined });
if (result.fileName) {
setUploadedFileName(result.fileName);
}
}
} catch (error) {
console.error('Upload failed:', error);
if (error instanceof Error && error.message !== 'File selection cancelled') {
alert(`${t('upload_failed')}: ${error.message}`);
} else if (typeof error === 'string' && error !== 'File selection cancelled') {
alert(`${t('upload_failed')}: ${error}`);
}
} finally {
setIsUploading(false);
}
};
return (
<table className={styles.postFormTable}>
<tbody>
@@ -233,7 +267,11 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
}
}}
/>
{isInPostView && <button onClick={onPublishReply}>{t('post')}</button>}
{isInPostView && (
<button onClick={onPublishReply} disabled={isUploading}>
{t('post')}
</button>
)}
</td>
</tr>
{!isInPostView && (
@@ -266,6 +304,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
autoComplete='off'
spellCheck='false'
ref={urlRef}
disabled={isUploading}
onChange={(e) => {
setUrl(e.target.value);
isInPostView ? setPublishReplyOptions({ link: e.target.value || undefined }) : setPublishPostStore({ link: e.target.value || undefined });
@@ -274,6 +313,17 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
<span className={styles.linkType}> {url && <LinkTypePreviewer link={url} />}</span>
</td>
</tr>
{isAndroid && (
<tr className={styles.uploadButton}>
<td>{t('file')}</td>
<td>
<button onClick={handleUpload} disabled={isUploading}>
{isUploading ? t('uploading') : t('choose_file')}
</button>
<span>{uploadedFileName ? uploadedFileName : t('no_file_chosen')}</span>
</td>
</tr>
)}
<tr className={styles.spoilerButton}>
<td>{t('options')}</td>
<td>
@@ -64,6 +64,12 @@
vertical-align: top;
}
.footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.footer button {
text-transform: capitalize;
float: right;
@@ -80,9 +86,37 @@
padding-top: 2px;
}
.spoilerButton label, .spoilerButton input[type="checkbox"] {
cursor: pointer;
}
.publishButton {
width: 75px;
filter: var(--filter80)
filter: var(--filter80);
}
.uploadButton {
float: left;
margin-right: 5px;
white-space: nowrap;
}
.uploadButton button {
white-space: nowrap;
}
.uploadFileName {
display: inline-block;
width: calc(100% - 75px);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.uploadContainer {
display: inline-flex;
align-items: center;
width: 130px;
}
.offlineBoard {
@@ -103,4 +137,15 @@
.title {
cursor: default;
}
}
.error {
width: 294px;
font-family: monospace;
background-color: #E62020;
font-size: 12px;
color: white;
padding: 3px 5px;
margin-top: 1px;
text-shadow: 0 1px rgba(0, 0, 0, 0.20);
}
+58 -4
View File
@@ -15,6 +15,10 @@ import styles from './reply-modal.module.css';
import { LinkTypePreviewer } from '../post-form';
import _ from 'lodash';
import useAnonMode from '../../hooks/use-anon-mode';
import FileUploader from '../../plugins/file-uploader';
import { Capacitor } from '@capacitor/core';
const isAndroid = Capacitor.getPlatform() === 'android';
interface ReplyModalProps {
closeModal: () => void;
@@ -68,20 +72,23 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
}
}, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, anonMode, displayName]);
const [error, setError] = useState<string | null>(null);
const onPublishReply = () => {
const currentContent = textRef.current?.value.slice(contentPrefix.length).trim() || '';
const currentUrl = urlRef.current?.value.trim() || '';
if (!currentContent && !currentUrl) {
alert(t('empty_comment_alert'));
setError(t('empty_comment_alert'));
return;
}
if (currentUrl && !isValidURL(currentUrl)) {
alert(t('invalid_url_alert'));
setError(t('invalid_url_alert'));
return;
}
setError(null);
publishReply();
};
@@ -167,6 +174,36 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
}
};
// on android, auto upload file to image hosting sites with open api
const [isUploading, setIsUploading] = useState(false);
const [uploadedFileName, setUploadedFileName] = useState<string | null>(null);
const handleUpload = async () => {
try {
setIsUploading(true);
const result = await FileUploader.pickAndUploadMedia();
console.log('Upload result:', result);
if (result.url) {
setUrl(result.url);
if (urlRef.current) {
urlRef.current.value = result.url;
}
setPublishReplyOptions({ link: result.url || undefined });
if (result.fileName) {
setUploadedFileName(result.fileName);
}
}
} catch (error) {
console.error('Upload failed, ', error);
if (error instanceof Error && error.message !== 'File selection cancelled') {
setError(`${t('upload_failed')}, ${error.message}`);
} else if (typeof error === 'string' && error !== 'File selection cancelled') {
setError(`${t('upload_failed')}, ${error}`);
}
} finally {
setIsUploading(false);
}
};
const modalContent = (
<div className={styles.container} ref={nodeRef}>
<div className={`replyModalHandle ${styles.title}`}>
@@ -218,11 +255,23 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
{!(isInAllView || isInSubscriptionsView) && offlineAlert}
<div className={styles.offlineAlert}></div>
<div className={styles.footer}>
{url && (
{url && !isAndroid && (
<>
{t('link_type')}: <LinkTypePreviewer link={url} />{' '}
{t('link_type')}: <LinkTypePreviewer link={url} />
</>
)}
{isAndroid && (
<span className={styles.uploadContainer}>
<span className={styles.uploadButton}>
<button onClick={handleUpload} disabled={isUploading}>
{isUploading ? t('uploading') : t('choose_file')}
</button>
</span>
<span className={styles.uploadFileName} title={uploadedFileName ? uploadedFileName : t('no_file_chosen')}>
{uploadedFileName ? uploadedFileName : t('no_file_chosen')}
</span>
</span>
)}
<span className={styles.spoilerButton}>
[
<label>
@@ -235,6 +284,11 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
{t('post')}
</button>
</div>
{error && (
<div className={styles.error}>
{t('error')}: {error}
</div>
)}
</div>
</div>
);
@@ -27,4 +27,10 @@
.setting input[type="checkbox"] {
margin-right: 2px;
}
}
.settingTip {
font-size: 0.85em;
margin: 2px 0 5px 0;
padding-left: 19px;
}
@@ -7,6 +7,7 @@ import styles from './interface-settings.module.css';
import _ from 'lodash';
import useInterfaceSettingsStore from '../../../stores/use-interface-settings-store';
import useCatalogFiltersStore from '../../../stores/use-catalog-filters-store';
import useExpandedMediaStore from '../../../stores/use-expanded-media-store';
const commitRef = process.env.REACT_APP_COMMIT_REF;
const isElectron = window.isElectron === true;
@@ -114,6 +115,7 @@ const InterfaceSettings = () => {
const { hideAvatars, setHideAvatars } = useAvatarVisibilityStore();
const { hideGoreBoards, setHideGoreBoards, hideAdultBoards, setHideAdultBoards, hideThreadsWithoutImages, setHideThreadsWithoutImages } = useInterfaceSettingsStore();
const { setShowTextOnlyThreads } = useCatalogFiltersStore();
const { fitExpandedImagesToScreen, setFitExpandedImagesToScreen } = useExpandedMediaStore();
const handleHideAvatarsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setHideAvatars(e.target.checked);
@@ -141,21 +143,6 @@ const InterfaceSettings = () => {
<div className={styles.setting}>
{_.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 className={styles.setting}>
<label>
<input type='checkbox' checked={hideGoreBoards} onChange={(e) => setHideGoreBoards(e.target.checked)} /> {_.capitalize(t('hide_gore_boards'))}
</label>
</div>
<div className={styles.setting}>
<label>
<input type='checkbox' checked={hideAdultBoards} onChange={(e) => setHideAdultBoards(e.target.checked)} /> {_.capitalize(t('hide_adult_boards'))}
</label>
</div>
<div className={styles.setting}>
<label>
<input
@@ -168,6 +155,32 @@ const InterfaceSettings = () => {
/>
{_.capitalize(t('hide_threads_without_images'))}
</label>
<div className={styles.settingTip}>{_.capitalize(t('threads_without_images_tip'))}</div>
</div>
<div className={styles.setting}>
<label>
<input type='checkbox' checked={hideGoreBoards} onChange={(e) => setHideGoreBoards(e.target.checked)} /> {_.capitalize(t('hide_gore_boards'))}
</label>
<div className={styles.settingTip}>{_.capitalize(t('hide_gore_boards_tip'))}</div>
</div>
<div className={styles.setting}>
<label>
<input type='checkbox' checked={hideAdultBoards} onChange={(e) => setHideAdultBoards(e.target.checked)} /> {_.capitalize(t('hide_adult_boards'))}
</label>
<div className={styles.settingTip}>{_.capitalize(t('hide_adult_boards_tip'))}</div>
</div>
<div className={styles.setting}>
<label>
<input type='checkbox' checked={fitExpandedImagesToScreen} onChange={(e) => setFitExpandedImagesToScreen(e.target.checked)} />
{_.capitalize(t('fit_expanded_images_to_screen'))}
</label>
<div className={styles.settingTip}>{_.capitalize(t('fit_expanded_images_to_screen_tip'))}</div>
</div>
<div className={styles.setting}>
<label>
<input type='checkbox' checked={hideAvatars} onChange={handleHideAvatarsChange} /> {_.capitalize(t('hide_avatars'))}
</label>
<div className={styles.settingTip}>{_.capitalize(t('hide_avatars_tip'))}</div>
</div>
</div>
);
+1
View File
@@ -32,6 +32,7 @@
}
.disabledButton {
text-transform: capitalize;
cursor: not-allowed !important;
}
+2 -2
View File
@@ -96,7 +96,7 @@ const TopBarDesktop = () => {
e.preventDefault();
}}
>
Create
{t('create')}
</Link>
] [
<Link
@@ -106,7 +106,7 @@ const TopBarDesktop = () => {
e.preventDefault();
}}
>
Vote
{t('vote')}
</Link>
]
</span>
+5 -5
View File
@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { useAccount, usePublishComment } from '@plebbit/plebbit-react-hooks';
import { Comment, useAccount, usePublishComment } from '@plebbit/plebbit-react-hooks';
import useAnonMode from './use-anon-mode';
import usePublishReplyStore, { SetReplyStoreData } from '../stores/use-publish-reply-store';
import usePublishReplyStore from '../stores/use-publish-reply-store';
const usePublishReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: string }) => {
const parentCid = cid;
@@ -22,8 +22,8 @@ const usePublishReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAd
const resetReplyStore = usePublishReplyStore((state) => state.resetReplyStore);
const setPublishReplyOptions = useCallback(
(options: Partial<SetReplyStoreData>) => {
const newOptions: Partial<SetReplyStoreData> = {
(options: Comment) => {
const newOptions: Comment = {
subplebbitAddress,
parentCid,
content: options.content === '' ? undefined : options.content ?? content,
@@ -51,7 +51,7 @@ const usePublishReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAd
};
}
setReplyStore(newOptions as SetReplyStoreData);
setReplyStore(newOptions);
},
[subplebbitAddress, parentCid, author, signer, content, link, spoiler, setReplyStore, anonMode, account],
);
+9
View File
@@ -0,0 +1,9 @@
import { registerPlugin } from '@capacitor/core';
export interface FileUploaderPlugin {
pickAndUploadMedia(): Promise<{ url: string; fileName: string }>;
}
const FileUploader = registerPlugin<FileUploaderPlugin>('FileUploader');
export default FileUploader;
+21
View File
@@ -0,0 +1,21 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface ExpandedMediaState {
fitExpandedImagesToScreen: boolean;
setFitExpandedImagesToScreen: (fit: boolean) => void;
}
const useExpandedMediaStore = create<ExpandedMediaState>()(
persist(
(set) => ({
fitExpandedImagesToScreen: false,
setFitExpandedImagesToScreen: (fit) => set({ fitExpandedImagesToScreen: fit }),
}),
{
name: 'expanded-media-store',
},
),
);
export default useExpandedMediaStore;
+4 -14
View File
@@ -3,17 +3,6 @@ import { create } from 'zustand';
import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils';
import useChallengesStore from './use-challenges-store';
export type SetReplyStoreData = {
subplebbitAddress: string;
parentCid: string;
author?: any;
displayName?: string;
content: string;
link?: string;
signer?: any;
spoiler: boolean;
};
type ReplyState = {
author: { [parentCid: string]: any | undefined };
displayName: { [parentCid: string]: string | undefined };
@@ -22,7 +11,7 @@ type ReplyState = {
signer: { [parentCid: string]: any | undefined };
spoiler: { [parentCid: string]: boolean | undefined };
publishCommentOptions: { [parentCid: string]: PublishCommentOptions | undefined };
setReplyStore: (data: SetReplyStoreData) => void;
setReplyStore: (comment: Comment) => void;
resetReplyStore: (parentCid: string) => void;
};
@@ -37,14 +26,15 @@ const usePublishReplyStore = create<ReplyState>((set) => ({
spoiler: {},
publishCommentOptions: {},
setReplyStore: (data: SetReplyStoreData) =>
setReplyStore: (comment: Comment) =>
set((state) => {
const { subplebbitAddress, parentCid, author, displayName, content, link, signer, spoiler } = data;
const { subplebbitAddress, parentCid, author, displayName, content, link, signer, spoiler } = comment;
const updatedAuthor = displayName ? { ...author, displayName } : author;
const publishCommentOptions: PublishCommentOptions = {
subplebbitAddress,
parentCid,
postCid: comment?.postCid || parentCid,
content,
link,
spoiler,
+4
View File
@@ -1,3 +1,7 @@
.content {
overflow: hidden;
}
.footer {
color: var(--post-mobile-abbr-text-color);
padding: 15px 0 10px 5px;
+54 -65
View File
@@ -121,27 +121,6 @@ const Board = () => {
const { blocked, unblock } = useBlock({ address: subplebbitAddress });
const loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading');
const loadingString = (
<div className={styles.stateString}>
{state === 'failed' ? (
<span className='red'>{state}</span>
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
t('not_subscribed_to_any_board')
) : blocked ? (
'you have blocked this board'
) : !hasMore && feed.length === 0 ? (
t('no_posts')
) : (
hasMore && <LoadingEllipsis string={loadingStateString} />
)}
{error && (
<div className='red'>
<br />
{error.message}
</div>
)}
</div>
);
const handleNewerPostsButtonClick = () => {
window.scrollTo({ top: 0, left: 0 });
@@ -219,13 +198,46 @@ const Board = () => {
</div>
))
)}
<div className={styles.stateString}>
<LoadingEllipsis string={loadingStateString} />
</div>
</>
);
}
return <div className={styles.footer}>{footerContent}</div>;
return (
<div className={styles.footer}>
{footerContent}
<div>
{state === 'failed' ? (
<span className='red'>{state}</span>
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
t('not_subscribed_to_any_board')
) : blocked ? (
'you have blocked this board'
) : (
hasMore && <LoadingEllipsis string={loadingStateString} />
)}
{error && (
<div className='red'>
<br />
{error.message}
</div>
)}
{blocked && (
<>
&nbsp;&nbsp;[
<span
className={styles.button}
onClick={() => {
unblock();
reset();
}}
>
Unblock
</span>
]
</>
)}
</div>
</div>
);
};
// save the last Virtuoso state to restore it when navigating back
@@ -273,47 +285,24 @@ const Board = () => {
title={title}
/>
)}
{feed.length !== 0 ? (
<>
{rules && !description && rules.length > 0 && <SubplebbitRules subplebbitAddress={subplebbitAddress} createdAt={createdAt} rules={rules} />}
<Virtuoso
increaseViewportBy={{ bottom: 1200, top: 1200 }}
totalCount={combinedFeed.length}
data={combinedFeed}
itemContent={(index, post) => {
const { deleted, locked, removed } = post || {};
const isThreadClosed = deleted || locked || removed;
{rules && !description && rules.length > 0 && <SubplebbitRules subplebbitAddress={subplebbitAddress} createdAt={createdAt} rules={rules} />}
<Virtuoso
increaseViewportBy={{ bottom: 1200, top: 1200 }}
totalCount={combinedFeed.length}
data={combinedFeed}
itemContent={(index, post) => {
const { deleted, locked, removed } = post || {};
const isThreadClosed = deleted || locked || removed;
return <Post index={index} post={post} openReplyModal={isThreadClosed ? () => alert(t('thread_closed_alert')) : openReplyModal} />;
}}
useWindowScroll={true}
components={{ Footer }}
endReached={loadMore}
ref={virtuosoRef}
restoreStateFrom={lastVirtuosoState}
initialScrollTop={lastVirtuosoState?.scrollTop}
/>
</>
) : (
<div className={styles.footer}>
{loadingString}
{blocked && (
<>
&nbsp;&nbsp;[
<span
className={styles.button}
onClick={() => {
unblock();
reset();
}}
>
Unblock
</span>
]
</>
)}
</div>
)}
return <Post index={index} post={post} openReplyModal={isThreadClosed ? () => alert(t('thread_closed_alert')) : openReplyModal} />;
}}
useWindowScroll={true}
components={{ Footer }}
endReached={loadMore}
ref={virtuosoRef}
restoreStateFrom={lastVirtuosoState}
initialScrollTop={lastVirtuosoState?.scrollTop}
/>
</div>
);
};
+6 -1
View File
@@ -581,4 +581,9 @@
.replyMobile {
display: none;
}
}
}
.hiddenReplyEditMenuSpacer {
width: 6px;
display: inline-block;
}