mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
@@ -148,5 +148,16 @@
|
||||
"close_thread": "اغلق الموضوع",
|
||||
"view_spoiler": "عرض الحاضر",
|
||||
"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": "فتح"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "থ্রেড বন্ধ করুন",
|
||||
"view_spoiler": "স্পোয়ালার দেখুন",
|
||||
"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": "খুলুন"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "uzavřít vlákno",
|
||||
"view_spoiler": "zobrazit spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "luk tråd",
|
||||
"view_spoiler": "vis spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "Thread schließen",
|
||||
"view_spoiler": "Spoiler anzeigen",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "κλείσιμο νήματος",
|
||||
"view_spoiler": "προβολή spoiler",
|
||||
"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": "ανοικτό"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "close thread",
|
||||
"view_spoiler": "view spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "cerrar hilo",
|
||||
"view_spoiler": "ver spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "بستن موضوع",
|
||||
"view_spoiler": "نمایش اسپویلر",
|
||||
"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": "باز کردن"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "sulje keskustelu",
|
||||
"view_spoiler": "näytä spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "isara ang thread",
|
||||
"view_spoiler": "tingnan ang spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "fermer le fil",
|
||||
"view_spoiler": "voir le spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "סגור את הנושא",
|
||||
"view_spoiler": "הצג ספוילר",
|
||||
"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": "לפתוח"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "थ्रेड बंद करें",
|
||||
"view_spoiler": "स्पॉइलर देखें",
|
||||
"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": "खोलें"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "szál bezárása",
|
||||
"view_spoiler": "spoiler megtekintése",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "tutup utas",
|
||||
"view_spoiler": "lihat spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "chiudi il thread",
|
||||
"view_spoiler": "mostra spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "スレッドを閉じる",
|
||||
"view_spoiler": "スポイラーを表示",
|
||||
"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": "開く"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "스레드 닫기",
|
||||
"view_spoiler": "스포일러 보기",
|
||||
"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": "열기"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "थ्रेड बंद करा",
|
||||
"view_spoiler": "स्पॉईलर पहा",
|
||||
"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": "उघडा"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "draad sluiten",
|
||||
"view_spoiler": "bekijk spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "lukk tråd",
|
||||
"view_spoiler": "se spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "zamknij wątek",
|
||||
"view_spoiler": "pokaż spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "fechar tópico",
|
||||
"view_spoiler": "ver spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "închide firul",
|
||||
"view_spoiler": "vezi spoilerul",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "закрыть тему",
|
||||
"view_spoiler": "посмотреть спойлер",
|
||||
"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": "открыть"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "mbyll temën",
|
||||
"view_spoiler": "shikoni spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "stäng tråd",
|
||||
"view_spoiler": "visa spoiler",
|
||||
"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"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "థ్రెడ్ను మూసేయండి",
|
||||
"view_spoiler": "స్పోయ్లర్ వీక్షించండి",
|
||||
"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": "తెరవండి"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "ปิดกระทู้",
|
||||
"view_spoiler": "ดูสปอยล์เลอร์",
|
||||
"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": "เปิด"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "konuyu kapat",
|
||||
"view_spoiler": "spoileri görüntüle",
|
||||
"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ç"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "закрити тему",
|
||||
"view_spoiler": "переглянути спойлер",
|
||||
"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": "відкрити"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "موضوع بند کریں",
|
||||
"view_spoiler": "اسپوائلر دیکھیں",
|
||||
"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": "کھولیں"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "đóng chủ đề",
|
||||
"view_spoiler": "xem spoiler",
|
||||
"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ở"
|
||||
}
|
||||
@@ -148,5 +148,16 @@
|
||||
"close_thread": "关闭主题",
|
||||
"view_spoiler": "查看剧透",
|
||||
"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
@@ -1,6 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
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 useTheme from './hooks/use-theme';
|
||||
import styles from './app.module.css';
|
||||
@@ -21,6 +21,8 @@ const BoardLayout = () => {
|
||||
const { accountCommentIndex, subplebbitAddress } = useParams();
|
||||
const location = useLocation();
|
||||
const isMobile = useIsMobile();
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname);
|
||||
|
||||
const isValidAccountCommentIndex = !accountCommentIndex || (!isNaN(parseInt(accountCommentIndex)) && parseInt(accountCommentIndex) >= 0);
|
||||
|
||||
@@ -36,16 +38,16 @@ const BoardLayout = () => {
|
||||
<TopBar />
|
||||
<BoardHeader />
|
||||
{isMobile
|
||||
? subplebbitAddress && (
|
||||
? (subplebbitAddress || isInAllView || isInSubscriptionsView) && (
|
||||
<>
|
||||
<PostForm key={key} />
|
||||
<MobileBoardButtons />
|
||||
</>
|
||||
)
|
||||
: subplebbitAddress && (
|
||||
: (subplebbitAddress || isInAllView || isInSubscriptionsView) && (
|
||||
<>
|
||||
<PostForm key={key} />
|
||||
<SubplebbitStats />
|
||||
{!(isInAllView || isInSubscriptionsView) && <SubplebbitStats />}
|
||||
<DesktopBoardButtons />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -83,8 +83,8 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.post:hover .postMenu {
|
||||
visibility: visible;
|
||||
.postMenuVisible {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.loadingSkeleton {
|
||||
@@ -95,4 +95,37 @@
|
||||
|
||||
.fileDeleted {
|
||||
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);
|
||||
}
|
||||
@@ -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 { Comment } from '@plebbit/plebbit-react-hooks';
|
||||
import styles from './catalog-row.module.css';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
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 { getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isAllView } from '../../lib/utils/view-utils';
|
||||
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
||||
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 React, { useState } from 'react';
|
||||
import styles from './catalog-row.module.css';
|
||||
import _ from 'lodash';
|
||||
|
||||
interface CatalogPostMediaProps {
|
||||
commentMediaInfo: any;
|
||||
@@ -69,7 +73,7 @@ export const CatalogPostMedia = ({ commentMediaInfo, isOutOfFeed, linkWidth, lin
|
||||
|
||||
return (
|
||||
<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}
|
||||
</div>
|
||||
);
|
||||
@@ -77,7 +81,8 @@ export const CatalogPostMedia = ({ commentMediaInfo, isOutOfFeed, linkWidth, lin
|
||||
|
||||
const CatalogPost = ({ post }: { post: Comment }) => {
|
||||
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 hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
|
||||
@@ -95,38 +100,133 @@ const CatalogPost = ({ post }: { post: Comment }) => {
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.post}>
|
||||
{hasThumbnail ? (
|
||||
<Link to={postLink}>
|
||||
<div className={styles.mediaPaddingWrapper}>
|
||||
{threadIcons}
|
||||
<CatalogPostMedia commentMediaInfo={commentMediaInfo} isOutOfFeed={isDescription || isRules} linkWidth={linkWidth} linkHeight={linkHeight} />
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
threadIcons
|
||||
)}
|
||||
<div className={styles.meta}>
|
||||
R: <b>{replyCount || '0'}</b>
|
||||
{linkCount > 0 && (
|
||||
<span>
|
||||
{' '}
|
||||
/ L: <b>{linkCount}</b>
|
||||
</span>
|
||||
)}
|
||||
<span className={styles.postMenu}>
|
||||
<PostMenuDesktop post={post} />
|
||||
</span>
|
||||
</div>
|
||||
<Link to={postLink}>
|
||||
<div className={styles.teaser}>
|
||||
<b>{title && `${title}${content ? ': ' : ''}`}</b>
|
||||
{content}
|
||||
</div>
|
||||
</Link>
|
||||
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 (
|
||||
<>
|
||||
<div className={styles.post}>
|
||||
<div onMouseOver={() => setHoveredCid(cid)} onMouseLeave={() => setHoveredCid(null)}>
|
||||
{hasThumbnail ? (
|
||||
<Link to={postLink}>
|
||||
<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}
|
||||
<CatalogPostMedia commentMediaInfo={commentMediaInfo} isOutOfFeed={isDescription || isRules} linkWidth={linkWidth} linkHeight={linkHeight} />
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
threadIcons
|
||||
)}
|
||||
<div className={styles.meta}>
|
||||
R: <b>{replyCount || '0'}</b>
|
||||
{linkCount > 0 && (
|
||||
<span>
|
||||
{' '}
|
||||
/ L: <b>{linkCount}</b>
|
||||
</span>
|
||||
)}
|
||||
<span className={`${styles.postMenu} ${hoveredCid && styles.postMenuVisible}`}>
|
||||
<PostMenuDesktop post={post} />
|
||||
</span>
|
||||
</div>
|
||||
{hasThumbnail ? postContent : <Link to={postLink}>{postContent}</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,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface CatalogRowProps {
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.subplebbitAvatar {
|
||||
.floatingEmbed, .subplebbitAvatar {
|
||||
max-width: 250px;
|
||||
max-height: 250px;
|
||||
margin: 3px 20px 5px 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.subplebbitAvatar {
|
||||
margin: 3px 20px 5px 0;
|
||||
}
|
||||
|
||||
.spoiler {
|
||||
display: inline-block;
|
||||
margin: 3px 20px 5px 20px;
|
||||
@@ -131,4 +134,11 @@
|
||||
|
||||
.fileDeleted {
|
||||
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 {
|
||||
commentMediaInfo?: CommentMediaInfo;
|
||||
post?: Comment;
|
||||
isFloatingEmbed?: boolean;
|
||||
isReply?: boolean;
|
||||
linkHeight?: number;
|
||||
linkWidth?: number;
|
||||
@@ -18,11 +19,11 @@ interface MediaProps {
|
||||
setShowThumbnail: (showThumbnail: boolean) => void;
|
||||
}
|
||||
|
||||
const Thumbnail = ({ commentMediaInfo, post, setShowThumbnail }: MediaProps) => {
|
||||
const Thumbnail = ({ commentMediaInfo, isFloatingEmbed, post, setShowThumbnail }: MediaProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { deleted, linkHeight, linkWidth, parentCid, removed, spoiler } = post || {};
|
||||
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 isDeleted = deleted || removed;
|
||||
|
||||
@@ -84,7 +85,7 @@ const Thumbnail = ({ commentMediaInfo, post, setShowThumbnail }: MediaProps) =>
|
||||
<span className={styles.spoilerText}>[{t('view_spoiler')}]</span>
|
||||
</span>
|
||||
) : isOutOfFeed ? (
|
||||
<span className={styles.subplebbitAvatar}>{thumbnailComponent}</span>
|
||||
<span className={`${isFloatingEmbed ? styles.floatingEmbed : styles.subplebbitAvatar}`}>{thumbnailComponent}</span>
|
||||
) : isMobile || isReply ? (
|
||||
<span className={`${styles.thumbnailSmall} ${thumbnailSmallPadding}`} style={thumbnailDimensions}>
|
||||
{thumbnailComponent}
|
||||
@@ -135,7 +136,7 @@ const Media = ({ commentMediaInfo, isReply, setShowThumbnail }: MediaProps) => {
|
||||
)}
|
||||
{isMobile && (type === 'iframe' || type === 'video' || type === 'audio') && (
|
||||
<div className={styles.closeButton}>
|
||||
<span className='button' onClick={() => setShowThumbnail(true)}>
|
||||
<span className='button' onClick={() => setShowThumbnail(false)}>
|
||||
{t('close')}
|
||||
</span>
|
||||
</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 isMobile = useIsMobile();
|
||||
const { type, url } = commentMediaInfo || {};
|
||||
@@ -152,7 +153,7 @@ const CommentMedia = ({ commentMediaInfo, post, showThumbnail, setShowThumbnail
|
||||
return (
|
||||
<span className={styles.content}>
|
||||
<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>}
|
||||
</span>
|
||||
{!showThumbnail && <Media commentMediaInfo={commentMediaInfo} isReply={post?.parentCid} setShowThumbnail={setShowThumbnail} />}
|
||||
|
||||
@@ -38,4 +38,10 @@
|
||||
|
||||
.spoiler:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.floatingEmbed {
|
||||
background-color: #d6daf0;
|
||||
border: 1px solid #b7c5d9;
|
||||
padding: 2px;
|
||||
}
|
||||
@@ -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 remarkGfm from 'remark-gfm';
|
||||
import supersub from 'remark-supersub';
|
||||
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
|
||||
import styles from './markdown.module.css';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDismiss, useFloating, useFocus, useHover, useInteractions, offset, shift, size, autoUpdate, Placement, FloatingPortal } from '@floating-ui/react';
|
||||
import { getLinkMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import CommentMedia from '../comment-media';
|
||||
import styles from './markdown.module.css';
|
||||
|
||||
interface MarkdownProps {
|
||||
content: string;
|
||||
spoiler?: boolean;
|
||||
interface ContentLinkEmbedProps {
|
||||
children: any;
|
||||
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 blockquoteToGreentext = () => (tree: any) => {
|
||||
@@ -38,6 +120,11 @@ const blockquoteToGreentext = () => (tree: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
interface MarkdownProps {
|
||||
content: string;
|
||||
spoiler?: boolean;
|
||||
}
|
||||
|
||||
const Markdown = ({ content, spoiler }: MarkdownProps) => {
|
||||
const remarkPlugins: any[] = [[supersub]];
|
||||
|
||||
@@ -59,9 +146,6 @@ const Markdown = ({ content, spoiler }: MarkdownProps) => {
|
||||
|
||||
remarkPlugins.push([blockquoteToGreentext]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const [showMedia, setShowMedia] = useState(false);
|
||||
|
||||
return (
|
||||
<span className={styles.markdown}>
|
||||
<ReactMarkdown
|
||||
@@ -69,7 +153,7 @@ const Markdown = ({ content, spoiler }: MarkdownProps) => {
|
||||
remarkPlugins={remarkPlugins}
|
||||
rehypePlugins={[[rehypeSanitize, customSchema]]}
|
||||
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>,
|
||||
video: ({ src }) => <span>{src}</span>,
|
||||
iframe: ({ src }) => <span>{src}</span>,
|
||||
@@ -83,24 +167,7 @@ const Markdown = ({ content, spoiler }: MarkdownProps) => {
|
||||
if (href) {
|
||||
const linkMediaInfo = getLinkMediaInfo(href);
|
||||
if (getHasThumbnail(linkMediaInfo, href)) {
|
||||
return (
|
||||
<>
|
||||
<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} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return <ContentLinkEmbed children={children} href={href} linkMediaInfo={linkMediaInfo} />;
|
||||
} else {
|
||||
return (
|
||||
<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 styles from '../post.module.css';
|
||||
import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../../lib/utils/media-utils';
|
||||
import { getFormattedDate } from '../../../lib/utils/time-utils';
|
||||
import { isValidURL } from '../../../lib/utils/url-utils';
|
||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils';
|
||||
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 useStateString from '../../../hooks/use-state-string';
|
||||
import CommentMedia from '../../comment-media';
|
||||
@@ -20,6 +19,7 @@ import PostMenuDesktop from './post-menu-desktop/';
|
||||
import EditMenu from '../edit-menu/edit-menu';
|
||||
import ReplyQuotePreview from '../reply-quote-preview';
|
||||
import { PostProps } from '../post';
|
||||
import Timestamp from '../timestamp';
|
||||
import _ from 'lodash';
|
||||
|
||||
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>}
|
||||
</span>
|
||||
<span className={styles.dateTime}>
|
||||
{getFormattedDate(timestamp)}
|
||||
<Timestamp timestamp={timestamp} />
|
||||
{isDescription || isRules ? '' : ' '}
|
||||
</span>
|
||||
<span className={styles.postNum}>
|
||||
@@ -185,7 +185,7 @@ const PostMessage = ({ post }: PostProps) => {
|
||||
{removed ? (
|
||||
<span className={styles.removedContent}>({t('this_post_was_removed')})</span>
|
||||
) : 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} />
|
||||
)}
|
||||
@@ -232,7 +232,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
|
||||
// scroll to reply if pathname is reply permalink (backlink)
|
||||
const replyRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||||
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]) {
|
||||
replyRefs.current[replyIndex]?.scrollIntoView();
|
||||
}
|
||||
@@ -240,7 +240,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
|
||||
|
||||
return (
|
||||
<div className={styles.postDesktop}>
|
||||
{showAllReplies ? (
|
||||
{showReplies ? (
|
||||
<div className={styles.hrWrapper}>
|
||||
<hr />
|
||||
</div>
|
||||
@@ -248,7 +248,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
|
||||
<div className={styles.replyQuotePreviewSpacer} />
|
||||
)}
|
||||
<div className={isHidden ? styles.postDesktopBlocked : ''}>
|
||||
{!isInPostPageView && !isDescription && !isRules && (
|
||||
{!isInPostPageView && !isDescription && !isRules && showReplies && (
|
||||
<span className={styles.hideButtonWrapper}>
|
||||
<span className={`${styles.hideButton} ${blocked ? styles.unhideThread : styles.hideThread}`} onClick={blocked ? unblock : block} />
|
||||
</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 className={styles.replyDesktop}>
|
||||
<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} />
|
||||
{reply.link && isValidURL(reply.link) && <PostMedia post={reply} />}
|
||||
{reply.content && <PostMessage post={reply} />}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.postMenu {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { autoUpdate, flip, FloatingFocusManager, offset, shift, useClick, useDis
|
||||
import styles from './post-menu-mobile.module.css';
|
||||
import { getCommentMediaInfo } from '../../../../lib/utils/media-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';
|
||||
|
||||
interface PostMenuMobileProps {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { Comment, useAccount, useComment } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import styles from '../post.module.css';
|
||||
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 useCountLinksInReplies from '../../../hooks/use-count-links-in-replies';
|
||||
import useReplies from '../../../hooks/use-replies';
|
||||
@@ -16,6 +15,7 @@ import Markdown from '../../markdown';
|
||||
import ReplyQuotePreview from '../reply-quote-preview';
|
||||
import PostMenuMobile from './post-menu-mobile';
|
||||
import { PostProps } from '../post';
|
||||
import Timestamp from '../timestamp';
|
||||
import _ from 'lodash';
|
||||
|
||||
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>
|
||||
</div>
|
||||
)}
|
||||
{getFormattedDate(timestamp)}{' '}
|
||||
<Timestamp timestamp={timestamp} />{' '}
|
||||
{!(isDescription || isRules) && (
|
||||
<span className={styles.postNumLink}>
|
||||
<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 { 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 location = useLocation();
|
||||
@@ -145,7 +145,7 @@ const PostMessageMobile = ({ post }: PostProps) => {
|
||||
) : deleted ? (
|
||||
<span className={styles.removedContent}>{t('user_deleted_this_post')}</span>
|
||||
) : (
|
||||
<Markdown content={displayContent} />
|
||||
<Markdown content={displayContent} spoiler={spoiler} />
|
||||
)}
|
||||
{(removed || deleted) && reason && (
|
||||
<span>
|
||||
@@ -183,11 +183,10 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
|
||||
const linksCount = useCountLinksInReplies(post);
|
||||
const replies = useReplies(post);
|
||||
|
||||
// scroll to reply if pathname is reply permalink (backlink)
|
||||
const replyRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||||
|
||||
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]) {
|
||||
replyRefs.current[replyIndex]?.scrollIntoView();
|
||||
}
|
||||
@@ -195,18 +194,18 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
|
||||
|
||||
return (
|
||||
<div className={styles.postMobile}>
|
||||
{showAllReplies && (
|
||||
{showReplies && (
|
||||
<div className={styles.hrWrapper}>
|
||||
<hr />
|
||||
</div>
|
||||
)}
|
||||
<div className={showAllReplies ? styles.thread : styles.quotePreview}>
|
||||
<div className={showReplies ? styles.thread : styles.quotePreview}>
|
||||
<div className={styles.postContainer}>
|
||||
<div className={styles.postOp}>
|
||||
<PostInfoAndMedia openReplyModal={openReplyModal} post={post} roles={roles} />
|
||||
{content && <PostMessageMobile post={post} />}
|
||||
</div>
|
||||
{!isInPostView && !isInPendingPostView && (
|
||||
{!isInPostView && !isInPendingPostView && showReplies && (
|
||||
<div className={styles.postLink}>
|
||||
<span className={styles.info}>
|
||||
{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 className={styles.replyMobile}>
|
||||
<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} />
|
||||
{reply.content && <PostMessageMobile post={reply} />}
|
||||
<ReplyBacklinks post={reply} />
|
||||
|
||||
@@ -392,12 +392,15 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.removedContent {
|
||||
text-transform: uppercase;
|
||||
.removedContent, .deletedContent {
|
||||
font-weight: 700;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.removedContent {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.backlink, .backlinkHash {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Comment } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import { Comment, useAccount } from '@plebbit/plebbit-react-hooks';
|
||||
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
|
||||
import useIsMobile from '../../../hooks/use-is-mobile';
|
||||
import styles from '../post.module.css';
|
||||
@@ -15,8 +14,32 @@ interface ReplyQuotePreviewProps {
|
||||
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 [hoveredCid, setHoveredCid] = useState<string | null>(null);
|
||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||
const placementRef = useRef<Placement>('right');
|
||||
const availableWidthRef = useRef<number>(0);
|
||||
|
||||
@@ -56,18 +79,37 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
};
|
||||
}, [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 = (
|
||||
<>
|
||||
<Link
|
||||
className={styles.backlink}
|
||||
to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`}
|
||||
ref={refs.setReference}
|
||||
onMouseOver={() => setHoveredCid(backlinkReply?.cid)}
|
||||
onMouseLeave={() => setHoveredCid(null)}
|
||||
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
|
||||
>
|
||||
c/{backlinkReply?.shortCid}
|
||||
</Link>
|
||||
{hoveredCid === backlinkReply?.cid &&
|
||||
outOfViewCid === backlinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={backlinkReply} showReplies={false} />
|
||||
@@ -77,19 +119,23 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
</>
|
||||
);
|
||||
|
||||
const account = useAccount();
|
||||
|
||||
const replyQuotelink = (
|
||||
<>
|
||||
<Link
|
||||
to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}
|
||||
ref={refs.setReference}
|
||||
className={styles.quoteLink}
|
||||
onMouseOver={() => setHoveredCid(quotelinkReply?.cid)}
|
||||
onMouseLeave={() => setHoveredCid(null)}
|
||||
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
|
||||
>
|
||||
{`c/${quotelinkReply?.cid && Plebbit.getShortCid(quotelinkReply.cid)}`}
|
||||
{`c/${quotelinkReply?.shortCid}`}
|
||||
{quotelinkReply?.author?.address === account?.author?.address && ' (You)'}
|
||||
</Link>
|
||||
<br />
|
||||
{hoveredCid === quotelinkReply?.cid &&
|
||||
outOfViewCid === quotelinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={quotelinkReply} showReplies={false} />
|
||||
@@ -104,6 +150,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
|
||||
const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
|
||||
const [hoveredCid, setHoveredCid] = useState<string | null>(null);
|
||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||
|
||||
const { refs, floatingStyles, update } = useFloating({
|
||||
placement: 'bottom',
|
||||
@@ -118,15 +165,39 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
};
|
||||
}, [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 = (
|
||||
<>
|
||||
<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}{' '}
|
||||
</span>
|
||||
<Link to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} className={styles.backlinkHash}>
|
||||
#
|
||||
</Link>
|
||||
{hoveredCid === backlinkReply?.cid &&
|
||||
outOfViewCid === backlinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={backlinkReply} showReplies={false} />
|
||||
@@ -136,16 +207,26 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
</>
|
||||
);
|
||||
|
||||
const account = useAccount();
|
||||
|
||||
const replyQuotelink = (
|
||||
<>
|
||||
<span ref={refs.setReference} className={styles.quoteLink} onMouseOver={() => setHoveredCid(quotelinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}>
|
||||
c/{quotelinkReply?.shortCid}{' '}
|
||||
<span
|
||||
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>
|
||||
<Link className={styles.quoteLink} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}>
|
||||
{' '}
|
||||
#
|
||||
</Link>
|
||||
<br />
|
||||
{hoveredCid === quotelinkReply?.cid &&
|
||||
outOfViewCid === quotelinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={quotelinkReply} showReplies={false} />
|
||||
|
||||
@@ -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';
|
||||
|
||||
interface EditCommentPrivileges {
|
||||
interface AuthorPrivilegesProps {
|
||||
commentAuthorAddress: string;
|
||||
subplebbitAddress: string;
|
||||
}
|
||||
|
||||
const useEditCommentPrivileges = ({ commentAuthorAddress, subplebbitAddress }: EditCommentPrivileges) => {
|
||||
const useAuthorPrivileges = ({ commentAuthorAddress, subplebbitAddress }: AuthorPrivilegesProps) => {
|
||||
const accountAuthorAddress = useAccount()?.author?.address;
|
||||
const { roles } = useSubplebbit({ subplebbitAddress }) || {};
|
||||
|
||||
@@ -15,7 +15,7 @@ const useEditCommentPrivileges = ({ commentAuthorAddress, subplebbitAddress }: E
|
||||
const isAccountMod = accountAuthorRole === 'admin' || accountAuthorRole === 'owner' || accountAuthorRole === 'moderator';
|
||||
const isAccountCommentAuthor = accountAuthorAddress === commentAuthorAddress;
|
||||
|
||||
return { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor };
|
||||
return { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor, commentAuthorRole, accountAuthorRole };
|
||||
};
|
||||
|
||||
export default useEditCommentPrivileges;
|
||||
export default useAuthorPrivileges;
|
||||
@@ -10,9 +10,9 @@ const usePopularPosts = (subplebbits: Subplebbit[]) => {
|
||||
const allPosts: Comment[] = [];
|
||||
|
||||
let postsPerSub = 1;
|
||||
if (subplebbits.length == 2) {
|
||||
if (subplebbits.length === 2) {
|
||||
postsPerSub = 4;
|
||||
} else if (subplebbits.length == 3) {
|
||||
} else if (subplebbits.length === 3) {
|
||||
postsPerSub = 3;
|
||||
} else if (subplebbits.length >= 4 && subplebbits.length < 8) {
|
||||
postsPerSub = 2;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useMemo, useCallback } from 'react';
|
||||
import { Comment, useAccountComments } from '@plebbit/plebbit-react-hooks';
|
||||
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
|
||||
const flattenedReplies = useMemo(() => flattenCommentsPages(comment.replies), [comment.replies]);
|
||||
|
||||
@@ -45,4 +45,4 @@ const useRepliesAndAccountReplies = (comment: Comment) => {
|
||||
return repliesAndNotYetPublishedReplies;
|
||||
};
|
||||
|
||||
export default useRepliesAndAccountReplies;
|
||||
export default useReplies;
|
||||
|
||||
@@ -26,6 +26,42 @@ hr {
|
||||
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) {
|
||||
.button {
|
||||
font-size: var(--button-font-size-mobile);
|
||||
|
||||
@@ -33,3 +33,38 @@ export const getFormattedDate = (commentTimestamp: number) => {
|
||||
}
|
||||
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) });
|
||||
};
|
||||
|
||||
@@ -45,12 +45,13 @@ export const isRulesView = (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);
|
||||
return (
|
||||
decodedPathname === `/p/${subplebbitAddress}/c/${commentCid}/settings` ||
|
||||
decodedPathname === `/p/${subplebbitAddress}/description/settings` ||
|
||||
decodedPathname === `/p/${subplebbitAddress}/rules/settings`
|
||||
decodedPathname === `/p/${subplebbitAddress}/rules/settings` ||
|
||||
decodedPathname === `/profile/${accountCommentIndex}/settings`
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+33
-1
@@ -25,6 +25,12 @@
|
||||
--catalog-post-menu-desktop-btn-hover-color: red;
|
||||
--catalog-post-menu-desktop-btn-opacity: 0.5;
|
||||
--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-background-color: #f0e0d6;
|
||||
@@ -226,6 +232,11 @@
|
||||
--catalog-post-menu-desktop-btn-hover-color: #d00;
|
||||
--catalog-post-menu-desktop-btn-opacity: 0.5;
|
||||
--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-background-color: #d6daf0;
|
||||
@@ -421,6 +432,12 @@
|
||||
--catalog-post-menu-desktop-btn-hover-color: red;
|
||||
--catalog-post-menu-desktop-btn-opacity: 0.5;
|
||||
--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-background-color: #f0e0d6;
|
||||
@@ -590,6 +607,11 @@
|
||||
--catalog-post-menu-desktop-btn-hover-color: red;
|
||||
--catalog-post-menu-desktop-btn-opacity: 0.5;
|
||||
--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-background-color: #d6daf0;
|
||||
@@ -766,12 +788,18 @@
|
||||
--catalog-post-menu-desktop-btn-hover-color: #5f89ac;
|
||||
--catalog-post-menu-desktop-btn-opacity: 0.5;
|
||||
--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-background-color: #282a2e;
|
||||
--challenge-modal-border: 1px solid #111;
|
||||
--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-font-size: 10pt;
|
||||
--challenge-modal-title-font-weight: 700;
|
||||
@@ -969,6 +997,10 @@
|
||||
--catalog-post-menu-desktop-btn-hover-color: #f30;
|
||||
--catalog-post-menu-desktop-btn-opacity: 0.5;
|
||||
--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-background-color: #ddd;
|
||||
|
||||
@@ -197,7 +197,7 @@ const BoardsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[]; subplebb
|
||||
return (
|
||||
<div className={`${styles.box} ${styles.boardsBox}`}>
|
||||
<div className={styles.boxBar}>
|
||||
<h2 className={styles.capitalize}>{t('boards')}</h2>
|
||||
<h2 className='capitalize'>{t('boards')}</h2>
|
||||
<BoxModal isBoardsBoxModal={true} />
|
||||
</div>
|
||||
<div className={styles.boardsBoxContent}>
|
||||
|
||||
@@ -150,10 +150,6 @@
|
||||
content: '✔ ';
|
||||
}
|
||||
|
||||
.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.list a {
|
||||
color: var(--homepage-box-link-text-color);
|
||||
text-decoration: var(--homepage-box-link-text-decoration);
|
||||
|
||||
@@ -88,7 +88,7 @@ const Stats = ({ multisub, subplebbitAddresses }: { multisub: any; subplebbitAdd
|
||||
return (
|
||||
<div className={styles.box}>
|
||||
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
||||
<h2 className={styles.capitalize}>{t('stats')}</h2>
|
||||
<h2 className='capitalize'>{t('stats')}</h2>
|
||||
</div>
|
||||
<div className={`${styles.boxContent} ${enoughStats ? styles.stats : ''}`}>
|
||||
{enoughStats ? (
|
||||
@@ -143,7 +143,7 @@ const Footer = () => {
|
||||
</a>
|
||||
</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
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -63,7 +63,7 @@ const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[];
|
||||
return (
|
||||
<div className={styles.box}>
|
||||
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
||||
<h2 className={styles.capitalize}>{t('popular_threads')}</h2>
|
||||
<h2 className='capitalize'>{t('popular_threads')}</h2>
|
||||
<BoxModal isBoardsBoxModal={false} />
|
||||
</div>
|
||||
<div className={`${styles.boxContent} ${popularPosts.length === 8 ? styles.popularThreads : ''}`}>
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
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 { isSettingsView } from '../../lib/utils/view-utils';
|
||||
import Post from '../../components/post';
|
||||
import SettingsModal from '../../components/settings-modal';
|
||||
|
||||
const PendingPost = () => {
|
||||
const { accountCommentIndex } = useParams<{ accountCommentIndex?: string }>();
|
||||
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
|
||||
const post = useAccountComment({ commentIndex });
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const isInSettingsView = isSettingsView(location.pathname, params);
|
||||
|
||||
useEffect(() => window.scrollTo(0, 0), []);
|
||||
|
||||
@@ -17,7 +22,12 @@ const PendingPost = () => {
|
||||
}
|
||||
}, [post, navigate]);
|
||||
|
||||
return <Post post={post} />;
|
||||
return (
|
||||
<>
|
||||
{isInSettingsView && <SettingsModal />}
|
||||
<Post post={post} showReplies={false} />;
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PendingPost;
|
||||
|
||||
Reference in New Issue
Block a user