diff --git a/public/translations/ar/default.json b/public/translations/ar/default.json index 5468a70e..35143b13 100644 --- a/public/translations/ar/default.json +++ b/public/translations/ar/default.json @@ -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": "فتح" } \ No newline at end of file diff --git a/public/translations/bn/default.json b/public/translations/bn/default.json index 0e1bacf1..77ee0266 100644 --- a/public/translations/bn/default.json +++ b/public/translations/bn/default.json @@ -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": "খুলুন" } \ No newline at end of file diff --git a/public/translations/cs/default.json b/public/translations/cs/default.json index d7513ff4..a8adf654 100644 --- a/public/translations/cs/default.json +++ b/public/translations/cs/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/da/default.json b/public/translations/da/default.json index 943201a0..8698e067 100644 --- a/public/translations/da/default.json +++ b/public/translations/da/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/de/default.json b/public/translations/de/default.json index 6c071bc6..c2b93b71 100644 --- a/public/translations/de/default.json +++ b/public/translations/de/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/el/default.json b/public/translations/el/default.json index 7a4d04af..67c75a5a 100644 --- a/public/translations/el/default.json +++ b/public/translations/el/default.json @@ -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": "ανοικτό" } \ No newline at end of file diff --git a/public/translations/en/default.json b/public/translations/en/default.json index 4f44f528..257c4e19 100644 --- a/public/translations/en/default.json +++ b/public/translations/en/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/es/default.json b/public/translations/es/default.json index 02d0f10c..d00027f5 100644 --- a/public/translations/es/default.json +++ b/public/translations/es/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/fa/default.json b/public/translations/fa/default.json index 15d8aac7..853da3b1 100644 --- a/public/translations/fa/default.json +++ b/public/translations/fa/default.json @@ -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": "باز کردن" } \ No newline at end of file diff --git a/public/translations/fi/default.json b/public/translations/fi/default.json index efaf244a..2543a863 100644 --- a/public/translations/fi/default.json +++ b/public/translations/fi/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/fil/default.json b/public/translations/fil/default.json index 4e100d83..9513962e 100644 --- a/public/translations/fil/default.json +++ b/public/translations/fil/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/fr/default.json b/public/translations/fr/default.json index 181b41bd..b8d41811 100644 --- a/public/translations/fr/default.json +++ b/public/translations/fr/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/he/default.json b/public/translations/he/default.json index 53d94cc5..93748454 100644 --- a/public/translations/he/default.json +++ b/public/translations/he/default.json @@ -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": "לפתוח" } \ No newline at end of file diff --git a/public/translations/hi/default.json b/public/translations/hi/default.json index e7a8fd70..a9263349 100644 --- a/public/translations/hi/default.json +++ b/public/translations/hi/default.json @@ -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": "खोलें" } \ No newline at end of file diff --git a/public/translations/hu/default.json b/public/translations/hu/default.json index d28f4bde..3f30df50 100644 --- a/public/translations/hu/default.json +++ b/public/translations/hu/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/id/default.json b/public/translations/id/default.json index 057ae59f..17aef358 100644 --- a/public/translations/id/default.json +++ b/public/translations/id/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/it/default.json b/public/translations/it/default.json index acae16c1..58d54e49 100644 --- a/public/translations/it/default.json +++ b/public/translations/it/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/ja/default.json b/public/translations/ja/default.json index 0fcec985..03b72bdf 100644 --- a/public/translations/ja/default.json +++ b/public/translations/ja/default.json @@ -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": "開く" } \ No newline at end of file diff --git a/public/translations/ko/default.json b/public/translations/ko/default.json index e933a350..3e11fa24 100644 --- a/public/translations/ko/default.json +++ b/public/translations/ko/default.json @@ -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": "열기" } \ No newline at end of file diff --git a/public/translations/mr/default.json b/public/translations/mr/default.json index 4c8c9501..b4daa7bd 100644 --- a/public/translations/mr/default.json +++ b/public/translations/mr/default.json @@ -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": "उघडा" } \ No newline at end of file diff --git a/public/translations/nl/default.json b/public/translations/nl/default.json index 9e1fa096..e7917b3b 100644 --- a/public/translations/nl/default.json +++ b/public/translations/nl/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/no/default.json b/public/translations/no/default.json index 8f1d6f74..834919ca 100644 --- a/public/translations/no/default.json +++ b/public/translations/no/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/pl/default.json b/public/translations/pl/default.json index 60396994..1fe47c61 100644 --- a/public/translations/pl/default.json +++ b/public/translations/pl/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/pt/default.json b/public/translations/pt/default.json index 8569b299..aa6e2925 100644 --- a/public/translations/pt/default.json +++ b/public/translations/pt/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/ro/default.json b/public/translations/ro/default.json index 9eb8de50..a04f133c 100644 --- a/public/translations/ro/default.json +++ b/public/translations/ro/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/ru/default.json b/public/translations/ru/default.json index 3c3ba51e..5b66383c 100644 --- a/public/translations/ru/default.json +++ b/public/translations/ru/default.json @@ -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": "открыть" } \ No newline at end of file diff --git a/public/translations/sq/default.json b/public/translations/sq/default.json index 5af61728..ce9fef24 100644 --- a/public/translations/sq/default.json +++ b/public/translations/sq/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/sv/default.json b/public/translations/sv/default.json index c62474e2..092e4336 100644 --- a/public/translations/sv/default.json +++ b/public/translations/sv/default.json @@ -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" } \ No newline at end of file diff --git a/public/translations/te/default.json b/public/translations/te/default.json index 22a39f5f..214ff344 100644 --- a/public/translations/te/default.json +++ b/public/translations/te/default.json @@ -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": "తెరవండి" } \ No newline at end of file diff --git a/public/translations/th/default.json b/public/translations/th/default.json index dcd1242c..ff3a3b1d 100644 --- a/public/translations/th/default.json +++ b/public/translations/th/default.json @@ -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": "เปิด" } \ No newline at end of file diff --git a/public/translations/tr/default.json b/public/translations/tr/default.json index 3db66cf7..3f250145 100644 --- a/public/translations/tr/default.json +++ b/public/translations/tr/default.json @@ -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ç" } \ No newline at end of file diff --git a/public/translations/uk/default.json b/public/translations/uk/default.json index c0b4e7b0..1ffe4b5a 100644 --- a/public/translations/uk/default.json +++ b/public/translations/uk/default.json @@ -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": "відкрити" } \ No newline at end of file diff --git a/public/translations/ur/default.json b/public/translations/ur/default.json index 1d7038ba..71cc12bb 100644 --- a/public/translations/ur/default.json +++ b/public/translations/ur/default.json @@ -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": "کھولیں" } \ No newline at end of file diff --git a/public/translations/vi/default.json b/public/translations/vi/default.json index 0bc003fe..cd0d8ce9 100644 --- a/public/translations/vi/default.json +++ b/public/translations/vi/default.json @@ -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ở" } \ No newline at end of file diff --git a/public/translations/zh/default.json b/public/translations/zh/default.json index 1a6d9e23..83a3dbe6 100644 --- a/public/translations/zh/default.json +++ b/public/translations/zh/default.json @@ -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": "打开" } \ No newline at end of file diff --git a/src/app.tsx b/src/app.tsx index 9d8fa691..4bc0d54e 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -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 = () => { {isMobile - ? subplebbitAddress && ( + ? (subplebbitAddress || isInAllView || isInSubscriptionsView) && ( <> ) - : subplebbitAddress && ( + : (subplebbitAddress || isInAllView || isInSubscriptionsView) && ( <> - + {!(isInAllView || isInSubscriptionsView) && } )} diff --git a/src/components/catalog-row/catalog-row.module.css b/src/components/catalog-row/catalog-row.module.css index e97bb7c5..66259f7e 100644 --- a/src/components/catalog-row/catalog-row.module.css +++ b/src/components/catalog-row/catalog-row.module.css @@ -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); } \ No newline at end of file diff --git a/src/components/catalog-row/catalog-row.tsx b/src/components/catalog-row/catalog-row.tsx index 85c92292..05f102f2 100644 --- a/src/components/catalog-row/catalog-row.tsx +++ b/src/components/catalog-row/catalog-row.tsx @@ -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 (
- {!isLoaded && !hasError && type !== 'video' && } + {!isLoaded && !hasError && type !== 'video' && type !== 'audio' && } {hasError ? File deleted : thumbnailComponent}
); @@ -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 }) => { ); - return ( -
- {hasThumbnail ? ( - -
- {threadIcons} - -
- - ) : ( - threadIcons - )} -
- R: {replyCount || '0'} - {linkCount > 0 && ( - - {' '} - / L: {linkCount} - - )} - - - -
- -
- {title && `${title}${content ? ': ' : ''}`} - {content} -
- + const [hoveredCid, setHoveredCid] = useState(null); + const [showPortal, setShowPortal] = useState(false); + const placementRef = useRef('right-start'); + const availableWidthRef = useRef(0); + const timeoutRef = useRef(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 = ( +
+ {title && `${title}${content ? ': ' : ''}`} + {content}
); + + return ( + <> +
+
setHoveredCid(cid)} onMouseLeave={() => setHoveredCid(null)}> + {hasThumbnail ? ( + +
(timeoutRef.current = setTimeout(() => setShowPortal(true), 250))} + onMouseLeave={() => { + setShowPortal(false); + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + }} + > + {threadIcons} + +
+ + ) : ( + threadIcons + )} +
+ R: {replyCount || '0'} + {linkCount > 0 && ( + + {' '} + / L: {linkCount} + + )} + + + +
+ {hasThumbnail ? postContent : {postContent}} +
+
+ {hoveredCid === cid && + showPortal && + createPortal( +
+ {title} + {' by '} + + {author?.displayName || _.capitalize(t('anonymous'))} + {isCatalogPostAuthorMod && {` ## Board ${catalogPostAuthorRole}`}} + + {getFormattedTimeAgo(timestamp)} + {replyCount > 0 && ( +
+ Last reply by{' '} + + {lastReply?.author?.displayName || _.capitalize(t('anonymous'))} + {isLastReplyAuthorMod && ` ## Board ${lastReplyAuthorRole}`} + + {getFormattedTimeAgo(lastReply?.timestamp)} +
+ )} +
, + document.body, + )} + + ); }; interface CatalogRowProps { diff --git a/src/components/comment-media/comment-media.module.css b/src/components/comment-media/comment-media.module.css index dc952788..749db0a5 100644 --- a/src/components/comment-media/comment-media.module.css +++ b/src/components/comment-media/comment-media.module.css @@ -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 */ + } } \ No newline at end of file diff --git a/src/components/comment-media/comment-media.tsx b/src/components/comment-media/comment-media.tsx index caa8715b..4852da36 100644 --- a/src/components/comment-media/comment-media.tsx +++ b/src/components/comment-media/comment-media.tsx @@ -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) => [{t('view_spoiler')}] ) : isOutOfFeed ? ( - {thumbnailComponent} + {thumbnailComponent} ) : isMobile || isReply ? ( {thumbnailComponent} @@ -135,7 +136,7 @@ const Media = ({ commentMediaInfo, isReply, setShowThumbnail }: MediaProps) => { )} {isMobile && (type === 'iframe' || type === 'video' || type === 'audio') && (
- setShowThumbnail(true)}> + setShowThumbnail(false)}> {t('close')}
@@ -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 ( - {url && } + {url && } {isMobile && type &&
{getDisplayMediaInfoType(type, t)}
}
{!showThumbnail && } diff --git a/src/components/markdown/markdown.module.css b/src/components/markdown/markdown.module.css index bfdb899c..21dcafb5 100644 --- a/src/components/markdown/markdown.module.css +++ b/src/components/markdown/markdown.module.css @@ -38,4 +38,10 @@ .spoiler:hover { color: white; +} + +.floatingEmbed { + background-color: #d6daf0; + border: 1px solid #b7c5d9; + padding: 2px; } \ No newline at end of file diff --git a/src/components/markdown/markdown.tsx b/src/components/markdown/markdown.tsx index 1ac29608..84a3ecf5 100644 --- a/src/components/markdown/markdown.tsx +++ b/src/components/markdown/markdown.tsx @@ -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('right'); + const availableWidthRef = useRef(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 ( + <> + + {children} + {' '} + [ + setShowMedia(!showMedia)} ref={refs.setReference} {...getReferenceProps()}> + {showMedia ? t('remove') : isMobile ? t('open') : t('embed')} + + ] + {showMedia && ( + <> +
+ + + )} + + {isOpen && !isMobile && ( +
+ +
+ )} +
+ + ); +}; + 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 ( { remarkPlugins={remarkPlugins} rehypePlugins={[[rehypeSanitize, customSchema]]} components={{ - p: ({ children }) =>

{spoiler ? {children} : children}

, + p: ({ children }) =>

{spoiler ? {children} : children}

, img: ({ src }) => {src}, video: ({ src }) => {src}, iframe: ({ src }) => {src}, @@ -83,24 +167,7 @@ const Markdown = ({ content, spoiler }: MarkdownProps) => { if (href) { const linkMediaInfo = getLinkMediaInfo(href); if (getHasThumbnail(linkMediaInfo, href)) { - return ( - <> - - {children} - {' '} - [ - setShowMedia(!showMedia)}> - {showMedia ? t('remove') : t('embed')} - - ] - {showMedia && ( - <> -
- - - )} - - ); + return ; } else { return ( diff --git a/src/components/post/post-desktop/post-desktop.tsx b/src/components/post/post-desktop/post-desktop.tsx index eca9442c..eab6903c 100644 --- a/src/components/post/post-desktop/post-desktop.tsx +++ b/src/components/post/post-desktop/post-desktop.tsx @@ -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) && (u/{shortAddress || accountShortAddress}) }
- {getFormattedDate(timestamp)} + {isDescription || isRules ? '' : ' '} @@ -185,7 +185,7 @@ const PostMessage = ({ post }: PostProps) => { {removed ? ( ({t('this_post_was_removed')}) ) : deleted ? ( - {t('user_deleted_this_post')} + {t('user_deleted_this_post')} ) : ( )} @@ -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 (
- {showAllReplies ? ( + {showReplies ? (

@@ -248,7 +248,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
)}
- {!isInPostPageView && !isDescription && !isRules && ( + {!isInPostPageView && !isDescription && !isRules && showReplies && ( @@ -287,7 +287,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
(replyRefs.current[index] = el)}>
{'>>'}
-
+
{reply.link && isValidURL(reply.link) && } {reply.content && } diff --git a/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.module.css b/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.module.css index 3f962756..02d261a2 100644 --- a/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.module.css +++ b/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.module.css @@ -10,6 +10,7 @@ font-weight: 700; font-size: 16px; height: 100%; + cursor: pointer; } .postMenu { diff --git a/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.tsx b/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.tsx index 18d3aef6..75bd5c94 100644 --- a/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.tsx +++ b/src/components/post/post-mobile/post-menu-mobile/post-menu-mobile.tsx @@ -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 { diff --git a/src/components/post/post-mobile/post-mobile.tsx b/src/components/post/post-mobile/post-mobile.tsx index 61b19dc7..1bd0ac7f 100644 --- a/src/components/post/post-mobile/post-mobile.tsx +++ b/src/components/post/post-mobile/post-mobile.tsx @@ -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) => { p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}
)} - {getFormattedDate(timestamp)}{' '} + {' '} {!(isDescription || isRules) && ( !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 ? ( {t('user_deleted_this_post')} ) : ( - + )} {(removed || deleted) && reason && ( @@ -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 (
- {showAllReplies && ( + {showReplies && (

)} -
+
{content && }
- {!isInPostView && !isInPendingPostView && ( + {!isInPostView && !isInPendingPostView && showReplies && (
{replyCount > 0 && `${replyCount} Replies`} @@ -233,7 +232,7 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
(replyRefs.current[index] = el)}>
-
+
{reply.content && } diff --git a/src/components/post/post.module.css b/src/components/post/post.module.css index 25993960..0a9acdfa 100644 --- a/src/components/post/post.module.css +++ b/src/components/post/post.module.css @@ -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; } diff --git a/src/components/post/reply-quote-preview/reply-quote-preview.tsx b/src/components/post/reply-quote-preview/reply-quote-preview.tsx index c01fa8b0..3873fca4 100644 --- a/src/components/post/reply-quote-preview/reply-quote-preview.tsx +++ b/src/components/post/reply-quote-preview/reply-quote-preview.tsx @@ -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(null); + const [outOfViewCid, setOutOfViewCid] = useState(null); const placementRef = useRef('right'); const availableWidthRef = useRef(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 = ( <> setHoveredCid(backlinkReply?.cid)} - onMouseLeave={() => setHoveredCid(null)} + onMouseOver={() => handleMouseOver(backlinkReply?.cid)} + onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)} > c/{backlinkReply?.shortCid} {hoveredCid === backlinkReply?.cid && + outOfViewCid === backlinkReply?.cid && createPortal(
@@ -77,19 +119,23 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i ); + const account = useAccount(); + const replyQuotelink = ( <> 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)'}
{hoveredCid === quotelinkReply?.cid && + outOfViewCid === quotelinkReply?.cid && createPortal(
@@ -104,6 +150,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => { const [hoveredCid, setHoveredCid] = useState(null); + const [outOfViewCid, setOutOfViewCid] = useState(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 = ( <> - setHoveredCid(backlinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> + handleMouseOver(backlinkReply?.cid)} + onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)} + > c/{backlinkReply?.shortCid}{' '} # {hoveredCid === backlinkReply?.cid && + outOfViewCid === backlinkReply?.cid && createPortal(
@@ -136,16 +207,26 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is ); + const account = useAccount(); + const replyQuotelink = ( <> - setHoveredCid(quotelinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> - c/{quotelinkReply?.shortCid}{' '} + handleMouseOver(quotelinkReply?.cid)} + onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)} + > + c/{quotelinkReply?.shortCid} + {quotelinkReply?.author?.address === account?.author?.address && ' (You)'} + {' '} #
{hoveredCid === quotelinkReply?.cid && + outOfViewCid === quotelinkReply?.cid && createPortal(
diff --git a/src/components/post/timestamp/index.ts b/src/components/post/timestamp/index.ts new file mode 100644 index 00000000..8fe28740 --- /dev/null +++ b/src/components/post/timestamp/index.ts @@ -0,0 +1 @@ +export { default } from './timestamp'; diff --git a/src/components/post/timestamp/timestamp.tsx b/src/components/post/timestamp/timestamp.tsx new file mode 100644 index 00000000..d5b71828 --- /dev/null +++ b/src/components/post/timestamp/timestamp.tsx @@ -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 ( + <> + + {getFormattedDate(timestamp)} + + + {isOpen && ( +
+ {getFormattedTimeAgo(timestamp)} +
+ )} +
+ + ); +}; + +export default Timestamp; diff --git a/src/hooks/use-edit-comment-privileges.ts b/src/hooks/use-author-privileges.ts similarity index 78% rename from src/hooks/use-edit-comment-privileges.ts rename to src/hooks/use-author-privileges.ts index 92b43b8c..09b40d08 100644 --- a/src/hooks/use-edit-comment-privileges.ts +++ b/src/hooks/use-author-privileges.ts @@ -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; diff --git a/src/hooks/use-popular-posts.ts b/src/hooks/use-popular-posts.ts index 65360890..d8aa7e42 100644 --- a/src/hooks/use-popular-posts.ts +++ b/src/hooks/use-popular-posts.ts @@ -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; diff --git a/src/hooks/use-replies.ts b/src/hooks/use-replies.ts index 6af6b66b..bc59fc0a 100644 --- a/src/hooks/use-replies.ts +++ b/src/hooks/use-replies.ts @@ -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; diff --git a/src/index.css b/src/index.css index 938cfbd0..d62858cd 100644 --- a/src/index.css +++ b/src/index.css @@ -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); diff --git a/src/lib/utils/time-utils.ts b/src/lib/utils/time-utils.ts index 05ca793b..5c332bd8 100644 --- a/src/lib/utils/time-utils.ts +++ b/src/lib/utils/time-utils.ts @@ -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) }); +}; diff --git a/src/lib/utils/view-utils.ts b/src/lib/utils/view-utils.ts index 080d19ec..a990c9c5 100644 --- a/src/lib/utils/view-utils.ts +++ b/src/lib/utils/view-utils.ts @@ -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` ); }; diff --git a/src/themes.css b/src/themes.css index 83197713..54c95b97 100644 --- a/src/themes.css +++ b/src/themes.css @@ -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; diff --git a/src/views/home/boards-box/boards-box.tsx b/src/views/home/boards-box/boards-box.tsx index ee7ce7aa..aef5bbed 100644 --- a/src/views/home/boards-box/boards-box.tsx +++ b/src/views/home/boards-box/boards-box.tsx @@ -197,7 +197,7 @@ const BoardsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[]; subplebb return (
-

{t('boards')}

+

{t('boards')}

diff --git a/src/views/home/home.module.css b/src/views/home/home.module.css index 0bad3b19..a7855eba 100644 --- a/src/views/home/home.module.css +++ b/src/views/home/home.module.css @@ -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); diff --git a/src/views/home/home.tsx b/src/views/home/home.tsx index 84456ae4..3c61045d 100644 --- a/src/views/home/home.tsx +++ b/src/views/home/home.tsx @@ -88,7 +88,7 @@ const Stats = ({ multisub, subplebbitAddresses }: { multisub: any; subplebbitAdd return (
-

{t('stats')}

+

{t('stats')}

{enoughStats ? ( @@ -143,7 +143,7 @@ const Footer = () => {
  • - + Twitter
  • diff --git a/src/views/home/popular-threads-box/popular-threads-box.tsx b/src/views/home/popular-threads-box/popular-threads-box.tsx index 76b13a1e..338dc4c8 100644 --- a/src/views/home/popular-threads-box/popular-threads-box.tsx +++ b/src/views/home/popular-threads-box/popular-threads-box.tsx @@ -63,7 +63,7 @@ const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[]; return (
    -

    {t('popular_threads')}

    +

    {t('popular_threads')}

    diff --git a/src/views/pending-post/pending-post.tsx b/src/views/pending-post/pending-post.tsx index 0aab5e3b..4b25fd9c 100644 --- a/src/views/pending-post/pending-post.tsx +++ b/src/views/pending-post/pending-post.tsx @@ -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 ; + return ( + <> + {isInSettingsView && } + ; + + ); }; export default PendingPost;