Merge pull request #391 from plebbit/development

Development
This commit is contained in:
Tom (plebeius.eth)
2024-06-08 17:25:39 +02:00
committed by GitHub
62 changed files with 1011 additions and 167 deletions
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "اغلق الموضوع", "close_thread": "اغلق الموضوع",
"view_spoiler": "عرض الحاضر", "view_spoiler": "عرض الحاضر",
"filter": "تصفية", "filter": "تصفية",
"edit": "تحرير" "edit": "تحرير",
"time_1_minute_ago": "منذ دقيقة واحدة",
"time_x_minutes_ago": "منذ {{count}} دقائق",
"time_1_hour_ago": "منذ ساعة واحدة",
"time_x_hours_ago": "منذ {{count}} ساعات",
"time_1_day_ago": "منذ يوم واحد",
"time_x_days_ago": "منذ {{count}} أيام",
"time_1_month_ago": "منذ شهر واحد",
"time_x_months_ago": "منذ {{count}} شهور",
"time_1_year_ago": "منذ عام واحد",
"time_x_years_ago": "منذ {{count}} سنوات",
"open": "فتح"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "থ্রেড বন্ধ করুন", "close_thread": "থ্রেড বন্ধ করুন",
"view_spoiler": "স্পোয়ালার দেখুন", "view_spoiler": "স্পোয়ালার দেখুন",
"filter": "ফিল্টার", "filter": "ফিল্টার",
"edit": "সম্পাদনা" "edit": "সম্পাদনা",
"time_1_minute_ago": "১ মিনিট আগে",
"time_x_minutes_ago": "{{count}} মিনিট আগে",
"time_1_hour_ago": "১ ঘণ্টা আগে",
"time_x_hours_ago": "{{count}} ঘণ্টা আগে",
"time_1_day_ago": "১ দিন আগে",
"time_x_days_ago": "{{count}} দিন আগে",
"time_1_month_ago": "১ মাস আগে",
"time_x_months_ago": "{{count}} মাস আগে",
"time_1_year_ago": "১ বছর আগে",
"time_x_years_ago": "{{count}} বছর আগে",
"open": "খুলুন"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "uzavřít vlákno", "close_thread": "uzavřít vlákno",
"view_spoiler": "zobrazit spoiler", "view_spoiler": "zobrazit spoiler",
"filter": "filtr", "filter": "filtr",
"edit": "upravit" "edit": "upravit",
"time_1_minute_ago": "Před 1 minutou",
"time_x_minutes_ago": "Před {{count}} minutami",
"time_1_hour_ago": "Před 1 hodinou",
"time_x_hours_ago": "Před {{count}} hodinami",
"time_1_day_ago": "Před 1 dnem",
"time_x_days_ago": "Před {{count}} dny",
"time_1_month_ago": "Před 1 měsícem",
"time_x_months_ago": "Před {{count}} měsíci",
"time_1_year_ago": "Před 1 rokem",
"time_x_years_ago": "Před {{count}} roky",
"open": "otevřít"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "luk tråd", "close_thread": "luk tråd",
"view_spoiler": "vis spoiler", "view_spoiler": "vis spoiler",
"filter": "filtrér", "filter": "filtrér",
"edit": "rediger" "edit": "rediger",
"time_1_minute_ago": "1 minut siden",
"time_x_minutes_ago": "{{count}} minutter siden",
"time_1_hour_ago": "1 time siden",
"time_x_hours_ago": "{{count}} timer siden",
"time_1_day_ago": "1 dag siden",
"time_x_days_ago": "{{count}} dage siden",
"time_1_month_ago": "1 måned siden",
"time_x_months_ago": "{{count}} måneder siden",
"time_1_year_ago": "1 år siden",
"time_x_years_ago": "{{count}} år siden",
"open": "åben"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "Thread schließen", "close_thread": "Thread schließen",
"view_spoiler": "Spoiler anzeigen", "view_spoiler": "Spoiler anzeigen",
"filter": "filtern", "filter": "filtern",
"edit": "bearbeiten" "edit": "bearbeiten",
"time_1_minute_ago": "vor 1 Minute",
"time_x_minutes_ago": "vor {{count}} Minuten",
"time_1_hour_ago": "vor 1 Stunde",
"time_x_hours_ago": "vor {{count}} Stunden",
"time_1_day_ago": "vor 1 Tag",
"time_x_days_ago": "vor {{count}} Tagen",
"time_1_month_ago": "vor 1 Monat",
"time_x_months_ago": "vor {{count}} Monaten",
"time_1_year_ago": "vor 1 Jahr",
"time_x_years_ago": "vor {{count}} Jahren",
"open": "öffnen"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "κλείσιμο νήματος", "close_thread": "κλείσιμο νήματος",
"view_spoiler": "προβολή spoiler", "view_spoiler": "προβολή spoiler",
"filter": "φίλτρο", "filter": "φίλτρο",
"edit": "επεξεργασία" "edit": "επεξεργασία",
"time_1_minute_ago": "Πριν από 1 λεπτό",
"time_x_minutes_ago": "Πριν από {{count}} λεπτά",
"time_1_hour_ago": "Πριν από 1 ώρα",
"time_x_hours_ago": "Πριν από {{count}} ώρες",
"time_1_day_ago": "Πριν από 1 ημέρα",
"time_x_days_ago": "Πριν από {{count}} ημέρες",
"time_1_month_ago": "Πριν από 1 μήνα",
"time_x_months_ago": "Πριν από {{count}} μήνες",
"time_1_year_ago": "Πριν από 1 έτος",
"time_x_years_ago": "Πριν από {{count}} έτη",
"open": "ανοικτό"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "close thread", "close_thread": "close thread",
"view_spoiler": "view spoiler", "view_spoiler": "view spoiler",
"filter": "filter", "filter": "filter",
"edit": "edit" "edit": "edit",
"time_1_minute_ago": "1 minute ago",
"time_x_minutes_ago": "{{count}} minutes ago",
"time_1_hour_ago": "1 hour ago",
"time_x_hours_ago": "{{count}} hours ago",
"time_1_day_ago": "1 day ago",
"time_x_days_ago": "{{count}} days ago",
"time_1_month_ago": "1 month ago",
"time_x_months_ago": "{{count}} months ago",
"time_1_year_ago": "1 year ago",
"time_x_years_ago": "{{count}} years ago",
"open": "open"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "cerrar hilo", "close_thread": "cerrar hilo",
"view_spoiler": "ver spoiler", "view_spoiler": "ver spoiler",
"filter": "filtrar", "filter": "filtrar",
"edit": "editar" "edit": "editar",
"time_1_minute_ago": "hace 1 minuto",
"time_x_minutes_ago": "hace {{count}} minutos",
"time_1_hour_ago": "hace 1 hora",
"time_x_hours_ago": "hace {{count}} horas",
"time_1_day_ago": "hace 1 día",
"time_x_days_ago": "hace {{count}} días",
"time_1_month_ago": "hace 1 mes",
"time_x_months_ago": "hace {{count}} meses",
"time_1_year_ago": "hace 1 año",
"time_x_years_ago": "hace {{count}} años",
"open": "abrir"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "بستن موضوع", "close_thread": "بستن موضوع",
"view_spoiler": "نمایش اسپویلر", "view_spoiler": "نمایش اسپویلر",
"filter": "فیلتر", "filter": "فیلتر",
"edit": "ویرایش" "edit": "ویرایش",
"time_1_minute_ago": "1 دقیقه پیش",
"time_x_minutes_ago": "{{count}} دقیقه پیش",
"time_1_hour_ago": "1 ساعت پیش",
"time_x_hours_ago": "{{count}} ساعت پیش",
"time_1_day_ago": "1 روز پیش",
"time_x_days_ago": "{{count}} روز پیش",
"time_1_month_ago": "1 ماه پیش",
"time_x_months_ago": "{{count}} ماه پیش",
"time_1_year_ago": "1 سال پیش",
"time_x_years_ago": "{{count}} سال پیش",
"open": "باز کردن"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "sulje keskustelu", "close_thread": "sulje keskustelu",
"view_spoiler": "näytä spoiler", "view_spoiler": "näytä spoiler",
"filter": "suodatin", "filter": "suodatin",
"edit": "muokkaa" "edit": "muokkaa",
"time_1_minute_ago": "1 minuutti sitten",
"time_x_minutes_ago": "{{count}} minuuttia sitten",
"time_1_hour_ago": "1 tunti sitten",
"time_x_hours_ago": "{{count}} tuntia sitten",
"time_1_day_ago": "1 päivä sitten",
"time_x_days_ago": "{{count}} päivää sitten",
"time_1_month_ago": "1 kuukausi sitten",
"time_x_months_ago": "{{count}} kuukautta sitten",
"time_1_year_ago": "1 vuosi sitten",
"time_x_years_ago": "{{count}} vuotta sitten",
"open": "avata"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "isara ang thread", "close_thread": "isara ang thread",
"view_spoiler": "tingnan ang spoiler", "view_spoiler": "tingnan ang spoiler",
"filter": "salain", "filter": "salain",
"edit": "i-edit" "edit": "i-edit",
"time_1_minute_ago": "1 minuto ang nakalipas",
"time_x_minutes_ago": "{{count}} minuto ang nakalipas",
"time_1_hour_ago": "1 oras ang nakalipas",
"time_x_hours_ago": "{{count}} oras ang nakalipas",
"time_1_day_ago": "1 araw ang nakalipas",
"time_x_days_ago": "{{count}} araw ang nakalipas",
"time_1_month_ago": "1 buwan ang nakalipas",
"time_x_months_ago": "{{count}} buwan ang nakalipas",
"time_1_year_ago": "1 taon ang nakalipas",
"time_x_years_ago": "{{count}} taon ang nakalipas",
"open": "buksan"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "fermer le fil", "close_thread": "fermer le fil",
"view_spoiler": "voir le spoiler", "view_spoiler": "voir le spoiler",
"filter": "filtre", "filter": "filtre",
"edit": "modifier" "edit": "modifier",
"time_1_minute_ago": "il y a 1 minute",
"time_x_minutes_ago": "il y a {{count}} minutes",
"time_1_hour_ago": "il y a 1 heure",
"time_x_hours_ago": "il y a {{count}} heures",
"time_1_day_ago": "il y a 1 jour",
"time_x_days_ago": "il y a {{count}} jours",
"time_1_month_ago": "il y a 1 mois",
"time_x_months_ago": "il y a {{count}} mois",
"time_1_year_ago": "il y a 1 an",
"time_x_years_ago": "il y a {{count}} ans",
"open": "ouvrir"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "סגור את הנושא", "close_thread": "סגור את הנושא",
"view_spoiler": "הצג ספוילר", "view_spoiler": "הצג ספוילר",
"filter": "סנן", "filter": "סנן",
"edit": "ערוך" "edit": "ערוך",
"time_1_minute_ago": "לפני דקה",
"time_x_minutes_ago": "לפני {{count}} דקות",
"time_1_hour_ago": "לפני שעה",
"time_x_hours_ago": "לפני {{count}} שעות",
"time_1_day_ago": "לפני יום",
"time_x_days_ago": "לפני {{count}} ימים",
"time_1_month_ago": "לפני חודש",
"time_x_months_ago": "לפני {{count}} חודשים",
"time_1_year_ago": "לפני שנה",
"time_x_years_ago": "לפני {{count}} שנים",
"open": "לפתוח"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "थ्रेड बंद करें", "close_thread": "थ्रेड बंद करें",
"view_spoiler": "स्पॉइलर देखें", "view_spoiler": "स्पॉइलर देखें",
"filter": "फ़िल्टर", "filter": "फ़िल्टर",
"edit": "संपादित करें" "edit": "संपादित करें",
"time_1_minute_ago": "1 मिनट पहले",
"time_x_minutes_ago": "{{count}} मिनट पहले",
"time_1_hour_ago": "1 घंटा पहले",
"time_x_hours_ago": "{{count}} घंटे पहले",
"time_1_day_ago": "1 दिन पहले",
"time_x_days_ago": "{{count}} दिन पहले",
"time_1_month_ago": "1 महीना पहले",
"time_x_months_ago": "{{count}} महीने पहले",
"time_1_year_ago": "1 साल पहले",
"time_x_years_ago": "{{count}} साल पहले",
"open": "खोलें"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "szál bezárása", "close_thread": "szál bezárása",
"view_spoiler": "spoiler megtekintése", "view_spoiler": "spoiler megtekintése",
"filter": "szűrő", "filter": "szűrő",
"edit": "szerkesztés" "edit": "szerkesztés",
"time_1_minute_ago": "1 perce",
"time_x_minutes_ago": "{{count}} perce",
"time_1_hour_ago": "1 órája",
"time_x_hours_ago": "{{count}} órája",
"time_1_day_ago": "1 napja",
"time_x_days_ago": "{{count}} napja",
"time_1_month_ago": "1 hónapja",
"time_x_months_ago": "{{count}} hónapja",
"time_1_year_ago": "1 éve",
"time_x_years_ago": "{{count}} éve",
"open": "nyit"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "tutup utas", "close_thread": "tutup utas",
"view_spoiler": "lihat spoiler", "view_spoiler": "lihat spoiler",
"filter": "menyaring", "filter": "menyaring",
"edit": "sunting" "edit": "sunting",
"time_1_minute_ago": "1 menit yang lalu",
"time_x_minutes_ago": "{{count}} menit yang lalu",
"time_1_hour_ago": "1 jam yang lalu",
"time_x_hours_ago": "{{count}} jam yang lalu",
"time_1_day_ago": "1 hari yang lalu",
"time_x_days_ago": "{{count}} hari yang lalu",
"time_1_month_ago": "1 bulan yang lalu",
"time_x_months_ago": "{{count}} bulan yang lalu",
"time_1_year_ago": "1 tahun yang lalu",
"time_x_years_ago": "{{count}} tahun yang lalu",
"open": "buka"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "chiudi il thread", "close_thread": "chiudi il thread",
"view_spoiler": "mostra spoiler", "view_spoiler": "mostra spoiler",
"filter": "filtro", "filter": "filtro",
"edit": "modifica" "edit": "modifica",
"time_1_minute_ago": "1 minuto fa",
"time_x_minutes_ago": "{{count}} minuti fa",
"time_1_hour_ago": "1 ora fa",
"time_x_hours_ago": "{{count}} ore fa",
"time_1_day_ago": "1 giorno fa",
"time_x_days_ago": "{{count}} giorni fa",
"time_1_month_ago": "1 mese fa",
"time_x_months_ago": "{{count}} mesi fa",
"time_1_year_ago": "1 anno fa",
"time_x_years_ago": "{{count}} anni fa",
"open": "apri"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "スレッドを閉じる", "close_thread": "スレッドを閉じる",
"view_spoiler": "スポイラーを表示", "view_spoiler": "スポイラーを表示",
"filter": "フィルター", "filter": "フィルター",
"edit": "編集" "edit": "編集",
"time_1_minute_ago": "1分前",
"time_x_minutes_ago": "{{count}}分前",
"time_1_hour_ago": "1時間前",
"time_x_hours_ago": "{{count}}時間前",
"time_1_day_ago": "1日前",
"time_x_days_ago": "{{count}}日前",
"time_1_month_ago": "1ヶ月前",
"time_x_months_ago": "{{count}}ヶ月前",
"time_1_year_ago": "1年前",
"time_x_years_ago": "{{count}}年前",
"open": "開く"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "스레드 닫기", "close_thread": "스레드 닫기",
"view_spoiler": "스포일러 보기", "view_spoiler": "스포일러 보기",
"filter": "필터", "filter": "필터",
"edit": "편집" "edit": "편집",
"time_1_minute_ago": "1분 전",
"time_x_minutes_ago": "{{count}}분 전",
"time_1_hour_ago": "1시간 전",
"time_x_hours_ago": "{{count}}시간 전",
"time_1_day_ago": "1일 전",
"time_x_days_ago": "{{count}}일 전",
"time_1_month_ago": "1개월 전",
"time_x_months_ago": "{{count}}개월 전",
"time_1_year_ago": "1년 전",
"time_x_years_ago": "{{count}}년 전",
"open": "열기"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "थ्रेड बंद करा", "close_thread": "थ्रेड बंद करा",
"view_spoiler": "स्पॉईलर पहा", "view_spoiler": "स्पॉईलर पहा",
"filter": "फिल्टर", "filter": "फिल्टर",
"edit": "संपादित करा" "edit": "संपादित करा",
"time_1_minute_ago": "१ मिनिटांपूर्वी",
"time_x_minutes_ago": "{{count}} मिनिटांपूर्वी",
"time_1_hour_ago": "१ तासांपूर्वी",
"time_x_hours_ago": "{{count}} तासांपूर्वी",
"time_1_day_ago": "१ दिवसांपूर्वी",
"time_x_days_ago": "{{count}} दिवसांपूर्वी",
"time_1_month_ago": "१ महिन्यांपूर्वी",
"time_x_months_ago": "{{count}} महिन्यांपूर्वी",
"time_1_year_ago": "१ वर्षांपूर्वी",
"time_x_years_ago": "{{count}} वर्षांपूर्वी",
"open": "उघडा"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "draad sluiten", "close_thread": "draad sluiten",
"view_spoiler": "bekijk spoiler", "view_spoiler": "bekijk spoiler",
"filter": "filter", "filter": "filter",
"edit": "bewerken" "edit": "bewerken",
"time_1_minute_ago": "1 minuut geleden",
"time_x_minutes_ago": "{{count}} minuten geleden",
"time_1_hour_ago": "1 uur geleden",
"time_x_hours_ago": "{{count}} uur geleden",
"time_1_day_ago": "1 dag geleden",
"time_x_days_ago": "{{count}} dagen geleden",
"time_1_month_ago": "1 maand geleden",
"time_x_months_ago": "{{count}} maanden geleden",
"time_1_year_ago": "1 jaar geleden",
"time_x_years_ago": "{{count}} jaar geleden",
"open": "openen"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "lukk tråd", "close_thread": "lukk tråd",
"view_spoiler": "se spoiler", "view_spoiler": "se spoiler",
"filter": "filter", "filter": "filter",
"edit": "rediger" "edit": "rediger",
"time_1_minute_ago": "1 minutt siden",
"time_x_minutes_ago": "{{count}} minutter siden",
"time_1_hour_ago": "1 time siden",
"time_x_hours_ago": "{{count}} timer siden",
"time_1_day_ago": "1 dag siden",
"time_x_days_ago": "{{count}} dager siden",
"time_1_month_ago": "1 måned siden",
"time_x_months_ago": "{{count}} måneder siden",
"time_1_year_ago": "1 år siden",
"time_x_years_ago": "{{count}} år siden",
"open": "åpne"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "zamknij wątek", "close_thread": "zamknij wątek",
"view_spoiler": "pokaż spoiler", "view_spoiler": "pokaż spoiler",
"filter": "filtr", "filter": "filtr",
"edit": "edytuj" "edit": "edytuj",
"time_1_minute_ago": "1 minutę temu",
"time_x_minutes_ago": "{{count}} minut temu",
"time_1_hour_ago": "1 godzinę temu",
"time_x_hours_ago": "{{count}} godzin temu",
"time_1_day_ago": "1 dzień temu",
"time_x_days_ago": "{{count}} dni temu",
"time_1_month_ago": "1 miesiąc temu",
"time_x_months_ago": "{{count}} miesięcy temu",
"time_1_year_ago": "1 rok temu",
"time_x_years_ago": "{{count}} lat temu",
"open": "otwórz"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "fechar tópico", "close_thread": "fechar tópico",
"view_spoiler": "ver spoiler", "view_spoiler": "ver spoiler",
"filter": "filtro", "filter": "filtro",
"edit": "editar" "edit": "editar",
"time_1_minute_ago": "há 1 minuto",
"time_x_minutes_ago": "há {{count}} minutos",
"time_1_hour_ago": "há 1 hora",
"time_x_hours_ago": "há {{count}} horas",
"time_1_day_ago": "há 1 dia",
"time_x_days_ago": "há {{count}} dias",
"time_1_month_ago": "há 1 mês",
"time_x_months_ago": "há {{count}} meses",
"time_1_year_ago": "há 1 ano",
"time_x_years_ago": "há {{count}} anos",
"open": "abrir"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "închide firul", "close_thread": "închide firul",
"view_spoiler": "vezi spoilerul", "view_spoiler": "vezi spoilerul",
"filter": "filtru", "filter": "filtru",
"edit": "editați" "edit": "editați",
"time_1_minute_ago": "Acum 1 minut",
"time_x_minutes_ago": "Acum {{count}} minute",
"time_1_hour_ago": "Acum 1 oră",
"time_x_hours_ago": "Acum {{count}} ore",
"time_1_day_ago": "Acum 1 zi",
"time_x_days_ago": "Acum {{count}} zile",
"time_1_month_ago": "Acum 1 lună",
"time_x_months_ago": "Acum {{count}} luni",
"time_1_year_ago": "Acum 1 an",
"time_x_years_ago": "Acum {{count}} ani",
"open": "deschis"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "закрыть тему", "close_thread": "закрыть тему",
"view_spoiler": "посмотреть спойлер", "view_spoiler": "посмотреть спойлер",
"filter": "фильтр", "filter": "фильтр",
"edit": "редактировать" "edit": "редактировать",
"time_1_minute_ago": "1 минуту назад",
"time_x_minutes_ago": "{{count}} минут назад",
"time_1_hour_ago": "1 час назад",
"time_x_hours_ago": "{{count}} часов назад",
"time_1_day_ago": "1 день назад",
"time_x_days_ago": "{{count}} дней назад",
"time_1_month_ago": "1 месяц назад",
"time_x_months_ago": "{{count}} месяцев назад",
"time_1_year_ago": "1 год назад",
"time_x_years_ago": "{{count}} лет назад",
"open": "открыть"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "mbyll temën", "close_thread": "mbyll temën",
"view_spoiler": "shikoni spoiler", "view_spoiler": "shikoni spoiler",
"filter": "filtruar", "filter": "filtruar",
"edit": "redakto" "edit": "redakto",
"time_1_minute_ago": "1 minutë më parë",
"time_x_minutes_ago": "{{count}} minuta më parë",
"time_1_hour_ago": "1 orë më parë",
"time_x_hours_ago": "{{count}} orë më parë",
"time_1_day_ago": "1 ditë më parë",
"time_x_days_ago": "{{count}} ditë më parë",
"time_1_month_ago": "1 muaj më parë",
"time_x_months_ago": "{{count}} muaj më parë",
"time_1_year_ago": "1 vit më parë",
"time_x_years_ago": "{{count}} vite më parë",
"open": "hap"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "stäng tråd", "close_thread": "stäng tråd",
"view_spoiler": "visa spoiler", "view_spoiler": "visa spoiler",
"filter": "filter", "filter": "filter",
"edit": "redigera" "edit": "redigera",
"time_1_minute_ago": "För 1 minut sedan",
"time_x_minutes_ago": "För {{count}} minuter sedan",
"time_1_hour_ago": "För 1 timme sedan",
"time_x_hours_ago": "För {{count}} timmar sedan",
"time_1_day_ago": "För 1 dag sedan",
"time_x_days_ago": "För {{count}} dagar sedan",
"time_1_month_ago": "För 1 månad sedan",
"time_x_months_ago": "För {{count}} månader sedan",
"time_1_year_ago": "För 1 år sedan",
"time_x_years_ago": "För {{count}} år sedan",
"open": "öppna"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "థ్రెడ్‌ను మూసేయండి", "close_thread": "థ్రెడ్‌ను మూసేయండి",
"view_spoiler": "స్పోయ్లర్ వీక్షించండి", "view_spoiler": "స్పోయ్లర్ వీక్షించండి",
"filter": "వడపోత", "filter": "వడపోత",
"edit": "సవరించు" "edit": "సవరించు",
"time_1_minute_ago": "1 నిమిషం క్రితం",
"time_x_minutes_ago": "{{count}} నిమిషాల క్రితం",
"time_1_hour_ago": "1 గంట క్రితం",
"time_x_hours_ago": "{{count}} గంటల క్రితం",
"time_1_day_ago": "1 రోజు క్రితం",
"time_x_days_ago": "{{count}} రోజుల క్రితం",
"time_1_month_ago": "1 నెల క్రితం",
"time_x_months_ago": "{{count}} నెలల క్రితం",
"time_1_year_ago": "1 సంవత్సరం క్రితం",
"time_x_years_ago": "{{count}} సంవత్సరాల క్రితం",
"open": "తెరవండి"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "ปิดกระทู้", "close_thread": "ปิดกระทู้",
"view_spoiler": "ดูสปอยล์เลอร์", "view_spoiler": "ดูสปอยล์เลอร์",
"filter": "ตัวกรอง", "filter": "ตัวกรอง",
"edit": "แก้ไข" "edit": "แก้ไข",
"time_1_minute_ago": "1 นาทีที่ผ่านมา",
"time_x_minutes_ago": "{{count}} นาทีที่ผ่านมา",
"time_1_hour_ago": "1 ชั่วโมงที่ผ่านมา",
"time_x_hours_ago": "{{count}} ชั่วโมงที่ผ่านมา",
"time_1_day_ago": "1 วันที่ผ่านมา",
"time_x_days_ago": "{{count}} วันที่ผ่านมา",
"time_1_month_ago": "1 เดือนที่ผ่านมา",
"time_x_months_ago": "{{count}} เดือนที่ผ่านมา",
"time_1_year_ago": "1 ปีที่ผ่านมา",
"time_x_years_ago": "{{count}} ปีที่ผ่านมา",
"open": "เปิด"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "konuyu kapat", "close_thread": "konuyu kapat",
"view_spoiler": "spoileri görüntüle", "view_spoiler": "spoileri görüntüle",
"filter": "filtre", "filter": "filtre",
"edit": "düzenle" "edit": "düzenle",
"time_1_minute_ago": "1 dakika önce",
"time_x_minutes_ago": "{{count}} dakika önce",
"time_1_hour_ago": "1 saat önce",
"time_x_hours_ago": "{{count}} saat önce",
"time_1_day_ago": "1 gün önce",
"time_x_days_ago": "{{count}} gün önce",
"time_1_month_ago": "1 ay önce",
"time_x_months_ago": "{{count}} ay önce",
"time_1_year_ago": "1 yıl önce",
"time_x_years_ago": "{{count}} yıl önce",
"open": "aç"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "закрити тему", "close_thread": "закрити тему",
"view_spoiler": "переглянути спойлер", "view_spoiler": "переглянути спойлер",
"filter": "фільтр", "filter": "фільтр",
"edit": "редагувати" "edit": "редагувати",
"time_1_minute_ago": "1 хвилину тому",
"time_x_minutes_ago": "{{count}} хвилин тому",
"time_1_hour_ago": "1 годину тому",
"time_x_hours_ago": "{{count}} годин тому",
"time_1_day_ago": "1 день тому",
"time_x_days_ago": "{{count}} днів тому",
"time_1_month_ago": "1 місяць тому",
"time_x_months_ago": "{{count}} місяців тому",
"time_1_year_ago": "1 рік тому",
"time_x_years_ago": "{{count}} років тому",
"open": "відкрити"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "موضوع بند کریں", "close_thread": "موضوع بند کریں",
"view_spoiler": "اسپوائلر دیکھیں", "view_spoiler": "اسپوائلر دیکھیں",
"filter": "فلٹر", "filter": "فلٹر",
"edit": "ترمیم کریں" "edit": "ترمیم کریں",
"time_1_minute_ago": "1 منٹ پہلے",
"time_x_minutes_ago": "{{count}} منٹ پہلے",
"time_1_hour_ago": "1 گھنٹہ پہلے",
"time_x_hours_ago": "{{count}} گھنٹے پہلے",
"time_1_day_ago": "1 دن پہلے",
"time_x_days_ago": "{{count}} دن پہلے",
"time_1_month_ago": "1 مہینہ پہلے",
"time_x_months_ago": "{{count}} مہینے پہلے",
"time_1_year_ago": "1 سال پہلے",
"time_x_years_ago": "{{count}} سال پہلے",
"open": "کھولیں"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "đóng chủ đề", "close_thread": "đóng chủ đề",
"view_spoiler": "xem spoiler", "view_spoiler": "xem spoiler",
"filter": "bộ lọc", "filter": "bộ lọc",
"edit": "chỉnh sửa" "edit": "chỉnh sửa",
"time_1_minute_ago": "1 phút trước",
"time_x_minutes_ago": "{{count}} phút trước",
"time_1_hour_ago": "1 giờ trước",
"time_x_hours_ago": "{{count}} giờ trước",
"time_1_day_ago": "1 ngày trước",
"time_x_days_ago": "{{count}} ngày trước",
"time_1_month_ago": "1 tháng trước",
"time_x_months_ago": "{{count}} tháng trước",
"time_1_year_ago": "1 năm trước",
"time_x_years_ago": "{{count}} năm trước",
"open": "mở"
} }
+12 -1
View File
@@ -148,5 +148,16 @@
"close_thread": "关闭主题", "close_thread": "关闭主题",
"view_spoiler": "查看剧透", "view_spoiler": "查看剧透",
"filter": "过滤器", "filter": "过滤器",
"edit": "编辑" "edit": "编辑",
"time_1_minute_ago": "1分钟前",
"time_x_minutes_ago": "{{count}}分钟前",
"time_1_hour_ago": "1小时前",
"time_x_hours_ago": "{{count}}小时前",
"time_1_day_ago": "1天前",
"time_x_days_ago": "{{count}}天前",
"time_1_month_ago": "1个月前",
"time_x_months_ago": "{{count}}个月前",
"time_1_year_ago": "1年前",
"time_x_years_ago": "{{count}}年前",
"open": "打开"
} }
+6 -4
View File
@@ -1,6 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { Outlet, Route, Routes, useLocation, useParams } from 'react-router-dom'; import { Outlet, Route, Routes, useLocation, useParams } from 'react-router-dom';
import { isHomeView } from './lib/utils/view-utils'; import { isAllView, isHomeView, isSubscriptionsView } from './lib/utils/view-utils';
import useIsMobile from './hooks/use-is-mobile'; import useIsMobile from './hooks/use-is-mobile';
import useTheme from './hooks/use-theme'; import useTheme from './hooks/use-theme';
import styles from './app.module.css'; import styles from './app.module.css';
@@ -21,6 +21,8 @@ const BoardLayout = () => {
const { accountCommentIndex, subplebbitAddress } = useParams(); const { accountCommentIndex, subplebbitAddress } = useParams();
const location = useLocation(); const location = useLocation();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const isInAllView = isAllView(location.pathname);
const isInSubscriptionsView = isSubscriptionsView(location.pathname);
const isValidAccountCommentIndex = !accountCommentIndex || (!isNaN(parseInt(accountCommentIndex)) && parseInt(accountCommentIndex) >= 0); const isValidAccountCommentIndex = !accountCommentIndex || (!isNaN(parseInt(accountCommentIndex)) && parseInt(accountCommentIndex) >= 0);
@@ -36,16 +38,16 @@ const BoardLayout = () => {
<TopBar /> <TopBar />
<BoardHeader /> <BoardHeader />
{isMobile {isMobile
? subplebbitAddress && ( ? (subplebbitAddress || isInAllView || isInSubscriptionsView) && (
<> <>
<PostForm key={key} /> <PostForm key={key} />
<MobileBoardButtons /> <MobileBoardButtons />
</> </>
) )
: subplebbitAddress && ( : (subplebbitAddress || isInAllView || isInSubscriptionsView) && (
<> <>
<PostForm key={key} /> <PostForm key={key} />
<SubplebbitStats /> {!(isInAllView || isInSubscriptionsView) && <SubplebbitStats />}
<DesktopBoardButtons /> <DesktopBoardButtons />
</> </>
)} )}
@@ -83,8 +83,8 @@
visibility: hidden; visibility: hidden;
} }
.post:hover .postMenu { .postMenuVisible {
visibility: visible; visibility: visible !important;
} }
.loadingSkeleton { .loadingSkeleton {
@@ -96,3 +96,36 @@
.fileDeleted { .fileDeleted {
image-rendering: pixelated; image-rendering: pixelated;
} }
.postPreview {
background-color: var(--catalog-post-preview-background-color);
border-radius: 3px;
padding: 5px 8px 4px;
z-index: 100000;
word-wrap: break-word;
white-space: pre-line;
max-width: 500px;
color: var(--catalog-post-preview-color);
font-family: arial, helvetica, sans-serif;
font-size: 10pt;
}
.postPreview .postSubject {
font-weight: 700;
color: var(--catalog-post-preview-subject-color);
}
.postPreview .postAuthor {
color: var(--catalog-post-preview-author-color);
font-weight: 700;
}
.postPreview .postLast {
color: var(--catalog-post-preview-last-color);
font-size: 90%;
margin-top: 3px;
}
.postPreview .capcode {
color: var(--catalog-post-preview-author-capcode-color);
}
+114 -14
View File
@@ -1,14 +1,18 @@
import { Link, useLocation } from 'react-router-dom'; import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Comment } from '@plebbit/plebbit-react-hooks'; import { Link, useLocation } from 'react-router-dom';
import styles from './catalog-row.module.css'; import { Comment, useComment } from '@plebbit/plebbit-react-hooks';
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
import { isAllView } from '../../lib/utils/view-utils'; import { isAllView } from '../../lib/utils/view-utils';
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame'; import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useEditCommentPrivileges from '../../hooks/use-author-privileges';
import PostMenuDesktop from '../post/post-desktop/post-menu-desktop/'; import PostMenuDesktop from '../post/post-desktop/post-menu-desktop/';
import styles from './catalog-row.module.css';
import React, { useState } from 'react'; import _ from 'lodash';
interface CatalogPostMediaProps { interface CatalogPostMediaProps {
commentMediaInfo: any; commentMediaInfo: any;
@@ -69,7 +73,7 @@ export const CatalogPostMedia = ({ commentMediaInfo, isOutOfFeed, linkWidth, lin
return ( return (
<div className={hasError ? '' : styles.mediaWrapper} style={thumbnailDimensions}> <div className={hasError ? '' : styles.mediaWrapper} style={thumbnailDimensions}>
{!isLoaded && !hasError && type !== 'video' && <span className={styles.loadingSkeleton} />} {!isLoaded && !hasError && type !== 'video' && type !== 'audio' && <span className={styles.loadingSkeleton} />}
{hasError ? <img className={styles.fileDeleted} src='/assets/filedeleted-res.gif' alt='File deleted' /> : thumbnailComponent} {hasError ? <img className={styles.fileDeleted} src='/assets/filedeleted-res.gif' alt='File deleted' /> : thumbnailComponent}
</div> </div>
); );
@@ -77,7 +81,8 @@ export const CatalogPostMedia = ({ commentMediaInfo, isOutOfFeed, linkWidth, lin
const CatalogPost = ({ post }: { post: Comment }) => { const CatalogPost = ({ post }: { post: Comment }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { cid, content, isDescription, isRules, link, linkHeight, linkWidth, locked, pinned, replyCount, subplebbitAddress, title } = post || {}; const { author, cid, content, isDescription, isRules, lastChildCid, link, linkHeight, linkWidth, locked, pinned, replyCount, subplebbitAddress, timestamp, title } =
post || {};
const commentMediaInfo = getCommentMediaInfo(post); const commentMediaInfo = getCommentMediaInfo(post);
const hasThumbnail = getHasThumbnail(commentMediaInfo, link); const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
@@ -95,11 +100,85 @@ const CatalogPost = ({ post }: { post: Comment }) => {
</div> </div>
); );
const [hoveredCid, setHoveredCid] = useState<string | null>(null);
const [showPortal, setShowPortal] = useState<boolean>(false);
const placementRef = useRef<Placement>('right-start');
const availableWidthRef = useRef<number>(0);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const { refs, floatingStyles, update } = useFloating({
open: showPortal,
placement: placementRef.current,
middleware: [
shift({ padding: 10 }),
offset({ mainAxis: 5 }),
size({
apply({ availableWidth, elements }) {
availableWidthRef.current = availableWidth;
if (availableWidth >= 250) {
elements.floating.style.maxWidth = `${availableWidth - 12}px`;
} else if (placementRef.current === 'right-start') {
placementRef.current = 'left-start';
}
},
}),
],
whileElementsMounted: autoUpdate,
});
useEffect(() => {
const handleResize = () => {
const availableWidth = availableWidthRef.current;
if (availableWidth >= 250) {
placementRef.current = 'right-start';
} else {
placementRef.current = 'left-start';
}
update();
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [update]);
const lastReply = useComment({ commentCid: lastChildCid });
const { isCommentAuthorMod: isCatalogPostAuthorMod, commentAuthorRole: catalogPostAuthorRole } = useEditCommentPrivileges({
commentAuthorAddress: author?.address,
subplebbitAddress,
});
const { isCommentAuthorMod: isLastReplyAuthorMod, commentAuthorRole: lastReplyAuthorRole } = useEditCommentPrivileges({
commentAuthorAddress: lastReply?.author?.address,
subplebbitAddress,
});
const postContent = (
<div className={styles.teaser}>
<b>{title && `${title}${content ? ': ' : ''}`}</b>
{content}
</div>
);
return ( return (
<>
<div className={styles.post}> <div className={styles.post}>
<div onMouseOver={() => setHoveredCid(cid)} onMouseLeave={() => setHoveredCid(null)}>
{hasThumbnail ? ( {hasThumbnail ? (
<Link to={postLink}> <Link to={postLink}>
<div className={styles.mediaPaddingWrapper}> <div
className={styles.mediaPaddingWrapper}
ref={refs.setReference}
onMouseOver={() => (timeoutRef.current = setTimeout(() => setShowPortal(true), 250))}
onMouseLeave={() => {
setShowPortal(false);
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
}}
>
{threadIcons} {threadIcons}
<CatalogPostMedia commentMediaInfo={commentMediaInfo} isOutOfFeed={isDescription || isRules} linkWidth={linkWidth} linkHeight={linkHeight} /> <CatalogPostMedia commentMediaInfo={commentMediaInfo} isOutOfFeed={isDescription || isRules} linkWidth={linkWidth} linkHeight={linkHeight} />
</div> </div>
@@ -115,17 +194,38 @@ const CatalogPost = ({ post }: { post: Comment }) => {
/ L: <b>{linkCount}</b> / L: <b>{linkCount}</b>
</span> </span>
)} )}
<span className={styles.postMenu}> <span className={`${styles.postMenu} ${hoveredCid && styles.postMenuVisible}`}>
<PostMenuDesktop post={post} /> <PostMenuDesktop post={post} />
</span> </span>
</div> </div>
<Link to={postLink}> {hasThumbnail ? postContent : <Link to={postLink}>{postContent}</Link>}
<div className={styles.teaser}>
<b>{title && `${title}${content ? ': ' : ''}`}</b>
{content}
</div> </div>
</Link>
</div> </div>
{hoveredCid === cid &&
showPortal &&
createPortal(
<div className={styles.postPreview} ref={refs.setFloating} style={floatingStyles}>
<span className={styles.postSubject}>{title}</span>
{' by '}
<span className={`${styles.postAuthor} ${(isCatalogPostAuthorMod || isRules || isDescription) && styles.capcode}`}>
{author?.displayName || _.capitalize(t('anonymous'))}
{isCatalogPostAuthorMod && <span className='capitalize'>{` ## Board ${catalogPostAuthorRole}`}</span>}
</span>
<span className={styles.postAgo}> {getFormattedTimeAgo(timestamp)}</span>
{replyCount > 0 && (
<div className={styles.postLast}>
Last reply by{' '}
<span className={`${styles.postAuthor} ${isLastReplyAuthorMod && styles.capcode}`}>
{lastReply?.author?.displayName || _.capitalize(t('anonymous'))}
{isLastReplyAuthorMod && ` ## Board ${lastReplyAuthorRole}`}
</span>
<span className={styles.postAgo}> {getFormattedTimeAgo(lastReply?.timestamp)}</span>
</div>
)}
</div>,
document.body,
)}
</>
); );
}; };
@@ -11,13 +11,16 @@
overflow: hidden; overflow: hidden;
} }
.subplebbitAvatar { .floatingEmbed, .subplebbitAvatar {
max-width: 250px; max-width: 250px;
max-height: 250px; max-height: 250px;
margin: 3px 20px 5px 0;
display: inline-block; display: inline-block;
} }
.subplebbitAvatar {
margin: 3px 20px 5px 0;
}
.spoiler { .spoiler {
display: inline-block; display: inline-block;
margin: 3px 20px 5px 20px; margin: 3px 20px 5px 20px;
@@ -132,3 +135,10 @@
.fileDeleted { .fileDeleted {
image-rendering: pixelated; image-rendering: pixelated;
} }
@media (min-width: 640px) {
.thumbnail,
.content {
line-height: 0; /* Ensure no extra space due to line-height */
}
}
@@ -11,6 +11,7 @@ import Embed, { canEmbed } from '../embed';
interface MediaProps { interface MediaProps {
commentMediaInfo?: CommentMediaInfo; commentMediaInfo?: CommentMediaInfo;
post?: Comment; post?: Comment;
isFloatingEmbed?: boolean;
isReply?: boolean; isReply?: boolean;
linkHeight?: number; linkHeight?: number;
linkWidth?: number; linkWidth?: number;
@@ -18,11 +19,11 @@ interface MediaProps {
setShowThumbnail: (showThumbnail: boolean) => void; setShowThumbnail: (showThumbnail: boolean) => void;
} }
const Thumbnail = ({ commentMediaInfo, post, setShowThumbnail }: MediaProps) => { const Thumbnail = ({ commentMediaInfo, isFloatingEmbed, post, setShowThumbnail }: MediaProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { deleted, linkHeight, linkWidth, parentCid, removed, spoiler } = post || {}; const { deleted, linkHeight, linkWidth, parentCid, removed, spoiler } = post || {};
const { isDescription, isRules } = post || {}; // custom properties, not from api const { isDescription, isRules } = post || {}; // custom properties, not from api
const isOutOfFeed = isDescription || isRules; // virtuoso wrapper unneeded const isOutOfFeed = isDescription || isRules || isFloatingEmbed; // virtuoso wrapper unneeded
const isReply = parentCid; const isReply = parentCid;
const isDeleted = deleted || removed; const isDeleted = deleted || removed;
@@ -84,7 +85,7 @@ const Thumbnail = ({ commentMediaInfo, post, setShowThumbnail }: MediaProps) =>
<span className={styles.spoilerText}>[{t('view_spoiler')}]</span> <span className={styles.spoilerText}>[{t('view_spoiler')}]</span>
</span> </span>
) : isOutOfFeed ? ( ) : isOutOfFeed ? (
<span className={styles.subplebbitAvatar}>{thumbnailComponent}</span> <span className={`${isFloatingEmbed ? styles.floatingEmbed : styles.subplebbitAvatar}`}>{thumbnailComponent}</span>
) : isMobile || isReply ? ( ) : isMobile || isReply ? (
<span className={`${styles.thumbnailSmall} ${thumbnailSmallPadding}`} style={thumbnailDimensions}> <span className={`${styles.thumbnailSmall} ${thumbnailSmallPadding}`} style={thumbnailDimensions}>
{thumbnailComponent} {thumbnailComponent}
@@ -135,7 +136,7 @@ const Media = ({ commentMediaInfo, isReply, setShowThumbnail }: MediaProps) => {
)} )}
{isMobile && (type === 'iframe' || type === 'video' || type === 'audio') && ( {isMobile && (type === 'iframe' || type === 'video' || type === 'audio') && (
<div className={styles.closeButton}> <div className={styles.closeButton}>
<span className='button' onClick={() => setShowThumbnail(true)}> <span className='button' onClick={() => setShowThumbnail(false)}>
{t('close')} {t('close')}
</span> </span>
</div> </div>
@@ -144,7 +145,7 @@ const Media = ({ commentMediaInfo, isReply, setShowThumbnail }: MediaProps) => {
); );
}; };
const CommentMedia = ({ commentMediaInfo, post, showThumbnail, setShowThumbnail }: MediaProps) => { const CommentMedia = ({ commentMediaInfo, isFloatingEmbed, post, showThumbnail, setShowThumbnail }: MediaProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const { type, url } = commentMediaInfo || {}; const { type, url } = commentMediaInfo || {};
@@ -152,7 +153,7 @@ const CommentMedia = ({ commentMediaInfo, post, showThumbnail, setShowThumbnail
return ( return (
<span className={styles.content}> <span className={styles.content}>
<span className={`${showThumbnail ? styles.show : styles.hide} ${styles.thumbnail}`}> <span className={`${showThumbnail ? styles.show : styles.hide} ${styles.thumbnail}`}>
{url && <Thumbnail commentMediaInfo={commentMediaInfo} post={post} setShowThumbnail={setShowThumbnail} />} {url && <Thumbnail commentMediaInfo={commentMediaInfo} isFloatingEmbed={isFloatingEmbed} post={post} setShowThumbnail={setShowThumbnail} />}
{isMobile && type && <div className={styles.fileInfo}>{getDisplayMediaInfoType(type, t)}</div>} {isMobile && type && <div className={styles.fileInfo}>{getDisplayMediaInfoType(type, t)}</div>}
</span> </span>
{!showThumbnail && <Media commentMediaInfo={commentMediaInfo} isReply={post?.parentCid} setShowThumbnail={setShowThumbnail} />} {!showThumbnail && <Media commentMediaInfo={commentMediaInfo} isReply={post?.parentCid} setShowThumbnail={setShowThumbnail} />}
@@ -39,3 +39,9 @@
.spoiler:hover { .spoiler:hover {
color: white; color: white;
} }
.floatingEmbed {
background-color: #d6daf0;
border: 1px solid #b7c5d9;
padding: 2px;
}
+95 -28
View File
@@ -1,18 +1,100 @@
import React, { useMemo, useState } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm'; import remarkGfm from 'remark-gfm';
import supersub from 'remark-supersub'; import supersub from 'remark-supersub';
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
import styles from './markdown.module.css'; import { useDismiss, useFloating, useFocus, useHover, useInteractions, offset, shift, size, autoUpdate, Placement, FloatingPortal } from '@floating-ui/react';
import { useTranslation } from 'react-i18next';
import { getLinkMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getLinkMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import useIsMobile from '../../hooks/use-is-mobile';
import CommentMedia from '../comment-media'; import CommentMedia from '../comment-media';
import styles from './markdown.module.css';
interface MarkdownProps { interface ContentLinkEmbedProps {
content: string; children: any;
spoiler?: boolean; href: string;
linkMediaInfo: any;
} }
const ContentLinkEmbed = ({ children, href, linkMediaInfo }: ContentLinkEmbedProps) => {
const { t } = useTranslation();
const isMobile = useIsMobile();
const [isOpen, setIsOpen] = useState(false);
const [showMedia, setShowMedia] = useState(false);
const placementRef = useRef<Placement>('right');
const availableWidthRef = useRef<number>(0);
const { refs, floatingStyles, update, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
placement: placementRef.current,
middleware: [
shift({ padding: 10 }),
offset({ mainAxis: 5 }),
size({
apply({ availableWidth, elements }) {
availableWidthRef.current = availableWidth;
if (availableWidth >= 250) {
elements.floating.style.maxWidth = `${availableWidth - 12}px`;
} else if (placementRef.current === 'right') {
placementRef.current = 'left';
}
},
}),
],
whileElementsMounted: autoUpdate,
});
const hover = useHover(context, { move: false });
const focus = useFocus(context);
const dismiss = useDismiss(context);
const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus, dismiss]);
useEffect(() => {
const handleResize = () => {
const availableWidth = availableWidthRef.current;
if (availableWidth >= 250) {
placementRef.current = 'right';
} else {
placementRef.current = 'left';
}
update();
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [update]);
return (
<>
<a href={href} target='_blank' rel='noopener noreferrer'>
{children}
</a>{' '}
[
<span className={styles.embedButton} onClick={() => setShowMedia(!showMedia)} ref={refs.setReference} {...getReferenceProps()}>
{showMedia ? t('remove') : isMobile ? t('open') : t('embed')}
</span>
]
{showMedia && (
<>
<br />
<CommentMedia isReply={false} setShowThumbnail={setShowMedia} commentMediaInfo={linkMediaInfo} showThumbnail={false} />
</>
)}
<FloatingPortal>
{isOpen && !isMobile && (
<div className={styles.floatingEmbed} ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
<CommentMedia isReply={false} isFloatingEmbed={true} setShowThumbnail={setShowMedia} commentMediaInfo={linkMediaInfo} showThumbnail={true} />
</div>
)}
</FloatingPortal>
</>
);
};
const MAX_LENGTH_FOR_GFM = 10000; // remarkGfm lags with large content const MAX_LENGTH_FOR_GFM = 10000; // remarkGfm lags with large content
const blockquoteToGreentext = () => (tree: any) => { const blockquoteToGreentext = () => (tree: any) => {
@@ -38,6 +120,11 @@ const blockquoteToGreentext = () => (tree: any) => {
}); });
}; };
interface MarkdownProps {
content: string;
spoiler?: boolean;
}
const Markdown = ({ content, spoiler }: MarkdownProps) => { const Markdown = ({ content, spoiler }: MarkdownProps) => {
const remarkPlugins: any[] = [[supersub]]; const remarkPlugins: any[] = [[supersub]];
@@ -59,9 +146,6 @@ const Markdown = ({ content, spoiler }: MarkdownProps) => {
remarkPlugins.push([blockquoteToGreentext]); remarkPlugins.push([blockquoteToGreentext]);
const { t } = useTranslation();
const [showMedia, setShowMedia] = useState(false);
return ( return (
<span className={styles.markdown}> <span className={styles.markdown}>
<ReactMarkdown <ReactMarkdown
@@ -69,7 +153,7 @@ const Markdown = ({ content, spoiler }: MarkdownProps) => {
remarkPlugins={remarkPlugins} remarkPlugins={remarkPlugins}
rehypePlugins={[[rehypeSanitize, customSchema]]} rehypePlugins={[[rehypeSanitize, customSchema]]}
components={{ components={{
p: ({ children }) => <p className=''>{spoiler ? <span className={styles.spoiler}>{children}</span> : children}</p>, p: ({ children }) => <p>{spoiler ? <span className={styles.spoiler}>{children}</span> : children}</p>,
img: ({ src }) => <span>{src}</span>, img: ({ src }) => <span>{src}</span>,
video: ({ src }) => <span>{src}</span>, video: ({ src }) => <span>{src}</span>,
iframe: ({ src }) => <span>{src}</span>, iframe: ({ src }) => <span>{src}</span>,
@@ -83,24 +167,7 @@ const Markdown = ({ content, spoiler }: MarkdownProps) => {
if (href) { if (href) {
const linkMediaInfo = getLinkMediaInfo(href); const linkMediaInfo = getLinkMediaInfo(href);
if (getHasThumbnail(linkMediaInfo, href)) { if (getHasThumbnail(linkMediaInfo, href)) {
return ( return <ContentLinkEmbed children={children} href={href} linkMediaInfo={linkMediaInfo} />;
<>
<a href={href} target='_blank' rel='noopener noreferrer'>
{children}
</a>{' '}
[
<span className={styles.embedButton} onClick={() => setShowMedia(!showMedia)}>
{showMedia ? t('remove') : t('embed')}
</span>
]
{showMedia && (
<>
<br />
<CommentMedia isReply={false} setShowThumbnail={setShowMedia} commentMediaInfo={linkMediaInfo} showThumbnail={false} />
</>
)}
</>
);
} else { } else {
return ( return (
<a href={href} target='_blank' rel='noopener noreferrer'> <a href={href} target='_blank' rel='noopener noreferrer'>
@@ -5,11 +5,10 @@ import { Comment, useAccount, useBlock, useComment } from '@plebbit/plebbit-reac
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
import styles from '../post.module.css'; import styles from '../post.module.css';
import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../../lib/utils/media-utils'; import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../../lib/utils/media-utils';
import { getFormattedDate } from '../../../lib/utils/time-utils';
import { isValidURL } from '../../../lib/utils/url-utils'; import { isValidURL } from '../../../lib/utils/url-utils';
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils'; import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils';
import useCountLinksInReplies from '../../../hooks/use-count-links-in-replies'; import useCountLinksInReplies from '../../../hooks/use-count-links-in-replies';
import useEditCommentPrivileges from '../../../hooks/use-edit-comment-privileges'; import useEditCommentPrivileges from '../../../hooks/use-author-privileges';
import useReplies from '../../../hooks/use-replies'; import useReplies from '../../../hooks/use-replies';
import useStateString from '../../../hooks/use-state-string'; import useStateString from '../../../hooks/use-state-string';
import CommentMedia from '../../comment-media'; import CommentMedia from '../../comment-media';
@@ -20,6 +19,7 @@ import PostMenuDesktop from './post-menu-desktop/';
import EditMenu from '../edit-menu/edit-menu'; import EditMenu from '../edit-menu/edit-menu';
import ReplyQuotePreview from '../reply-quote-preview'; import ReplyQuotePreview from '../reply-quote-preview';
import { PostProps } from '../post'; import { PostProps } from '../post';
import Timestamp from '../timestamp';
import _ from 'lodash'; import _ from 'lodash';
const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => { const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
@@ -58,7 +58,7 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
{!(isDescription || isRules) && <span className={styles.userAddress}>(u/{shortAddress || accountShortAddress}) </span>} {!(isDescription || isRules) && <span className={styles.userAddress}>(u/{shortAddress || accountShortAddress}) </span>}
</span> </span>
<span className={styles.dateTime}> <span className={styles.dateTime}>
{getFormattedDate(timestamp)} <Timestamp timestamp={timestamp} />
{isDescription || isRules ? '' : ' '} {isDescription || isRules ? '' : ' '}
</span> </span>
<span className={styles.postNum}> <span className={styles.postNum}>
@@ -185,7 +185,7 @@ const PostMessage = ({ post }: PostProps) => {
{removed ? ( {removed ? (
<span className={styles.removedContent}>({t('this_post_was_removed')})</span> <span className={styles.removedContent}>({t('this_post_was_removed')})</span>
) : deleted ? ( ) : deleted ? (
<span className={styles.removedContent}>{t('user_deleted_this_post')}</span> <span className={styles.deletedContent}>{t('user_deleted_this_post')}</span>
) : ( ) : (
<Markdown content={displayContent} spoiler={spoiler} /> <Markdown content={displayContent} spoiler={spoiler} />
)} )}
@@ -232,7 +232,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
// scroll to reply if pathname is reply permalink (backlink) // scroll to reply if pathname is reply permalink (backlink)
const replyRefs = useRef<(HTMLDivElement | null)[]>([]); const replyRefs = useRef<(HTMLDivElement | null)[]>([]);
useEffect(() => { useEffect(() => {
const replyIndex = replies.findIndex((reply) => location.pathname.startsWith(`/p/${subplebbitAddress}/c/${reply?.cid}`)); const replyIndex = replies.findIndex((reply) => location.pathname === `/p/${subplebbitAddress}/c/${reply?.cid}`);
if (replyIndex !== -1 && replyRefs.current[replyIndex]) { if (replyIndex !== -1 && replyRefs.current[replyIndex]) {
replyRefs.current[replyIndex]?.scrollIntoView(); replyRefs.current[replyIndex]?.scrollIntoView();
} }
@@ -240,7 +240,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
return ( return (
<div className={styles.postDesktop}> <div className={styles.postDesktop}>
{showAllReplies ? ( {showReplies ? (
<div className={styles.hrWrapper}> <div className={styles.hrWrapper}>
<hr /> <hr />
</div> </div>
@@ -248,7 +248,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
<div className={styles.replyQuotePreviewSpacer} /> <div className={styles.replyQuotePreviewSpacer} />
)} )}
<div className={isHidden ? styles.postDesktopBlocked : ''}> <div className={isHidden ? styles.postDesktopBlocked : ''}>
{!isInPostPageView && !isDescription && !isRules && ( {!isInPostPageView && !isDescription && !isRules && showReplies && (
<span className={styles.hideButtonWrapper}> <span className={styles.hideButtonWrapper}>
<span className={`${styles.hideButton} ${blocked ? styles.unhideThread : styles.hideThread}`} onClick={blocked ? unblock : block} /> <span className={`${styles.hideButton} ${blocked ? styles.unhideThread : styles.hideThread}`} onClick={blocked ? unblock : block} />
</span> </span>
@@ -287,7 +287,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
<div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}> <div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}>
<div className={styles.replyDesktop}> <div className={styles.replyDesktop}>
<div className={styles.sideArrows}>{'>>'}</div> <div className={styles.sideArrows}>{'>>'}</div>
<div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight}`}> <div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight}`} id={reply?.cid}>
<PostInfo openReplyModal={openReplyModal} post={reply} roles={roles} /> <PostInfo openReplyModal={openReplyModal} post={reply} roles={roles} />
{reply.link && isValidURL(reply.link) && <PostMedia post={reply} />} {reply.link && isValidURL(reply.link) && <PostMedia post={reply} />}
{reply.content && <PostMessage post={reply} />} {reply.content && <PostMessage post={reply} />}
@@ -10,6 +10,7 @@
font-weight: 700; font-weight: 700;
font-size: 16px; font-size: 16px;
height: 100%; height: 100%;
cursor: pointer;
} }
.postMenu { .postMenu {
@@ -6,7 +6,7 @@ import { autoUpdate, flip, FloatingFocusManager, offset, shift, useClick, useDis
import styles from './post-menu-mobile.module.css'; import styles from './post-menu-mobile.module.css';
import { getCommentMediaInfo } from '../../../../lib/utils/media-utils'; import { getCommentMediaInfo } from '../../../../lib/utils/media-utils';
import { copyShareLinkToClipboard, isValidURL } from '../../../../lib/utils/url-utils'; import { copyShareLinkToClipboard, isValidURL } from '../../../../lib/utils/url-utils';
import useEditCommentPrivileges from '../../../../hooks/use-edit-comment-privileges'; import useEditCommentPrivileges from '../../../../hooks/use-author-privileges';
import EditMenu from '../../edit-menu/edit-menu'; import EditMenu from '../../edit-menu/edit-menu';
interface PostMenuMobileProps { interface PostMenuMobileProps {
+10 -11
View File
@@ -5,7 +5,6 @@ import { Comment, useAccount, useComment } from '@plebbit/plebbit-react-hooks';
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
import styles from '../post.module.css'; import styles from '../post.module.css';
import { getCommentMediaInfo, getHasThumbnail } from '../../../lib/utils/media-utils'; import { getCommentMediaInfo, getHasThumbnail } from '../../../lib/utils/media-utils';
import { getFormattedDate } from '../../../lib/utils/time-utils';
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils'; import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils';
import useCountLinksInReplies from '../../../hooks/use-count-links-in-replies'; import useCountLinksInReplies from '../../../hooks/use-count-links-in-replies';
import useReplies from '../../../hooks/use-replies'; import useReplies from '../../../hooks/use-replies';
@@ -16,6 +15,7 @@ import Markdown from '../../markdown';
import ReplyQuotePreview from '../reply-quote-preview'; import ReplyQuotePreview from '../reply-quote-preview';
import PostMenuMobile from './post-menu-mobile'; import PostMenuMobile from './post-menu-mobile';
import { PostProps } from '../post'; import { PostProps } from '../post';
import Timestamp from '../timestamp';
import _ from 'lodash'; import _ from 'lodash';
const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => { const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
@@ -78,7 +78,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
<Link to={`/p/${subplebbitAddress}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link> <Link to={`/p/${subplebbitAddress}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>
</div> </div>
)} )}
{getFormattedDate(timestamp)}{' '} <Timestamp timestamp={timestamp} />{' '}
{!(isDescription || isRules) && ( {!(isDescription || isRules) && (
<span className={styles.postNumLink}> <span className={styles.postNumLink}>
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}> <Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
@@ -117,7 +117,7 @@ const ReplyBacklinks = ({ post }: PostProps) => {
const PostMessageMobile = ({ post }: PostProps) => { const PostMessageMobile = ({ post }: PostProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { cid, content, deleted, parentCid, postCid, reason, removed, state, subplebbitAddress } = post || {}; const { cid, content, deleted, parentCid, postCid, reason, removed, spoiler, state, subplebbitAddress } = post || {};
const params = useParams(); const params = useParams();
const location = useLocation(); const location = useLocation();
@@ -145,7 +145,7 @@ const PostMessageMobile = ({ post }: PostProps) => {
) : deleted ? ( ) : deleted ? (
<span className={styles.removedContent}>{t('user_deleted_this_post')}</span> <span className={styles.removedContent}>{t('user_deleted_this_post')}</span>
) : ( ) : (
<Markdown content={displayContent} /> <Markdown content={displayContent} spoiler={spoiler} />
)} )}
{(removed || deleted) && reason && ( {(removed || deleted) && reason && (
<span> <span>
@@ -183,11 +183,10 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
const linksCount = useCountLinksInReplies(post); const linksCount = useCountLinksInReplies(post);
const replies = useReplies(post); const replies = useReplies(post);
// scroll to reply if pathname is reply permalink (backlink)
const replyRefs = useRef<(HTMLDivElement | null)[]>([]); const replyRefs = useRef<(HTMLDivElement | null)[]>([]);
useEffect(() => { useEffect(() => {
const replyIndex = replies.findIndex((reply) => location.pathname.startsWith(`/p/${subplebbitAddress}/c/${reply?.cid}`)); const replyIndex = replies.findIndex((reply) => location.pathname === `/p/${subplebbitAddress}/c/${reply?.cid}`);
if (replyIndex !== -1 && replyRefs.current[replyIndex]) { if (replyIndex !== -1 && replyRefs.current[replyIndex]) {
replyRefs.current[replyIndex]?.scrollIntoView(); replyRefs.current[replyIndex]?.scrollIntoView();
} }
@@ -195,18 +194,18 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
return ( return (
<div className={styles.postMobile}> <div className={styles.postMobile}>
{showAllReplies && ( {showReplies && (
<div className={styles.hrWrapper}> <div className={styles.hrWrapper}>
<hr /> <hr />
</div> </div>
)} )}
<div className={showAllReplies ? styles.thread : styles.quotePreview}> <div className={showReplies ? styles.thread : styles.quotePreview}>
<div className={styles.postContainer}> <div className={styles.postContainer}>
<div className={styles.postOp}> <div className={styles.postOp}>
<PostInfoAndMedia openReplyModal={openReplyModal} post={post} roles={roles} /> <PostInfoAndMedia openReplyModal={openReplyModal} post={post} roles={roles} />
{content && <PostMessageMobile post={post} />} {content && <PostMessageMobile post={post} />}
</div> </div>
{!isInPostView && !isInPendingPostView && ( {!isInPostView && !isInPendingPostView && showReplies && (
<div className={styles.postLink}> <div className={styles.postLink}>
<span className={styles.info}> <span className={styles.info}>
{replyCount > 0 && `${replyCount} Replies`} {replyCount > 0 && `${replyCount} Replies`}
@@ -233,7 +232,7 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
<div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}> <div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}>
<div className={styles.replyMobile}> <div className={styles.replyMobile}>
<div className={styles.reply}> <div className={styles.reply}>
<div className={`${styles.replyContainer} ${isRouteLinkToReply && styles.highlight}`}> <div className={`${styles.replyContainer} ${isRouteLinkToReply && styles.highlight}`} id={reply?.cid}>
<PostInfoAndMedia openReplyModal={openReplyModal} post={reply} roles={roles} /> <PostInfoAndMedia openReplyModal={openReplyModal} post={reply} roles={roles} />
{reply.content && <PostMessageMobile post={reply} />} {reply.content && <PostMessageMobile post={reply} />}
<ReplyBacklinks post={reply} /> <ReplyBacklinks post={reply} />
+5 -2
View File
@@ -392,12 +392,15 @@
cursor: pointer; cursor: pointer;
} }
.removedContent { .removedContent, .deletedContent {
text-transform: uppercase;
font-weight: 700; font-weight: 700;
color: red; color: red;
} }
.removedContent {
text-transform: uppercase;
}
.backlink, .backlinkHash { .backlink, .backlinkHash {
font-size: 0.8em; font-size: 0.8em;
} }
@@ -1,8 +1,7 @@
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Comment } from '@plebbit/plebbit-react-hooks'; import { Comment, useAccount } from '@plebbit/plebbit-react-hooks';
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react'; import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
import useIsMobile from '../../../hooks/use-is-mobile'; import useIsMobile from '../../../hooks/use-is-mobile';
import styles from '../post.module.css'; import styles from '../post.module.css';
@@ -15,8 +14,32 @@ interface ReplyQuotePreviewProps {
quotelinkReply?: Comment; quotelinkReply?: Comment;
} }
const handleQuoteHover = (cid: string, onElementOutOfView: () => void) => {
const targetElement = document.getElementById(cid);
if (!targetElement) return;
const isInViewport = (element: HTMLElement) => {
const bounding = element.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
if (isInViewport(targetElement)) {
targetElement.classList.add('highlight');
} else {
targetElement.classList.remove('highlight');
onElementOutOfView();
}
};
const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => { const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
const [hoveredCid, setHoveredCid] = useState<string | null>(null); const [hoveredCid, setHoveredCid] = useState<string | null>(null);
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
const placementRef = useRef<Placement>('right'); const placementRef = useRef<Placement>('right');
const availableWidthRef = useRef<number>(0); const availableWidthRef = useRef<number>(0);
@@ -56,18 +79,37 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
}; };
}, [update]); }, [update]);
const handleMouseOver = (cid: string | undefined) => {
if (!cid) return;
handleQuoteHover(cid, () => setOutOfViewCid(cid));
setHoveredCid(cid);
};
const handleMouseLeave = (cid: string | null) => {
if (cid) {
const targetElement = document.getElementById(cid);
if (targetElement) {
targetElement.classList.remove('highlight');
}
}
setHoveredCid(null);
setOutOfViewCid(null);
};
const replyBacklink = ( const replyBacklink = (
<> <>
<Link <Link
className={styles.backlink} className={styles.backlink}
to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`}
ref={refs.setReference} ref={refs.setReference}
onMouseOver={() => setHoveredCid(backlinkReply?.cid)} onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
onMouseLeave={() => setHoveredCid(null)} onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
> >
c/{backlinkReply?.shortCid} c/{backlinkReply?.shortCid}
</Link> </Link>
{hoveredCid === backlinkReply?.cid && {hoveredCid === backlinkReply?.cid &&
outOfViewCid === backlinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={backlinkReply} showReplies={false} /> <Post post={backlinkReply} showReplies={false} />
@@ -77,19 +119,23 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
</> </>
); );
const account = useAccount();
const replyQuotelink = ( const replyQuotelink = (
<> <>
<Link <Link
to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}
ref={refs.setReference} ref={refs.setReference}
className={styles.quoteLink} className={styles.quoteLink}
onMouseOver={() => setHoveredCid(quotelinkReply?.cid)} onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
onMouseLeave={() => setHoveredCid(null)} onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
> >
{`c/${quotelinkReply?.cid && Plebbit.getShortCid(quotelinkReply.cid)}`} {`c/${quotelinkReply?.shortCid}`}
{quotelinkReply?.author?.address === account?.author?.address && ' (You)'}
</Link> </Link>
<br /> <br />
{hoveredCid === quotelinkReply?.cid && {hoveredCid === quotelinkReply?.cid &&
outOfViewCid === quotelinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={quotelinkReply} showReplies={false} /> <Post post={quotelinkReply} showReplies={false} />
@@ -104,6 +150,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => { const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
const [hoveredCid, setHoveredCid] = useState<string | null>(null); const [hoveredCid, setHoveredCid] = useState<string | null>(null);
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
const { refs, floatingStyles, update } = useFloating({ const { refs, floatingStyles, update } = useFloating({
placement: 'bottom', placement: 'bottom',
@@ -118,15 +165,39 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
}; };
}, [update]); }, [update]);
const handleMouseOver = (cid: string | undefined) => {
if (!cid) return;
handleQuoteHover(cid, () => setOutOfViewCid(cid));
setHoveredCid(cid);
};
const handleMouseLeave = (cid: string | null) => {
if (cid) {
const targetElement = document.getElementById(cid);
if (targetElement) {
targetElement.classList.remove('highlight');
}
}
setHoveredCid(null);
setOutOfViewCid(null);
};
const replyBacklink = ( const replyBacklink = (
<> <>
<span className={styles.backlink} ref={refs.setReference} onMouseOver={() => setHoveredCid(backlinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> <span
className={styles.backlink}
ref={refs.setReference}
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
>
c/{backlinkReply?.shortCid}{' '} c/{backlinkReply?.shortCid}{' '}
</span> </span>
<Link to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} className={styles.backlinkHash}> <Link to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} className={styles.backlinkHash}>
# #
</Link> </Link>
{hoveredCid === backlinkReply?.cid && {hoveredCid === backlinkReply?.cid &&
outOfViewCid === backlinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={backlinkReply} showReplies={false} /> <Post post={backlinkReply} showReplies={false} />
@@ -136,16 +207,26 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
</> </>
); );
const account = useAccount();
const replyQuotelink = ( const replyQuotelink = (
<> <>
<span ref={refs.setReference} className={styles.quoteLink} onMouseOver={() => setHoveredCid(quotelinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> <span
c/{quotelinkReply?.shortCid}{' '} ref={refs.setReference}
className={styles.quoteLink}
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
>
c/{quotelinkReply?.shortCid}
{quotelinkReply?.author?.address === account?.author?.address && ' (You)'}
</span> </span>
<Link className={styles.quoteLink} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}> <Link className={styles.quoteLink} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}>
{' '}
# #
</Link> </Link>
<br /> <br />
{hoveredCid === quotelinkReply?.cid && {hoveredCid === quotelinkReply?.cid &&
outOfViewCid === quotelinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={quotelinkReply} showReplies={false} /> <Post post={quotelinkReply} showReplies={false} />
+1
View File
@@ -0,0 +1 @@
export { default } from './timestamp';
@@ -0,0 +1,45 @@
import { useState } from 'react';
import { getFormattedDate, getFormattedTimeAgo } from '../../../lib/utils/time-utils';
import { useFloating, autoUpdate, offset, flip, shift, useHover, useFocus, useDismiss, useRole, useInteractions, FloatingPortal } from '@floating-ui/react';
const Timestamp = ({ timestamp }: { timestamp: number }) => {
const [isOpen, setIsOpen] = useState(false);
const { refs, floatingStyles, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
placement: 'top',
whileElementsMounted: autoUpdate,
middleware: [
offset(5),
flip({
fallbackAxisSideDirection: 'start',
}),
shift(),
],
});
const hover = useHover(context, { move: false, delay: { open: 250, close: 0 } });
const focus = useFocus(context);
const dismiss = useDismiss(context);
const role = useRole(context, { role: 'tooltip' });
const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus, dismiss, role]);
return (
<>
<span ref={refs.setReference} {...getReferenceProps()}>
{getFormattedDate(timestamp)}
</span>
<FloatingPortal>
{isOpen && (
<div className='tooltip' ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
{getFormattedTimeAgo(timestamp)}
</div>
)}
</FloatingPortal>
</>
);
};
export default Timestamp;
@@ -1,11 +1,11 @@
import { useAccount, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { useAccount, useSubplebbit } from '@plebbit/plebbit-react-hooks';
interface EditCommentPrivileges { interface AuthorPrivilegesProps {
commentAuthorAddress: string; commentAuthorAddress: string;
subplebbitAddress: string; subplebbitAddress: string;
} }
const useEditCommentPrivileges = ({ commentAuthorAddress, subplebbitAddress }: EditCommentPrivileges) => { const useAuthorPrivileges = ({ commentAuthorAddress, subplebbitAddress }: AuthorPrivilegesProps) => {
const accountAuthorAddress = useAccount()?.author?.address; const accountAuthorAddress = useAccount()?.author?.address;
const { roles } = useSubplebbit({ subplebbitAddress }) || {}; const { roles } = useSubplebbit({ subplebbitAddress }) || {};
@@ -15,7 +15,7 @@ const useEditCommentPrivileges = ({ commentAuthorAddress, subplebbitAddress }: E
const isAccountMod = accountAuthorRole === 'admin' || accountAuthorRole === 'owner' || accountAuthorRole === 'moderator'; const isAccountMod = accountAuthorRole === 'admin' || accountAuthorRole === 'owner' || accountAuthorRole === 'moderator';
const isAccountCommentAuthor = accountAuthorAddress === commentAuthorAddress; const isAccountCommentAuthor = accountAuthorAddress === commentAuthorAddress;
return { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor }; return { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor, commentAuthorRole, accountAuthorRole };
}; };
export default useEditCommentPrivileges; export default useAuthorPrivileges;
+2 -2
View File
@@ -10,9 +10,9 @@ const usePopularPosts = (subplebbits: Subplebbit[]) => {
const allPosts: Comment[] = []; const allPosts: Comment[] = [];
let postsPerSub = 1; let postsPerSub = 1;
if (subplebbits.length == 2) { if (subplebbits.length === 2) {
postsPerSub = 4; postsPerSub = 4;
} else if (subplebbits.length == 3) { } else if (subplebbits.length === 3) {
postsPerSub = 3; postsPerSub = 3;
} else if (subplebbits.length >= 4 && subplebbits.length < 8) { } else if (subplebbits.length >= 4 && subplebbits.length < 8) {
postsPerSub = 2; postsPerSub = 2;
+2 -2
View File
@@ -2,7 +2,7 @@ import { useMemo, useCallback } from 'react';
import { Comment, useAccountComments } from '@plebbit/plebbit-react-hooks'; import { Comment, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'; import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils';
const useRepliesAndAccountReplies = (comment: Comment) => { const useReplies = (comment: Comment) => {
// flatten all replies including nested ones from the original comment // flatten all replies including nested ones from the original comment
const flattenedReplies = useMemo(() => flattenCommentsPages(comment.replies), [comment.replies]); const flattenedReplies = useMemo(() => flattenCommentsPages(comment.replies), [comment.replies]);
@@ -45,4 +45,4 @@ const useRepliesAndAccountReplies = (comment: Comment) => {
return repliesAndNotYetPublishedReplies; return repliesAndNotYetPublishedReplies;
}; };
export default useRepliesAndAccountReplies; export default useReplies;
+36
View File
@@ -26,6 +26,42 @@ hr {
color: var(--post-greentext-color); color: var(--post-greentext-color);
} }
.highlight {
background: var(--reply-highlight-background-color) !important;
}
.capitalize {
text-transform: capitalize;
}
.tooltip {
position: absolute;
background-color: #181f24;
font-size: 11px;
line-height: 13px;
padding: 3px 6px;
z-index: 100000;
word-wrap: break-word;
white-space: pre-line;
max-width: 400px;
color: #fff;
text-align: center;
}
.tooltip::before {
content: "";
display: block;
width: 0;
height: 0;
position: absolute;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #181f24;
margin-left: -4px;
bottom: -4px;
left: 50%;
}
@media (max-width: 640px) { @media (max-width: 640px) {
.button { .button {
font-size: var(--button-font-size-mobile); font-size: var(--button-font-size-mobile);
+35
View File
@@ -33,3 +33,38 @@ export const getFormattedDate = (commentTimestamp: number) => {
} }
return string; return string;
}; };
export const getFormattedTimeAgo = (unixTimestamp: number): string => {
const currentTime = Date.now() / 1000;
const timeDifference = currentTime - unixTimestamp;
const t = i18next.t;
if (timeDifference < 120) {
return t('time_1_minute_ago');
}
if (timeDifference < 3600) {
return t('time_x_minutes_ago', { count: Math.floor(timeDifference / 60) });
}
if (timeDifference < 7200) {
return t('time_1_hour_ago');
}
if (timeDifference < 86400) {
return t('time_x_hours_ago', { count: Math.floor(timeDifference / 3600) });
}
if (timeDifference < 172800) {
return t('time_1_day_ago');
}
if (timeDifference < 2592000) {
return t('time_x_days_ago', { count: Math.floor(timeDifference / 86400) });
}
if (timeDifference < 5184000) {
return t('time_1_month_ago');
}
if (timeDifference < 31104000) {
return t('time_x_months_ago', { count: Math.floor(timeDifference / 2592000) });
}
if (timeDifference < 62208000) {
return t('time_1_year_ago');
}
return t('time_x_years_ago', { count: Math.floor(timeDifference / 31104000) });
};
+3 -2
View File
@@ -45,12 +45,13 @@ export const isRulesView = (pathname: string, params: ParamsType): boolean => {
}; };
export const isSettingsView = (pathname: string, params: ParamsType): boolean => { export const isSettingsView = (pathname: string, params: ParamsType): boolean => {
const { subplebbitAddress, commentCid } = params; const { accountCommentIndex, commentCid, subplebbitAddress } = params;
const decodedPathname = decodeURIComponent(pathname); const decodedPathname = decodeURIComponent(pathname);
return ( return (
decodedPathname === `/p/${subplebbitAddress}/c/${commentCid}/settings` || decodedPathname === `/p/${subplebbitAddress}/c/${commentCid}/settings` ||
decodedPathname === `/p/${subplebbitAddress}/description/settings` || decodedPathname === `/p/${subplebbitAddress}/description/settings` ||
decodedPathname === `/p/${subplebbitAddress}/rules/settings` decodedPathname === `/p/${subplebbitAddress}/rules/settings` ||
decodedPathname === `/profile/${accountCommentIndex}/settings`
); );
}; };
+33 -1
View File
@@ -25,6 +25,12 @@
--catalog-post-menu-desktop-btn-hover-color: red; --catalog-post-menu-desktop-btn-hover-color: red;
--catalog-post-menu-desktop-btn-opacity: 0.5; --catalog-post-menu-desktop-btn-opacity: 0.5;
--catalog-post-menu-desktop-btn-hover-opacity: 1; --catalog-post-menu-desktop-btn-hover-opacity: 1;
--catalog-post-preview-background-color: #181f24;
--catalog-post-preview-color: #dedede;
--catalog-post-preview-subject-color: #cc1105;
--catalog-post-preview-author-color: #00a550;
--catalog-post-preview-last-color: #bbbfbd;
--catalog-post-preview-author-capcode-color: purple;
/* challenge modal */ /* challenge modal */
--challenge-modal-background-color: #f0e0d6; --challenge-modal-background-color: #f0e0d6;
@@ -226,6 +232,11 @@
--catalog-post-menu-desktop-btn-hover-color: #d00; --catalog-post-menu-desktop-btn-hover-color: #d00;
--catalog-post-menu-desktop-btn-opacity: 0.5; --catalog-post-menu-desktop-btn-opacity: 0.5;
--catalog-post-menu-desktop-btn-hover-opacity: 1; --catalog-post-menu-desktop-btn-hover-opacity: 1;
--catalog-post-preview-background-color: #181f24;
--catalog-post-preview-color: #dedede;
--catalog-post-preview-author-color: #00a550;
--catalog-post-preview-last-color: #bbbfbd;
--catalog-post-preview-author-capcode-color: purple;
/* challenge modal */ /* challenge modal */
--challenge-modal-background-color: #d6daf0; --challenge-modal-background-color: #d6daf0;
@@ -421,6 +432,12 @@
--catalog-post-menu-desktop-btn-hover-color: red; --catalog-post-menu-desktop-btn-hover-color: red;
--catalog-post-menu-desktop-btn-opacity: 0.5; --catalog-post-menu-desktop-btn-opacity: 0.5;
--catalog-post-menu-desktop-btn-hover-opacity: 1; --catalog-post-menu-desktop-btn-hover-opacity: 1;
--catalog-post-preview-background-color: #181f24;
--catalog-post-preview-color: #dedede;
--catalog-post-preview-subject-color: #cc1105;
--catalog-post-preview-author-color: #00a550;
--catalog-post-preview-last-color: #bbbfbd;
--catalog-post-preview-author-capcode-color: purple;
/* challenge modal */ /* challenge modal */
--challenge-modal-background-color: #f0e0d6; --challenge-modal-background-color: #f0e0d6;
@@ -590,6 +607,11 @@
--catalog-post-menu-desktop-btn-hover-color: red; --catalog-post-menu-desktop-btn-hover-color: red;
--catalog-post-menu-desktop-btn-opacity: 0.5; --catalog-post-menu-desktop-btn-opacity: 0.5;
--catalog-post-menu-desktop-btn-hover-opacity: 1; --catalog-post-menu-desktop-btn-hover-opacity: 1;
--catalog-post-preview-background-color: #181f24;
--catalog-post-preview-color: #dedede;
--catalog-post-preview-author-color: #00a550;
--catalog-post-preview-last-color: #bbbfbd;
--catalog-post-preview-author-capcode-color: purple;
/* challenge modal */ /* challenge modal */
--challenge-modal-background-color: #d6daf0; --challenge-modal-background-color: #d6daf0;
@@ -766,12 +788,18 @@
--catalog-post-menu-desktop-btn-hover-color: #5f89ac; --catalog-post-menu-desktop-btn-hover-color: #5f89ac;
--catalog-post-menu-desktop-btn-opacity: 0.5; --catalog-post-menu-desktop-btn-opacity: 0.5;
--catalog-post-menu-desktop-btn-hover-opacity: 1; --catalog-post-menu-desktop-btn-hover-opacity: 1;
--catalog-post-preview-background-color: #181f24;
--catalog-post-preview-color: #dedede;
--catalog-post-preview-subject-color: #b294bb;
--catalog-post-preview-author-color: #00a550;
--catalog-post-preview-last-color: #bbbfbd;
--catalog-post-preview-author-capcode-color: purple;
/* challenge modal */ /* challenge modal */
--challenge-modal-background-color: #282a2e; --challenge-modal-background-color: #282a2e;
--challenge-modal-border: 1px solid #111; --challenge-modal-border: 1px solid #111;
--challenge-modal-title-background-color: #282a2e; --challenge-modal-title-background-color: #282a2e;
--challenge-modal-title-text-color: #c5c8c6; --challenge-modal-title-text-color: #b0cab9;
--challenge-modal-title-border: unset; --challenge-modal-title-border: unset;
--challenge-modal-title-font-size: 10pt; --challenge-modal-title-font-size: 10pt;
--challenge-modal-title-font-weight: 700; --challenge-modal-title-font-weight: 700;
@@ -969,6 +997,10 @@
--catalog-post-menu-desktop-btn-hover-color: #f30; --catalog-post-menu-desktop-btn-hover-color: #f30;
--catalog-post-menu-desktop-btn-opacity: 0.5; --catalog-post-menu-desktop-btn-opacity: 0.5;
--catalog-post-menu-desktop-btn-hover-opacity: 1; --catalog-post-menu-desktop-btn-hover-opacity: 1;
--catalog-post-preview-background-color: #181f24;
--catalog-post-preview-color: #dedede;
--catalog-post-preview-last-color: #bbbfbd;
--catalog-post-preview-author-capcode-color: purple;
/* challenge modal */ /* challenge modal */
--challenge-modal-background-color: #ddd; --challenge-modal-background-color: #ddd;
+1 -1
View File
@@ -197,7 +197,7 @@ const BoardsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[]; subplebb
return ( return (
<div className={`${styles.box} ${styles.boardsBox}`}> <div className={`${styles.box} ${styles.boardsBox}`}>
<div className={styles.boxBar}> <div className={styles.boxBar}>
<h2 className={styles.capitalize}>{t('boards')}</h2> <h2 className='capitalize'>{t('boards')}</h2>
<BoxModal isBoardsBoxModal={true} /> <BoxModal isBoardsBoxModal={true} />
</div> </div>
<div className={styles.boardsBoxContent}> <div className={styles.boardsBoxContent}>
-4
View File
@@ -150,10 +150,6 @@
content: '✔ '; content: '✔ ';
} }
.capitalize {
text-transform: capitalize;
}
.list a { .list a {
color: var(--homepage-box-link-text-color); color: var(--homepage-box-link-text-color);
text-decoration: var(--homepage-box-link-text-decoration); text-decoration: var(--homepage-box-link-text-decoration);
+2 -2
View File
@@ -88,7 +88,7 @@ const Stats = ({ multisub, subplebbitAddresses }: { multisub: any; subplebbitAdd
return ( return (
<div className={styles.box}> <div className={styles.box}>
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}> <div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
<h2 className={styles.capitalize}>{t('stats')}</h2> <h2 className='capitalize'>{t('stats')}</h2>
</div> </div>
<div className={`${styles.boxContent} ${enoughStats ? styles.stats : ''}`}> <div className={`${styles.boxContent} ${enoughStats ? styles.stats : ''}`}>
{enoughStats ? ( {enoughStats ? (
@@ -143,7 +143,7 @@ const Footer = () => {
</a> </a>
</li> </li>
<li> <li>
<a href='https://twitter.com/plebchan_eth' target='_blank' rel='noopener noreferrer'> <a href='https://twitter.com/getplebchan' target='_blank' rel='noopener noreferrer'>
Twitter Twitter
</a> </a>
</li> </li>
@@ -63,7 +63,7 @@ const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[];
return ( return (
<div className={styles.box}> <div className={styles.box}>
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}> <div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
<h2 className={styles.capitalize}>{t('popular_threads')}</h2> <h2 className='capitalize'>{t('popular_threads')}</h2>
<BoxModal isBoardsBoxModal={false} /> <BoxModal isBoardsBoxModal={false} />
</div> </div>
<div className={`${styles.boxContent} ${popularPosts.length === 8 ? styles.popularThreads : ''}`}> <div className={`${styles.boxContent} ${popularPosts.length === 8 ? styles.popularThreads : ''}`}>
+12 -2
View File
@@ -1,13 +1,18 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { useAccountComment } from '@plebbit/plebbit-react-hooks'; import { useAccountComment } from '@plebbit/plebbit-react-hooks';
import { isSettingsView } from '../../lib/utils/view-utils';
import Post from '../../components/post'; import Post from '../../components/post';
import SettingsModal from '../../components/settings-modal';
const PendingPost = () => { const PendingPost = () => {
const { accountCommentIndex } = useParams<{ accountCommentIndex?: string }>(); const { accountCommentIndex } = useParams<{ accountCommentIndex?: string }>();
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined; const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
const post = useAccountComment({ commentIndex }); const post = useAccountComment({ commentIndex });
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation();
const params = useParams();
const isInSettingsView = isSettingsView(location.pathname, params);
useEffect(() => window.scrollTo(0, 0), []); useEffect(() => window.scrollTo(0, 0), []);
@@ -17,7 +22,12 @@ const PendingPost = () => {
} }
}, [post, navigate]); }, [post, navigate]);
return <Post post={post} />; return (
<>
{isInSettingsView && <SettingsModal />}
<Post post={post} showReplies={false} />;
</>
);
}; };
export default PendingPost; export default PendingPost;