mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
@@ -28,6 +28,7 @@
|
||||
"prettier": "3.0.3",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-draggable": "^4.4.6",
|
||||
"react-i18next": "13.2.2",
|
||||
"react-markdown": "8.0.6",
|
||||
"react-router-dom": "6.16.0",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="serverless, adminless, decentralized 4chan alternative" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "الرد على هذه المشاركة",
|
||||
"sticky": "مثبت",
|
||||
"closed": "مغلق",
|
||||
"reply": "رد",
|
||||
"reply": "الرد",
|
||||
"link": "رابط",
|
||||
"close": "إغلاق",
|
||||
"post_a_reply": "أضف ردًا",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "القاع",
|
||||
"top": "أعلى",
|
||||
"thread_closed": "تم إغلاق الموضوع.",
|
||||
"may_not_reply": "قد لا تتم الرد في هذا الوقت."
|
||||
"may_not_reply": "قد لا تتم الرد في هذا الوقت.",
|
||||
"post": "نشر",
|
||||
"name": "الاسم",
|
||||
"comment": "تعليق",
|
||||
"subject": "الموضوع",
|
||||
"anonymous": "مجهول"
|
||||
}
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "নীচে",
|
||||
"top": "শীর্ষ",
|
||||
"thread_closed": "থ্রেড বন্ধ হয়েছে।",
|
||||
"may_not_reply": "এই সময়ে আপনি প্রতিক্রিয়া দিতে পারবেন না।"
|
||||
"may_not_reply": "এই সময়ে আপনি প্রতিক্রিয়া দিতে পারবেন না।",
|
||||
"post": "পোস্ট",
|
||||
"name": "নাম",
|
||||
"comment": "মন্তব্য",
|
||||
"subject": "বিষয়",
|
||||
"anonymous": "অজানা"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Odpovědět na tento příspěvek",
|
||||
"sticky": "Připnutý",
|
||||
"closed": "Zavřeno",
|
||||
"reply": "Odpovědět",
|
||||
"reply": "odpovědět",
|
||||
"link": "Odkaz",
|
||||
"close": "Zavřít",
|
||||
"post_a_reply": "Zveřejnit Odpověď",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Dno",
|
||||
"top": "Nahoře",
|
||||
"thread_closed": "Vlákno uzavřeno.",
|
||||
"may_not_reply": "V tuto chvíli nemůžete odpovědět."
|
||||
"may_not_reply": "V tuto chvíli nemůžete odpovědět.",
|
||||
"post": "odeslat",
|
||||
"name": "název",
|
||||
"comment": "komentář",
|
||||
"subject": "předmět",
|
||||
"anonymous": "anonymní"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Svar på dette indlæg",
|
||||
"sticky": "Fikseret",
|
||||
"closed": "Lukket",
|
||||
"reply": "Svar",
|
||||
"reply": "besvar",
|
||||
"link": "Link",
|
||||
"close": "Luk",
|
||||
"post_a_reply": "Indsend Et Svar",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Bund",
|
||||
"top": "Top",
|
||||
"thread_closed": "Tråd lukket.",
|
||||
"may_not_reply": "Du kan muligvis ikke svare på dette tidspunkt."
|
||||
"may_not_reply": "Du kan muligvis ikke svare på dette tidspunkt.",
|
||||
"post": "send",
|
||||
"name": "navn",
|
||||
"comment": "kommentar",
|
||||
"subject": "emne",
|
||||
"anonymous": "anonym"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Antworten auf diesen Beitrag",
|
||||
"sticky": "Angeheftet",
|
||||
"closed": "Geschlossen",
|
||||
"reply": "Antworten",
|
||||
"reply": "antworten",
|
||||
"link": "Link",
|
||||
"close": "Schließen",
|
||||
"post_a_reply": "Eine Antwort Posten",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Unten",
|
||||
"top": "Oben",
|
||||
"thread_closed": "Thread geschlossen.",
|
||||
"may_not_reply": "Sie können möglicherweise zu diesem Zeitpunkt nicht antworten."
|
||||
"may_not_reply": "Sie können möglicherweise zu diesem Zeitpunkt nicht antworten.",
|
||||
"post": "posten",
|
||||
"name": "Name",
|
||||
"comment": "Kommentar",
|
||||
"subject": "Betreff",
|
||||
"anonymous": "anonym"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Απάντηση σε αυτήν την ανάρτηση",
|
||||
"sticky": "Κολλημένος",
|
||||
"closed": "Κλειστό",
|
||||
"reply": "Απάντηση",
|
||||
"reply": "απάντηση",
|
||||
"link": "Σύνδεσμος",
|
||||
"close": "Κλείσιμο",
|
||||
"post_a_reply": "Δημοσίευση Απάντησης",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Κάτω",
|
||||
"top": "Κορυφή",
|
||||
"thread_closed": "Το νήμα έκλεισε.",
|
||||
"may_not_reply": "Μπορεί να μην μπορείτε να απαντήσετε αυτή τη στιγμή."
|
||||
"may_not_reply": "Μπορεί να μην μπορείτε να απαντήσετε αυτή τη στιγμή.",
|
||||
"post": "δημοσίευση",
|
||||
"name": "όνομα",
|
||||
"comment": "σχόλιο",
|
||||
"subject": "θέμα",
|
||||
"anonymous": "ανώνυμος"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Reply to this post",
|
||||
"sticky": "Sticky",
|
||||
"closed": "Closed",
|
||||
"reply": "Reply",
|
||||
"reply": "reply",
|
||||
"link": "Link",
|
||||
"close": "Close",
|
||||
"post_a_reply": "Post a Reply",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Bottom",
|
||||
"top": "Top",
|
||||
"thread_closed": "Thread closed.",
|
||||
"may_not_reply": "You may not reply at this time."
|
||||
"may_not_reply": "You may not reply at this time.",
|
||||
"post": "post",
|
||||
"name": "name",
|
||||
"comment": "comment",
|
||||
"subject": "subject",
|
||||
"anonymous": "anonymous"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Responder a esta publicación",
|
||||
"sticky": "Fijado",
|
||||
"closed": "Cerrado",
|
||||
"reply": "Responder",
|
||||
"reply": "responder",
|
||||
"link": "Enlace",
|
||||
"close": "Cerrar",
|
||||
"post_a_reply": "Publicar una Respuesta",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Fondo",
|
||||
"top": "Arriba",
|
||||
"thread_closed": "Hilo cerrado.",
|
||||
"may_not_reply": "Es posible que no puedas responder en este momento."
|
||||
"may_not_reply": "Es posible que no puedas responder en este momento.",
|
||||
"post": "publicar",
|
||||
"name": "nombre",
|
||||
"comment": "comentario",
|
||||
"subject": "asunto",
|
||||
"anonymous": "anónimo"
|
||||
}
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "پایین",
|
||||
"top": "بالا",
|
||||
"thread_closed": "موضوع بسته شده است.",
|
||||
"may_not_reply": "شما ممکن است در این زمان پاسخ ندهید."
|
||||
"may_not_reply": "شما ممکن است در این زمان پاسخ ندهید.",
|
||||
"post": "پست",
|
||||
"name": "نام",
|
||||
"comment": "نظر",
|
||||
"subject": "موضوع",
|
||||
"anonymous": "ناشناس"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Vastaa tähän viestiin",
|
||||
"sticky": "Tikki",
|
||||
"closed": "Suljettu",
|
||||
"reply": "Vastaa",
|
||||
"reply": "vastata",
|
||||
"link": "Linkki",
|
||||
"close": "Sulje",
|
||||
"post_a_reply": "Lähetä Vastaus",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Pohja",
|
||||
"top": "Ylös",
|
||||
"thread_closed": "Keskustelu suljettu.",
|
||||
"may_not_reply": "Et ehkä voi vastata tällä hetkellä."
|
||||
"may_not_reply": "Et ehkä voi vastata tällä hetkellä.",
|
||||
"post": "lähetä",
|
||||
"name": "nimi",
|
||||
"comment": "kommentti",
|
||||
"subject": "aihe",
|
||||
"anonymous": "anonyymi"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Tumugon sa post na ito",
|
||||
"sticky": "Malagkit",
|
||||
"closed": "Sarado",
|
||||
"reply": "Tumugon",
|
||||
"reply": "sumagot",
|
||||
"link": "Link",
|
||||
"close": "Isara",
|
||||
"post_a_reply": "Mag-post ng Isang Tugon",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Ilalim",
|
||||
"top": "Itaas",
|
||||
"thread_closed": "Thread na isara.",
|
||||
"may_not_reply": "Hindi ka maaaring mag-reply sa oras na ito."
|
||||
"may_not_reply": "Hindi ka maaaring mag-reply sa oras na ito.",
|
||||
"post": "mag-post",
|
||||
"name": "pangalan",
|
||||
"comment": "komento",
|
||||
"subject": "paksa",
|
||||
"anonymous": "anonimo"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Répondre à ce message",
|
||||
"sticky": "Épinglé",
|
||||
"closed": "Fermé",
|
||||
"reply": "Répondre",
|
||||
"reply": "répondre",
|
||||
"link": "Lien",
|
||||
"close": "Fermer",
|
||||
"post_a_reply": "Publier une Réponse",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Bas",
|
||||
"top": "Haut",
|
||||
"thread_closed": "Fil fermé.",
|
||||
"may_not_reply": "Vous ne pouvez peut-être pas répondre en ce moment."
|
||||
"may_not_reply": "Vous ne pouvez peut-être pas répondre en ce moment.",
|
||||
"post": "poster",
|
||||
"name": "nom",
|
||||
"comment": "commentaire",
|
||||
"subject": "sujet",
|
||||
"anonymous": "anonyme"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "הגבה להודעה זו",
|
||||
"sticky": "מדבקה",
|
||||
"closed": "סגור",
|
||||
"reply": "הגב",
|
||||
"reply": "להגיב",
|
||||
"link": "קישור",
|
||||
"close": "סגור",
|
||||
"post_a_reply": "פרסם תגובה",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "תחתית",
|
||||
"top": "עליון",
|
||||
"thread_closed": "השרשור נסגר.",
|
||||
"may_not_reply": "אולי אינך יכול להגיב כרגע."
|
||||
"may_not_reply": "אולי אינך יכול להגיב כרגע.",
|
||||
"post": "לפרסם",
|
||||
"name": "שם",
|
||||
"comment": "תגובה",
|
||||
"subject": "נושא",
|
||||
"anonymous": "אנונימי"
|
||||
}
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "नीचे",
|
||||
"top": "ऊपर",
|
||||
"thread_closed": "थ्रेड बंद हो गया।",
|
||||
"may_not_reply": "इस समय आप जवाब नहीं दे सकते।"
|
||||
"may_not_reply": "इस समय आप जवाब नहीं दे सकते।",
|
||||
"post": "पोस्ट",
|
||||
"name": "नाम",
|
||||
"comment": "टिप्पणी",
|
||||
"subject": "विषय",
|
||||
"anonymous": "अनाम"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Válasz erre a hozzászólásra",
|
||||
"sticky": "Rögzített",
|
||||
"closed": "Zárt",
|
||||
"reply": "Válaszolás",
|
||||
"reply": "válasz",
|
||||
"link": "Hivatkozás",
|
||||
"close": "Bezárás",
|
||||
"post_a_reply": "Válasz Postázása",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Alja",
|
||||
"top": "Felső",
|
||||
"thread_closed": "A téma lezárult.",
|
||||
"may_not_reply": "Jelenleg nem válaszolhatsz erre."
|
||||
"may_not_reply": "Jelenleg nem válaszolhatsz erre.",
|
||||
"post": "posta",
|
||||
"name": "név",
|
||||
"comment": "megjegyzés",
|
||||
"subject": "tárgy",
|
||||
"anonymous": "névtelen"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Balas ke pos ini",
|
||||
"sticky": "Menempel",
|
||||
"closed": "Tutup",
|
||||
"reply": "Balas",
|
||||
"reply": "balas",
|
||||
"link": "Tautan",
|
||||
"close": "Tutup",
|
||||
"post_a_reply": "Kirim Balasan",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Bawah",
|
||||
"top": "Atas",
|
||||
"thread_closed": "Benang ditutup.",
|
||||
"may_not_reply": "Anda mungkin tidak bisa membalas pada saat ini."
|
||||
"may_not_reply": "Anda mungkin tidak bisa membalas pada saat ini.",
|
||||
"post": "posting",
|
||||
"name": "nama",
|
||||
"comment": "komentar",
|
||||
"subject": "subjek",
|
||||
"anonymous": "anonim"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Commenta questo post",
|
||||
"sticky": "Incollato",
|
||||
"closed": "Chiuso",
|
||||
"reply": "Commenta",
|
||||
"reply": "rispondi",
|
||||
"link": "Link",
|
||||
"close": "Chiudi",
|
||||
"post_a_reply": "Invia un Commento",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Vai sotto",
|
||||
"top": "Vai sopra",
|
||||
"thread_closed": "Thread chiuso.",
|
||||
"may_not_reply": "Non puoi rispondere in questo momento."
|
||||
"may_not_reply": "Non puoi rispondere in questo momento.",
|
||||
"post": "invia",
|
||||
"name": "nome",
|
||||
"comment": "commento",
|
||||
"subject": "oggetto",
|
||||
"anonymous": "anonimo"
|
||||
}
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "下へ",
|
||||
"top": "上へ",
|
||||
"thread_closed": "スレッドが閉じられました。",
|
||||
"may_not_reply": "現在、返信することはできません。"
|
||||
"may_not_reply": "現在、返信することはできません。",
|
||||
"post": "投稿",
|
||||
"name": "名前",
|
||||
"comment": "コメント",
|
||||
"subject": "件名",
|
||||
"anonymous": "匿名"
|
||||
}
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "하단",
|
||||
"top": "맨 위로",
|
||||
"thread_closed": "스레드가 닫혔습니다.",
|
||||
"may_not_reply": "현재 시간에는 답글을 달 수 없습니다."
|
||||
"may_not_reply": "현재 시간에는 답글을 달 수 없습니다.",
|
||||
"post": "게시",
|
||||
"name": "이름",
|
||||
"comment": "댓글",
|
||||
"subject": "제목",
|
||||
"anonymous": "익명"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "या पोस्टवर प्रतिसाद द्या",
|
||||
"sticky": "स्टिकी",
|
||||
"closed": "बंद",
|
||||
"reply": "प्रतिसाद",
|
||||
"reply": "प्रत्युत्तर",
|
||||
"link": "लिंक",
|
||||
"close": "बंद करा",
|
||||
"post_a_reply": "उत्तर पोस्ट करा",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "खाली",
|
||||
"top": "वर",
|
||||
"thread_closed": "सूत्र बंद झाला.",
|
||||
"may_not_reply": "हा वेळ उत्तर देण्यास शक्य नाही."
|
||||
"may_not_reply": "हा वेळ उत्तर देण्यास शक्य नाही.",
|
||||
"post": "पोस्ट",
|
||||
"name": "नाव",
|
||||
"comment": "टिप्पणी",
|
||||
"subject": "विषय",
|
||||
"anonymous": "अनाम"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Reageren op dit bericht",
|
||||
"sticky": "Vastgemaakt",
|
||||
"closed": "Gesloten",
|
||||
"reply": "Antwoord",
|
||||
"reply": "antwoorden",
|
||||
"link": "Link",
|
||||
"close": "Sluiten",
|
||||
"post_a_reply": "Een Antwoord Plaatsen",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Onderkant",
|
||||
"top": "Boven",
|
||||
"thread_closed": "Thread gesloten.",
|
||||
"may_not_reply": "U kunt op dit moment mogelijk niet antwoorden."
|
||||
"may_not_reply": "U kunt op dit moment mogelijk niet antwoorden.",
|
||||
"post": "plaatsen",
|
||||
"name": "naam",
|
||||
"comment": "opmerking",
|
||||
"subject": "onderwerp",
|
||||
"anonymous": "anoniem"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Svar på dette innlegget",
|
||||
"sticky": "Klistret",
|
||||
"closed": "Stengt",
|
||||
"reply": "Svar",
|
||||
"reply": "svare",
|
||||
"link": "Lenke",
|
||||
"close": "Lukk",
|
||||
"post_a_reply": "Legg Inn Et Svar",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Bunnen",
|
||||
"top": "Topp",
|
||||
"thread_closed": "Tråd stengt.",
|
||||
"may_not_reply": "Du kan kanskje ikke svare på dette tidspunktet."
|
||||
"may_not_reply": "Du kan kanskje ikke svare på dette tidspunktet.",
|
||||
"post": "poste",
|
||||
"name": "navn",
|
||||
"comment": "kommentar",
|
||||
"subject": "emne",
|
||||
"anonymous": "anonym"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Odpowiedz na ten post",
|
||||
"sticky": "Przyklejony",
|
||||
"closed": "Zamknięty",
|
||||
"reply": "Odpowiedz",
|
||||
"reply": "odpowiedź",
|
||||
"link": "Link",
|
||||
"close": "Zamknij",
|
||||
"post_a_reply": "Opublikuj Odpowiedź",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Dół",
|
||||
"top": "Góra",
|
||||
"thread_closed": "Wątek zamknięty.",
|
||||
"may_not_reply": "Może nie możesz teraz odpowiedzieć."
|
||||
"may_not_reply": "Może nie możesz teraz odpowiedzieć.",
|
||||
"post": "postać",
|
||||
"name": "nazwa",
|
||||
"comment": "komentarz",
|
||||
"subject": "temat",
|
||||
"anonymous": "anonimowy"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Responder a esta postagem",
|
||||
"sticky": "Fixado",
|
||||
"closed": "Fechado",
|
||||
"reply": "Responder",
|
||||
"reply": "responder",
|
||||
"link": "Link",
|
||||
"close": "Fechar",
|
||||
"post_a_reply": "Publicar uma Resposta",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Fundo",
|
||||
"top": "Topo",
|
||||
"thread_closed": "Tópico fechado.",
|
||||
"may_not_reply": "Você pode não conseguir responder neste momento."
|
||||
"may_not_reply": "Você pode não conseguir responder neste momento.",
|
||||
"post": "postar",
|
||||
"name": "nome",
|
||||
"comment": "comentário",
|
||||
"subject": "assunto",
|
||||
"anonymous": "anônimo"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Răspunde la acest mesaj",
|
||||
"sticky": "Lipit",
|
||||
"closed": "Închis",
|
||||
"reply": "Răspunde",
|
||||
"reply": "răspunde",
|
||||
"link": "Legătură",
|
||||
"close": "Închide",
|
||||
"post_a_reply": "Postează un Răspuns",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Partea de jos",
|
||||
"top": "Sus",
|
||||
"thread_closed": "Thread închis.",
|
||||
"may_not_reply": "Poate că nu puteți răspunde în acest moment."
|
||||
"may_not_reply": "Poate că nu puteți răspunde în acest moment.",
|
||||
"post": "posta",
|
||||
"name": "nume",
|
||||
"comment": "comentariu",
|
||||
"subject": "subiect",
|
||||
"anonymous": "anonim"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Ответить на это сообщение",
|
||||
"sticky": "Прикреплено",
|
||||
"closed": "Закрыто",
|
||||
"reply": "Ответить",
|
||||
"reply": "ответить",
|
||||
"link": "Ссылка",
|
||||
"close": "Закрыть",
|
||||
"post_a_reply": "Опубликовать Ответ",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Низ",
|
||||
"top": "Верх",
|
||||
"thread_closed": "Тема закрыта.",
|
||||
"may_not_reply": "Вы можете не ответить в это время."
|
||||
"may_not_reply": "Вы можете не ответить в это время.",
|
||||
"post": "разместить",
|
||||
"name": "имя",
|
||||
"comment": "комментарий",
|
||||
"subject": "тема",
|
||||
"anonymous": "анонимный"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Përgjigju në këtë postim",
|
||||
"sticky": "Ngjitës",
|
||||
"closed": "Mbyllur",
|
||||
"reply": "Përgjigju",
|
||||
"reply": "përgjigju",
|
||||
"link": "Lidhje",
|
||||
"close": "Mbylle",
|
||||
"post_a_reply": "Posto një Përgjigje",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Fund",
|
||||
"top": "Sipër",
|
||||
"thread_closed": "Fjala është e mbyllur.",
|
||||
"may_not_reply": "Nuk mund të përgjigjeni në këtë kohë."
|
||||
"may_not_reply": "Nuk mund të përgjigjeni në këtë kohë.",
|
||||
"post": "postë",
|
||||
"name": "emri",
|
||||
"comment": "koment",
|
||||
"subject": "subjekt",
|
||||
"anonymous": "anonim"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Svara på detta inlägg",
|
||||
"sticky": "Klistrad",
|
||||
"closed": "Stängd",
|
||||
"reply": "Svara",
|
||||
"reply": "svara",
|
||||
"link": "Länk",
|
||||
"close": "Stäng",
|
||||
"post_a_reply": "Posta Ett Svar",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Botten",
|
||||
"top": "Topp",
|
||||
"thread_closed": "Tråd stängd.",
|
||||
"may_not_reply": "Du kanske inte kan svara vid den här tiden."
|
||||
"may_not_reply": "Du kanske inte kan svara vid den här tiden.",
|
||||
"post": "skicka",
|
||||
"name": "namn",
|
||||
"comment": "kommentar",
|
||||
"subject": "ämne",
|
||||
"anonymous": "anonym"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "ఈ పోస్టుకు మరియుని జవాబు ఇవ్వండి",
|
||||
"sticky": "స్టికీ",
|
||||
"closed": "మూసివేయబడినది",
|
||||
"reply": "స్పందించు",
|
||||
"reply": "సమాధానం",
|
||||
"link": "లింక్",
|
||||
"close": "మూసి",
|
||||
"post_a_reply": "స్పందించండి",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "కిందకు",
|
||||
"top": "మేలే",
|
||||
"thread_closed": "థ్రెడ్ మూసివేయబడింది.",
|
||||
"may_not_reply": "ఈ సమయంలో మీరు ప్రతిసారం ఇవ్వలేరు."
|
||||
"may_not_reply": "ఈ సమయంలో మీరు ప్రతిసారం ఇవ్వలేరు.",
|
||||
"post": "పోస్ట్",
|
||||
"name": "పేరు",
|
||||
"comment": "వ్యాఖ్య",
|
||||
"subject": "విషయం",
|
||||
"anonymous": "అనామధుడు"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "ตอบกลับไปยังโพสต์นี้",
|
||||
"sticky": "ปักหมุด",
|
||||
"closed": "ปิด",
|
||||
"reply": "ตอบ",
|
||||
"reply": "ตอบกลับ",
|
||||
"link": "ลิงก์",
|
||||
"close": "ปิด",
|
||||
"post_a_reply": "โพสต์คำตอบ",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "ด้านล่าง",
|
||||
"top": "ด้านบน",
|
||||
"thread_closed": "เธรดถูกปิด",
|
||||
"may_not_reply": "คุณอาจไม่สามารถตอบกลับได้ในขณะนี้"
|
||||
"may_not_reply": "คุณอาจไม่สามารถตอบกลับได้ในขณะนี้",
|
||||
"post": "โพสต์",
|
||||
"name": "ชื่อ",
|
||||
"comment": "ความคิดเห็น",
|
||||
"subject": "หัวข้อ",
|
||||
"anonymous": "นิรนาม"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Bu gönderiye yanıtla",
|
||||
"sticky": "Yapışkan",
|
||||
"closed": "Kapalı",
|
||||
"reply": "Yanıtla",
|
||||
"reply": "yanıtla",
|
||||
"link": "Bağlantı",
|
||||
"close": "Kapat",
|
||||
"post_a_reply": "Yanıtı Yayınla",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Alt",
|
||||
"top": "Üst",
|
||||
"thread_closed": "Konu kapatıldı.",
|
||||
"may_not_reply": "Şu anda cevap veremeyebilirsiniz."
|
||||
"may_not_reply": "Şu anda cevap veremeyebilirsiniz.",
|
||||
"post": "posta",
|
||||
"name": "isim",
|
||||
"comment": "yorum",
|
||||
"subject": "konu",
|
||||
"anonymous": "anonim"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Відповісти на це повідомлення",
|
||||
"sticky": "Прикріплений",
|
||||
"closed": "Закрито",
|
||||
"reply": "Відповісти",
|
||||
"reply": "відповісти",
|
||||
"link": "Посилання",
|
||||
"close": "Закрити",
|
||||
"post_a_reply": "Опублікувати Відповідь",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Низ",
|
||||
"top": "Верхній",
|
||||
"thread_closed": "Тема закрита.",
|
||||
"may_not_reply": "Можливо, ви не зможете відповісти зараз."
|
||||
"may_not_reply": "Можливо, ви не зможете відповісти зараз.",
|
||||
"post": "пост",
|
||||
"name": "ім'я",
|
||||
"comment": "коментар",
|
||||
"subject": "тема",
|
||||
"anonymous": "анонім"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "اس پوسٹ کا جواب دیں",
|
||||
"sticky": "چسپی",
|
||||
"closed": "بند",
|
||||
"reply": "جواب دیں",
|
||||
"reply": "جواب",
|
||||
"link": "لنک",
|
||||
"close": "بند کریں",
|
||||
"post_a_reply": "ایک جواب بھیجیں",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "نیچے",
|
||||
"top": "اوپر",
|
||||
"thread_closed": "موضوع بند کر دیا گیا ہے۔",
|
||||
"may_not_reply": "آپ اس وقت جواب نہیں دے سکتے۔"
|
||||
"may_not_reply": "آپ اس وقت جواب نہیں دے سکتے۔",
|
||||
"post": "پوسٹ",
|
||||
"name": "نام",
|
||||
"comment": "تبصرہ",
|
||||
"subject": "موضوع",
|
||||
"anonymous": "ناشناس"
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"reply_to_post": "Trả lời bài viết này",
|
||||
"sticky": "Dán",
|
||||
"closed": "Đóng",
|
||||
"reply": "Trả lời",
|
||||
"reply": "trả lời",
|
||||
"link": "Liên kết",
|
||||
"close": "Đóng",
|
||||
"post_a_reply": "Đăng Một Câu Trả Lời",
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "Đáy",
|
||||
"top": "Đầu",
|
||||
"thread_closed": "Chủ đề đã đóng.",
|
||||
"may_not_reply": "Bạn có thể không thể trả lời vào thời điểm này."
|
||||
"may_not_reply": "Bạn có thể không thể trả lời vào thời điểm này.",
|
||||
"post": "đăng",
|
||||
"name": "tên",
|
||||
"comment": "bình luận",
|
||||
"subject": "chủ đề",
|
||||
"anonymous": "ẩn danh"
|
||||
}
|
||||
@@ -43,5 +43,10 @@
|
||||
"bottom": "底部",
|
||||
"top": "顶部",
|
||||
"thread_closed": "主题已关闭。",
|
||||
"may_not_reply": "您现在可能无法回复。"
|
||||
"may_not_reply": "您现在可能无法回复。",
|
||||
"post": "发布",
|
||||
"name": "名字",
|
||||
"comment": "评论",
|
||||
"subject": "主题",
|
||||
"anonymous": "匿名"
|
||||
}
|
||||
+7
-1
@@ -18,18 +18,24 @@ import PostForm from './components/post-form';
|
||||
|
||||
const BoardLayout = () => {
|
||||
const { subplebbitAddress } = useParams();
|
||||
const location = useLocation();
|
||||
|
||||
// force rerender of post form when navigating between pages
|
||||
const key = `${subplebbitAddress}-${location.pathname}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<BoardNav />
|
||||
<BoardBanner />
|
||||
<MobileBoardButtons />
|
||||
<PostForm key={subplebbitAddress} />
|
||||
<PostForm key={key} />
|
||||
<SubplebbitStats />
|
||||
<DesktopBoardButtons />
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const location = useLocation();
|
||||
const isInHomeView = isHomeView(location.pathname);
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
.container {
|
||||
position: fixed;
|
||||
top: calc(50% - 150px);
|
||||
left: calc(50% - 150px);
|
||||
display: block;
|
||||
padding: 2px;
|
||||
font-size: 10pt;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
z-index: 1000;
|
||||
background-color: var(--challenge-modal-background-color);
|
||||
border: var(--challenge-modal-border);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: var(--challenge-modal-title-font-size);
|
||||
text-align: center;
|
||||
margin-bottom: 1px;
|
||||
padding: 0;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
cursor: move;
|
||||
font-weight: var(--challenge-modal-title-font-weight);
|
||||
background-color: var(--challenge-modal-title-background-color);
|
||||
color: var(--challenge-modal-title-text-color);
|
||||
border: var(--challenge-modal-title-border);
|
||||
}
|
||||
|
||||
.closeIcon {
|
||||
all: unset;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
margin-bottom: -4px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: none;
|
||||
image-rendering: pixelated;
|
||||
background-image: var(--close-button-background-image);
|
||||
}
|
||||
|
||||
.container input, .container textarea {
|
||||
border: 1px solid #aaa;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 10pt;
|
||||
outline: medium none;
|
||||
width: 298px;
|
||||
filter: var(--filter80);
|
||||
padding: 2px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.content textarea {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.challengeAnswer {
|
||||
font-size: 11px !important;
|
||||
padding: 0px 2px;
|
||||
font-family: monospace !important;
|
||||
}
|
||||
|
||||
.challengeMediaWrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.challengeFooter {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.challengeFooter button {
|
||||
margin: 5px 5px 0 0;
|
||||
cursor: pointer;
|
||||
filter: var(--filter80);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import { useState } from 'react';
|
||||
import Draggable from 'react-draggable';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Challenge as ChallengeType } from '@plebbit/plebbit-react-hooks';
|
||||
import { getPublicationType } from '../../lib/utils/challenge-utils';
|
||||
import useChallenges from '../../hooks/use-challenges';
|
||||
import styles from './challenge-modal.module.css';
|
||||
|
||||
interface ChallengeProps {
|
||||
challenge: ChallengeType;
|
||||
closeModal: () => void;
|
||||
}
|
||||
|
||||
const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const challenges = challenge?.[0]?.challenges;
|
||||
const publication = challenge?.[1];
|
||||
|
||||
const publicationType = getPublicationType(publication);
|
||||
const { author, content, link, title } = publication || {};
|
||||
const { displayName } = author || {};
|
||||
|
||||
const [currentChallengeIndex, setCurrentChallengeIndex] = useState(0);
|
||||
const [answers, setAnswers] = useState<string[]>([]);
|
||||
|
||||
const isTextChallenge = challenges[currentChallengeIndex].type === 'text/plain';
|
||||
const isImageChallenge = challenges[currentChallengeIndex].type === 'image/png';
|
||||
|
||||
const onAnswersChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setAnswers((prevAnswers) => {
|
||||
const updatedAnswers = [...prevAnswers];
|
||||
updatedAnswers[currentChallengeIndex] = e.target.value;
|
||||
return updatedAnswers;
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
publication.publishChallengeAnswers(answers);
|
||||
setAnswers([]);
|
||||
closeModal();
|
||||
};
|
||||
|
||||
const onEnterKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key !== 'Enter') return;
|
||||
if (challenges[currentChallengeIndex + 1]) {
|
||||
setCurrentChallengeIndex((prev) => prev + 1);
|
||||
} else {
|
||||
onSubmit();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Draggable handle='.challengeHandle'>
|
||||
<div className={styles.container}>
|
||||
<div className={`challengeHandle ${styles.title}`}>
|
||||
Challenge for {publicationType}
|
||||
<button className={styles.closeIcon} onClick={closeModal} title='close' />
|
||||
</div>
|
||||
<div className={styles.publication}>
|
||||
<div className={styles.name}>
|
||||
<input type='text' value={displayName || 'Anonymous'} disabled />
|
||||
</div>
|
||||
{title && (
|
||||
<div className={styles.subject}>
|
||||
<input type='text' value={title} disabled />
|
||||
</div>
|
||||
)}
|
||||
{content && (
|
||||
<div className={styles.content}>
|
||||
<textarea value={content} disabled cols={48} rows={4} wrap='soft' />
|
||||
</div>
|
||||
)}
|
||||
{link && (
|
||||
<div className={styles.link}>
|
||||
<input type='text' value={link} disabled />
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.challengeContainer}>
|
||||
<input
|
||||
className={styles.challengeAnswer}
|
||||
type='text'
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
spellCheck='false'
|
||||
placeholder='TYPE THE ANSWER HERE AND PRESS ENTER'
|
||||
onKeyDown={onEnterKey}
|
||||
onChange={onAnswersChange}
|
||||
value={answers[currentChallengeIndex] || ''}
|
||||
autoFocus
|
||||
/>
|
||||
<div className={styles.challengeMediaWrapper}>
|
||||
{isTextChallenge && <div className={styles.challengeMedia}>{challenges[currentChallengeIndex]?.challenge}</div>}
|
||||
{isImageChallenge && (
|
||||
<img alt={t('loading')} className={styles.challengeMedia} src={`data:image/png;base64,${challenges[currentChallengeIndex]?.challenge}`} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.challengeFooter}>
|
||||
<div className={styles.counter}>{t('challenge_counter', { index: currentChallengeIndex + 1, total: challenges?.length })}</div>
|
||||
<span className={styles.buttons}>
|
||||
{!challenges[currentChallengeIndex + 1] && <button onClick={onSubmit}>{t('submit')}</button>}
|
||||
{challenges.length > 1 && (
|
||||
<button disabled={!challenges[currentChallengeIndex - 1]} onClick={() => setCurrentChallengeIndex((prev) => prev - 1)}>
|
||||
{t('previous')}
|
||||
</button>
|
||||
)}
|
||||
{challenges[currentChallengeIndex + 1] && <button onClick={() => setCurrentChallengeIndex((prev) => prev + 1)}>{t('next')}</button>}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Draggable>
|
||||
);
|
||||
};
|
||||
|
||||
const ChallengeModal = () => {
|
||||
const { challenges, removeChallenge } = useChallenges();
|
||||
const isOpen = !!challenges.length;
|
||||
const closeModal = () => removeChallenge();
|
||||
|
||||
return isOpen && <Challenge challenge={challenges[0]} closeModal={closeModal} />;
|
||||
};
|
||||
|
||||
export default ChallengeModal;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './challenge-modal';
|
||||
@@ -8,12 +8,8 @@
|
||||
text-decoration: var(--post-content-link-text-decoration-hover);
|
||||
}
|
||||
|
||||
.markdown ol {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.markdown ul {
|
||||
padding-left: 40px;
|
||||
.markdown li {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
.hrWrapper {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
padding: var(--post-form-field-title-padding);
|
||||
font-size: var(--post-form-field-title-font-size);
|
||||
width: 80px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.postFormTable td {
|
||||
@@ -78,7 +79,11 @@
|
||||
|
||||
.postFormTable button {
|
||||
margin-left: 2px;
|
||||
bottom: 0px;
|
||||
filter: var(--filter80);
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.linkType {
|
||||
|
||||
@@ -1,11 +1,57 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { useAccount, useComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { PublishCommentOptions, setAccount, useAccount, useAccountComment, useComment, usePublishComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { create } from 'zustand';
|
||||
import styles from './post-form.module.css';
|
||||
import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils';
|
||||
import { getLinkMediaInfo } from '../../lib/utils/media-utils';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isDescriptionView, isPostPageView, isRulesView } from '../../lib/utils/view-utils';
|
||||
import styles from './post-form.module.css';
|
||||
import challengesStore from '../../hooks/use-challenges';
|
||||
import useReply from '../../hooks/use-reply';
|
||||
import _ from 'lodash';
|
||||
|
||||
type SubmitState = {
|
||||
subplebbitAddress: string | undefined;
|
||||
title: string | undefined;
|
||||
content: string | undefined;
|
||||
link: string | undefined;
|
||||
publishCommentOptions: PublishCommentOptions;
|
||||
setSubmitStore: (data: Partial<SubmitState>) => void;
|
||||
resetSubmitStore: () => void;
|
||||
};
|
||||
|
||||
const { addChallenge } = challengesStore.getState();
|
||||
|
||||
const useSubmitStore = create<SubmitState>((set) => ({
|
||||
subplebbitAddress: undefined,
|
||||
title: undefined,
|
||||
content: undefined,
|
||||
link: undefined,
|
||||
publishCommentOptions: {},
|
||||
setSubmitStore: ({ subplebbitAddress, title, content, link }) =>
|
||||
set((state) => {
|
||||
const nextState = { ...state };
|
||||
if (subplebbitAddress !== undefined) nextState.subplebbitAddress = subplebbitAddress;
|
||||
if (title !== undefined) nextState.title = title || undefined;
|
||||
if (content !== undefined) nextState.content = content || undefined;
|
||||
if (link !== undefined) nextState.link = link || undefined;
|
||||
|
||||
nextState.publishCommentOptions = {
|
||||
...nextState,
|
||||
onChallenge: (...args: any) => addChallenge(args),
|
||||
onChallengeVerification: alertChallengeVerificationFailed,
|
||||
onError: (error: Error) => {
|
||||
console.error(error);
|
||||
let errorMessage = error.message;
|
||||
alert(errorMessage);
|
||||
},
|
||||
};
|
||||
return nextState;
|
||||
}),
|
||||
resetSubmitStore: () => set({ subplebbitAddress: undefined, title: undefined, content: undefined, link: undefined, publishCommentOptions: {} }),
|
||||
}));
|
||||
|
||||
const LinkTypePreviewer = ({ link }: { link: string }) => {
|
||||
const mediaInfo = getLinkMediaInfo(link);
|
||||
@@ -13,41 +59,140 @@ const LinkTypePreviewer = ({ link }: { link: string }) => {
|
||||
};
|
||||
|
||||
const PostFormTable = () => {
|
||||
const { t } = useTranslation();
|
||||
const account = useAccount();
|
||||
const { displayName } = account || {};
|
||||
const { displayName } = account?.author || {};
|
||||
|
||||
const [link, setLink] = useState('');
|
||||
const [url, setUrl] = useState('');
|
||||
|
||||
const { title, content, link, publishCommentOptions, setSubmitStore, resetSubmitStore } = useSubmitStore();
|
||||
|
||||
const { index, publishComment } = usePublishComment(publishCommentOptions);
|
||||
|
||||
const onPublishPost = () => {
|
||||
if (!title && !content && !link) {
|
||||
alert(`Cannot post empty comment`);
|
||||
return;
|
||||
}
|
||||
if (link && !isValidURL(link)) {
|
||||
alert(`Invalid link`);
|
||||
return;
|
||||
}
|
||||
|
||||
publishComment();
|
||||
};
|
||||
|
||||
const params = useParams();
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
useEffect(() => {
|
||||
if (subplebbitAddress) {
|
||||
setSubmitStore({ subplebbitAddress });
|
||||
}
|
||||
}, [subplebbitAddress, setSubmitStore]);
|
||||
|
||||
// redirect to pending page when pending comment is created
|
||||
const navigate = useNavigate();
|
||||
useEffect(() => {
|
||||
if (typeof index === 'number') {
|
||||
resetSubmitStore();
|
||||
navigate(`/profile/${index}`);
|
||||
}
|
||||
}, [index, resetSubmitStore, navigate]);
|
||||
|
||||
// in post page, publish a reply to the post
|
||||
const location = useLocation();
|
||||
const isInPostPage = isPostPageView(location.pathname, params);
|
||||
const cid = params?.commentCid as string;
|
||||
const { setContent, resetContent, replyIndex, publishReply } = useReply({ cid, subplebbitAddress });
|
||||
|
||||
const textRef = useRef<HTMLTextAreaElement>(null);
|
||||
const urlRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const onPublishReply = () => {
|
||||
const currentContent = textRef.current?.value || '';
|
||||
const currentUrl = urlRef.current?.value || '';
|
||||
|
||||
if (!currentContent.trim() && !currentUrl) {
|
||||
alert(`Cannot post empty comment`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentUrl && !isValidURL(currentUrl)) {
|
||||
alert('The provided link is not a valid URL.');
|
||||
return;
|
||||
}
|
||||
publishReply();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof replyIndex === 'number') {
|
||||
resetContent();
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
}
|
||||
}, [replyIndex, resetContent]);
|
||||
|
||||
return (
|
||||
<table className={styles.postFormTable}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>{t('name')}</td>
|
||||
<td>
|
||||
<input type='text' placeholder={!displayName ? 'Anonymous' : undefined} defaultValue={displayName || undefined} />
|
||||
<input
|
||||
type='text'
|
||||
placeholder={!displayName ? _.capitalize(t('anonymous')) : undefined}
|
||||
defaultValue={displayName || undefined}
|
||||
onChange={(e) => setAccount({ ...account, author: { ...account?.author, displayName: e.target.value } })}
|
||||
/>
|
||||
{isInPostPage && <button onClick={onPublishReply}>{t('post')}</button>}
|
||||
</td>
|
||||
</tr>
|
||||
{!isInPostPage && (
|
||||
<tr>
|
||||
<td>{t('subject')}</td>
|
||||
<td>
|
||||
<input
|
||||
type='text'
|
||||
onChange={(e) => {
|
||||
setSubmitStore({ title: e.target.value });
|
||||
}}
|
||||
/>
|
||||
<button onClick={onPublishPost}>{t('post')}</button>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
<tr>
|
||||
<td>{t('comment')}</td>
|
||||
<td>
|
||||
<textarea
|
||||
cols={48}
|
||||
rows={4}
|
||||
wrap='soft'
|
||||
ref={textRef}
|
||||
onChange={(e) => {
|
||||
isInPostPage ? setContent.content(e.target.value) : setSubmitStore({ content: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Subject</td>
|
||||
<td>{t('link')}</td>
|
||||
<td>
|
||||
<input type='text' />
|
||||
<button>Post</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Comment</td>
|
||||
<td>
|
||||
<textarea cols={48} rows={4} wrap='soft' />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Link</td>
|
||||
<td>
|
||||
<input type='text' onChange={(e) => setLink(e.target.value)} />
|
||||
<input
|
||||
type='text'
|
||||
autoCorrect='off'
|
||||
autoComplete='off'
|
||||
spellCheck='false'
|
||||
ref={urlRef}
|
||||
onChange={(e) => {
|
||||
setUrl(e.target.value);
|
||||
isInPostPage ? setContent.link(e.target.value) : setSubmitStore({ link: e.target.value });
|
||||
}}
|
||||
/>
|
||||
<span className={styles.linkType}>
|
||||
{link && (
|
||||
{url && (
|
||||
<>
|
||||
(<LinkTypePreviewer link={link} />)
|
||||
(<LinkTypePreviewer link={url} />)
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
@@ -66,9 +211,7 @@ const PostForm = () => {
|
||||
const isInDescriptionView = isDescriptionView(location.pathname, params);
|
||||
const isInRulesView = isRulesView(location.pathname, params);
|
||||
|
||||
const { subplebbitAddress, commentCid } = params || {};
|
||||
|
||||
const comment = useComment({ commentCid });
|
||||
const comment = useComment({ commentCid: useParams().commentCid });
|
||||
const { deleted, locked, removed } = comment || {};
|
||||
const isThreadClosed = deleted || locked || removed || isInDescriptionView || isInRulesView;
|
||||
|
||||
|
||||
@@ -303,6 +303,11 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.postMobile .postNumLink a {
|
||||
color: unset;
|
||||
text-decoration: unset;
|
||||
}
|
||||
|
||||
.postMobile .postMessage {
|
||||
padding: 10px;
|
||||
font-size: var(--post-mobile-content-font-size);
|
||||
@@ -416,6 +421,11 @@
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.pendingCid {
|
||||
color: red !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.postDesktop {
|
||||
display: none;
|
||||
|
||||
@@ -8,8 +8,10 @@ import { getFormattedDate } from '../../lib/utils/time-utils';
|
||||
import { isPostPageView } from '../../lib/utils/view-utils';
|
||||
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
|
||||
import useReplies from '../../hooks/use-replies';
|
||||
import useStateString from '../../hooks/use-state-string';
|
||||
import useWindowWidth from '../../hooks/use-window-width';
|
||||
import styles from './post.module.css';
|
||||
import LoadingEllipsis from '../loading-ellipsis';
|
||||
import Markdown from '../markdown';
|
||||
import CommentMedia from '../comment-media';
|
||||
import { canEmbed } from '../embed';
|
||||
@@ -24,13 +26,15 @@ interface PostProps {
|
||||
|
||||
const PostDesktop = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, cid, content, link, linkHeight, linkWidth, locked, pinned, postCid, replyCount, shortCid, subplebbitAddress, timestamp, title } = post || {};
|
||||
const { author, cid, content, link, linkHeight, linkWidth, locked, pinned, postCid, replyCount, shortCid, state, subplebbitAddress, timestamp, title } = post || {};
|
||||
const { address, displayName, shortAddress } = author || {};
|
||||
const authorRole = roles?.[address]?.role;
|
||||
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
|
||||
const isInPostPage = isPostPageView(useLocation().pathname, useParams());
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const isInPostPage = isPostPageView(location.pathname, params);
|
||||
|
||||
const displayTitle = title && title.length > 75 ? title?.slice(0, 75) + '...' : title;
|
||||
const displayContent = content && !isInPostPage && content.length > 1000 ? content?.slice(0, 1000) + '(...)' : content;
|
||||
@@ -120,12 +124,16 @@ const PostDesktop = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
<span className={styles.postNum}>
|
||||
{!(isDescription || isRules) && (
|
||||
<span className={styles.postNumLink}>
|
||||
<Link to={`/p/${subplebbitAddress}/${cid}`} className={styles.linkToPost} title={t('link_to_post')}>
|
||||
<Link to={`/p/${subplebbitAddress}/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
c/
|
||||
</Link>
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')}>
|
||||
{shortCid}
|
||||
</span>
|
||||
{!cid ? (
|
||||
<span className={styles.pendingCid}>{state === 'failed' ? 'Failed' : 'Pending'}</span>
|
||||
) : (
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')}>
|
||||
{shortCid}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
{pinned && (
|
||||
@@ -189,7 +197,7 @@ const PostDesktop = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
|
||||
const ReplyDesktop = ({ reply, roles }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, content, link, linkHeight, linkWidth, parentCid, pinned, postCid, shortCid, subplebbitAddress, timestamp } = reply || {};
|
||||
const { author, cid, content, link, linkHeight, linkWidth, parentCid, pinned, postCid, shortCid, state, subplebbitAddress, timestamp } = reply || {};
|
||||
const { address, displayName, shortAddress } = author || {};
|
||||
const authorRole = roles?.[address]?.role;
|
||||
|
||||
@@ -203,6 +211,11 @@ const ReplyDesktop = ({ reply, roles }: PostProps) => {
|
||||
|
||||
const [menuBtnRotated, setMenuBtnRotated] = useState(false);
|
||||
|
||||
const stateString = useStateString(reply);
|
||||
const loadingString = stateString && (
|
||||
<div className={`${styles.stateString} ${styles.ellipsis}`}>{stateString !== 'Failed' ? <LoadingEllipsis string={stateString} /> : stateString}</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.replyDesktop}>
|
||||
<div className={styles.sideArrows}>{'>>'}</div>
|
||||
@@ -221,12 +234,16 @@ const ReplyDesktop = ({ reply, roles }: PostProps) => {
|
||||
<span className={styles.dateTime}>{getFormattedDate(timestamp)} </span>
|
||||
<span className={styles.postNum}>
|
||||
<span className={styles.postNumLink}>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${reply.cid}`} className={styles.linkToPost} title='Link to post'>
|
||||
<Link to={`/p/${subplebbitAddress}/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
c/
|
||||
</Link>
|
||||
<span className={styles.replyToPost} title='Reply to post'>
|
||||
{shortCid}
|
||||
</span>
|
||||
{!cid ? (
|
||||
<span className={styles.pendingCid}>{state === 'failed' ? 'Failed' : 'Pending'}</span>
|
||||
) : (
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')}>
|
||||
{shortCid}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
{pinned && (
|
||||
<span className={styles.stickyIconWrapper}>
|
||||
@@ -296,6 +313,12 @@ const ReplyDesktop = ({ reply, roles }: PostProps) => {
|
||||
</>
|
||||
)}
|
||||
<Markdown content={content} />
|
||||
{!cid && (
|
||||
<>
|
||||
<br />
|
||||
{loadingString}
|
||||
</>
|
||||
)}
|
||||
</blockquote>
|
||||
)}
|
||||
</div>
|
||||
@@ -305,14 +328,17 @@ const ReplyDesktop = ({ reply, roles }: PostProps) => {
|
||||
|
||||
const PostMobile = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, cid, content, link, linkHeight, linkWidth, locked, pinned, replyCount, shortCid, subplebbitAddress, timestamp, title } = post || {};
|
||||
const { author, cid, content, link, linkHeight, linkWidth, locked, pinned, replyCount, shortCid, state, subplebbitAddress, timestamp, title } = post || {};
|
||||
const { address, displayName, shortAddress } = author || {};
|
||||
const authorRole = roles?.[address]?.role;
|
||||
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const isInPostPage = isPostPageView(location.pathname, params);
|
||||
|
||||
const linkCount = useCountLinksInReplies(post);
|
||||
const isInPostPage = isPostPageView(useLocation().pathname, useParams());
|
||||
const displayTitle = title && title.length > 30 ? title?.slice(0, 30) + '(...)' : title;
|
||||
const displayContent = content && !isInPostPage && content.length > 1000 ? content?.slice(0, 1000) : content;
|
||||
|
||||
@@ -335,7 +361,7 @@ const PostMobile = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
...
|
||||
</span>
|
||||
<span className={styles.nameBlock}>
|
||||
<span className={`${styles.name} ${authorRole && styles.capcodeMod}`}>
|
||||
<span className={`${styles.name} ${(isDescription || isRules || authorRole) && styles.capcodeMod}`}>
|
||||
{displayName || 'Anonymous'}
|
||||
{authorRole && ` ## Board ${authorRole}`}{' '}
|
||||
</span>
|
||||
@@ -360,10 +386,18 @@ const PostMobile = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
<span className={styles.dateTimePostNum}>
|
||||
{getFormattedDate(timestamp)}{' '}
|
||||
{!(isDescription || isRules) && (
|
||||
<>
|
||||
<span className={styles.linkToPost}>c/</span>
|
||||
<span className={styles.replyToPost}>{shortCid}</span>
|
||||
</>
|
||||
<span className={styles.postNumLink}>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
c/
|
||||
</Link>
|
||||
{!cid ? (
|
||||
<span className={styles.pendingCid}>{state === 'failed' ? 'Failed' : 'Pending'}</span>
|
||||
) : (
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')}>
|
||||
{shortCid}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
@@ -416,7 +450,7 @@ const PostMobile = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
|
||||
const ReplyMobile = ({ reply, roles }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, content, link, linkHeight, linkWidth, parentCid, pinned, postCid, shortCid, subplebbitAddress, timestamp } = reply || {};
|
||||
const { author, content, cid, link, linkHeight, linkWidth, parentCid, pinned, postCid, shortCid, state, subplebbitAddress, timestamp } = reply || {};
|
||||
const { address, displayName, shortAddress } = author || {};
|
||||
const authorRole = roles?.[address]?.role;
|
||||
|
||||
@@ -445,8 +479,19 @@ const ReplyMobile = ({ reply, roles }: PostProps) => {
|
||||
)}
|
||||
</span>
|
||||
<span className={styles.dateTimePostNum}>
|
||||
{getFormattedDate(timestamp)} <span className={styles.linkToPost}>c/</span>
|
||||
<span className={styles.replyToPost}>{shortCid}</span>
|
||||
{getFormattedDate(timestamp)}{' '}
|
||||
<span className={styles.postNumLink}>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${cid}`} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
c/
|
||||
</Link>
|
||||
</span>
|
||||
{!cid ? (
|
||||
<span className={styles.pendingCid}>{state === 'failed' ? 'Failed' : 'Pending'}</span>
|
||||
) : (
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')}>
|
||||
{shortCid}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{(hasThumbnail || link) && (
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { create } from 'zustand';
|
||||
import { Challenge } from '@plebbit/plebbit-react-hooks';
|
||||
|
||||
interface State {
|
||||
challenges: Challenge[];
|
||||
addChallenge: (challenge: Challenge) => void;
|
||||
removeChallenge: () => void;
|
||||
}
|
||||
|
||||
const useChallengesStore = create<State>((set) => ({
|
||||
challenges: [],
|
||||
addChallenge: (challenge: Challenge) => {
|
||||
set((state) => ({ challenges: [...state.challenges, challenge] }));
|
||||
},
|
||||
removeChallenge: () => {
|
||||
set((state) => {
|
||||
const challenges = [...state.challenges];
|
||||
challenges.shift();
|
||||
return { challenges };
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
export default useChallengesStore;
|
||||
@@ -0,0 +1,115 @@
|
||||
import { useMemo } from 'react';
|
||||
import { ChallengeVerification, Comment, PublishCommentOptions, usePublishComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { create } from 'zustand';
|
||||
import useChallengesStore from './use-challenges';
|
||||
import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils';
|
||||
|
||||
type SetReplyStoreData = {
|
||||
subplebbitAddress: string;
|
||||
parentCid: string;
|
||||
content: string | undefined;
|
||||
link: string | undefined;
|
||||
spoiler: boolean;
|
||||
};
|
||||
|
||||
type ReplyState = {
|
||||
content: { [parentCid: string]: string | undefined };
|
||||
link: { [parentCid: string]: string | undefined };
|
||||
spoiler: { [parentCid: string]: boolean | undefined };
|
||||
publishCommentOptions: PublishCommentOptions;
|
||||
setReplyStore: (data: SetReplyStoreData) => void;
|
||||
resetReplyStore: (parentCid: string) => void;
|
||||
};
|
||||
|
||||
const { addChallenge } = useChallengesStore.getState();
|
||||
|
||||
const useReplyStore = create<ReplyState>((set) => ({
|
||||
content: {},
|
||||
link: {},
|
||||
spoiler: {},
|
||||
publishCommentOptions: {},
|
||||
setReplyStore: (data: SetReplyStoreData) =>
|
||||
set((state) => {
|
||||
const { subplebbitAddress, parentCid, content, link, spoiler } = data;
|
||||
const publishCommentOptions = {
|
||||
subplebbitAddress,
|
||||
parentCid,
|
||||
content,
|
||||
link,
|
||||
spoiler,
|
||||
onChallenge: (...args: any) => addChallenge(args),
|
||||
onChallengeVerification: (challengeVerification: ChallengeVerification, comment: Comment) => {
|
||||
alertChallengeVerificationFailed(challengeVerification, comment);
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
console.error(error);
|
||||
alert(error.message);
|
||||
},
|
||||
};
|
||||
return {
|
||||
content: { ...state.content, [parentCid]: content },
|
||||
link: { ...state.link, [parentCid]: link },
|
||||
spoiler: { ...state.spoiler, [parentCid]: spoiler },
|
||||
publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: publishCommentOptions },
|
||||
};
|
||||
}),
|
||||
|
||||
resetReplyStore: (parentCid) =>
|
||||
set((state) => ({
|
||||
content: { ...state.content, [parentCid]: undefined },
|
||||
link: { ...state.link, [parentCid]: undefined },
|
||||
spoiler: { ...state.spoiler, [parentCid]: undefined },
|
||||
publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: undefined },
|
||||
})),
|
||||
}));
|
||||
|
||||
const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: string }) => {
|
||||
const parentCid = cid;
|
||||
const { content, link, spoiler, publishCommentOptions } = useReplyStore((state) => ({
|
||||
content: state.content[parentCid],
|
||||
link: state.link[parentCid],
|
||||
spoiler: state.spoiler[parentCid],
|
||||
publishCommentOptions: state.publishCommentOptions[parentCid],
|
||||
}));
|
||||
|
||||
const setReplyStore = useReplyStore((state) => state.setReplyStore);
|
||||
const resetReplyStore = useReplyStore((state) => state.resetReplyStore);
|
||||
|
||||
const setContent = useMemo(
|
||||
() => ({
|
||||
content: (newContent: string) =>
|
||||
setReplyStore({
|
||||
subplebbitAddress,
|
||||
parentCid,
|
||||
content: newContent === '' ? undefined : newContent,
|
||||
link: link || undefined,
|
||||
spoiler: spoiler || false,
|
||||
}),
|
||||
link: (newLink: string) =>
|
||||
setReplyStore({
|
||||
subplebbitAddress,
|
||||
parentCid,
|
||||
content: content,
|
||||
link: newLink || undefined,
|
||||
spoiler: spoiler || false,
|
||||
}),
|
||||
spoiler: (newSpoiler: boolean) =>
|
||||
setReplyStore({
|
||||
subplebbitAddress,
|
||||
parentCid,
|
||||
content: content,
|
||||
link: link || undefined,
|
||||
spoiler: newSpoiler,
|
||||
}),
|
||||
}),
|
||||
[subplebbitAddress, parentCid, setReplyStore, content, link, spoiler],
|
||||
);
|
||||
|
||||
const resetContent = useMemo(() => () => resetReplyStore(parentCid), [parentCid, resetReplyStore]);
|
||||
|
||||
const { index, publishComment } = usePublishComment(publishCommentOptions);
|
||||
|
||||
return { setContent, resetContent, replyIndex: index, publishReply: publishComment };
|
||||
};
|
||||
|
||||
export default useReply;
|
||||
@@ -0,0 +1,63 @@
|
||||
import { ChallengeVerification } from '@plebbit/plebbit-react-hooks';
|
||||
|
||||
export const alertChallengeVerificationFailed = (challengeVerification: ChallengeVerification, publication: any) => {
|
||||
if (challengeVerification?.challengeSuccess === false) {
|
||||
console.warn(challengeVerification, publication);
|
||||
alert(`p/${publication?.subplebbitAddress} challenge error: ${[...(challengeVerification?.challengeErrors || []), challengeVerification?.reason].join(' ')}`);
|
||||
} else {
|
||||
console.log(challengeVerification, publication);
|
||||
}
|
||||
};
|
||||
|
||||
export const getPublicationType = (publication: any) => {
|
||||
if (!publication) {
|
||||
return;
|
||||
}
|
||||
if (typeof publication.vote === 'number') {
|
||||
return 'vote';
|
||||
}
|
||||
if (publication.parentCid) {
|
||||
return 'reply';
|
||||
}
|
||||
if (publication.commentCid) {
|
||||
return 'edit';
|
||||
}
|
||||
return 'post';
|
||||
};
|
||||
|
||||
export const getVotePreview = (publication: any) => {
|
||||
if (typeof publication?.vote !== 'number') {
|
||||
return '';
|
||||
}
|
||||
let votePreview = '';
|
||||
if (publication.vote === -1) {
|
||||
votePreview += ' -1';
|
||||
} else {
|
||||
votePreview += ` +${publication.vote}`;
|
||||
}
|
||||
return votePreview;
|
||||
};
|
||||
|
||||
export const getPublicationPreview = (publication: any) => {
|
||||
if (!publication) {
|
||||
return '';
|
||||
}
|
||||
let publicationPreview = '';
|
||||
if (publication.title) {
|
||||
publicationPreview += publication.title;
|
||||
}
|
||||
if (publication.content) {
|
||||
if (publicationPreview) {
|
||||
publicationPreview += ': ';
|
||||
}
|
||||
publicationPreview += publication.content;
|
||||
}
|
||||
if (!publicationPreview && publication.link) {
|
||||
publicationPreview += publication.link;
|
||||
}
|
||||
|
||||
if (publicationPreview.length > 50) {
|
||||
publicationPreview = publicationPreview.substring(0, 50) + '...';
|
||||
}
|
||||
return publicationPreview;
|
||||
};
|
||||
Vendored
+2
@@ -6,3 +6,5 @@ declare module '*.module.css' {
|
||||
declare module 'ext-name';
|
||||
|
||||
declare module 'lodash';
|
||||
|
||||
declare module 'react-draggable';
|
||||
|
||||
+61
-1
@@ -30,9 +30,19 @@
|
||||
--catalog-post-menu-btn-opacity: 0.5;
|
||||
--catalog-post-menu-btn-hover-opacity: 1;
|
||||
|
||||
/* challenge modal */
|
||||
--challenge-modal-background-color: #f0e0d6;
|
||||
--challenge-modal-border: 1px solid #d9bfb7;
|
||||
--challenge-modal-title-background-color: #ea8;
|
||||
--challenge-modal-title-text-color: #800;
|
||||
--challenge-modal-title-border: 1px solid #800;
|
||||
--challenge-modal-title-font-size: 10pt;
|
||||
--challenge-modal-title-font-weight: 700;
|
||||
|
||||
/* desktop buttons */
|
||||
--button-desktop-text-color: #00e;
|
||||
--button-desktop-text-color-hover: red;
|
||||
--close-button-background-image: url("/public/assets/buttons/cross-red.png");
|
||||
|
||||
/* mobile buttons */
|
||||
--button-font-size-mobile: 10pt;
|
||||
@@ -173,6 +183,15 @@
|
||||
--catalog-post-menu-btn-opacity: 0.5;
|
||||
--catalog-post-menu-btn-hover-opacity: 1;
|
||||
|
||||
/* challenge modal */
|
||||
--challenge-modal-background-color: #d6daf0;
|
||||
--challenge-modal-border: 1px solid #b7c5d9;
|
||||
--challenge-modal-title-background-color: #98e;
|
||||
--challenge-modal-title-text-color: #000;
|
||||
--challenge-modal-title-border: 1px solid #000;
|
||||
--challenge-modal-title-font-size: 10pt;
|
||||
--challenge-modal-title-font-weight: 700;
|
||||
|
||||
/* homepage */
|
||||
--homepage-infobox-text-color: #000;
|
||||
--homepage-infobox-bar-text-color: #000;
|
||||
@@ -192,6 +211,7 @@
|
||||
/* desktop buttons */
|
||||
--button-desktop-text-color: #34345c;
|
||||
--button-desktop-text-color-hover: #d00;
|
||||
--close-button-background-image: url("/public/assets/buttons/cross-blue.png");
|
||||
|
||||
/* mobile buttons */
|
||||
--button-font-size-mobile: 10pt;
|
||||
@@ -310,10 +330,20 @@
|
||||
--catalog-post-menu-btn-opacity: 0.5;
|
||||
--catalog-post-menu-btn-hover-opacity: 1;
|
||||
|
||||
/* challenge modal */
|
||||
--challenge-modal-background-color: #f0e0d6;
|
||||
--challenge-modal-border: 1px solid #d9bfb7;
|
||||
--challenge-modal-title-background-color: #ea8;
|
||||
--challenge-modal-title-text-color: #800;
|
||||
--challenge-modal-title-border: 1px solid #800;
|
||||
--challenge-modal-title-font-size: 12pt;
|
||||
--challenge-modal-title-font-weight: 700;
|
||||
|
||||
/* desktop buttons */
|
||||
--button-desktop-text-color: #00e;
|
||||
--button-desktop-text-color-hover: red;
|
||||
--button-text-decoration: underline;
|
||||
--close-button-background-image: url("/public/assets/buttons/cross-red.png");
|
||||
|
||||
/* mobile buttons */
|
||||
--button-font-size-mobile: 11pt;
|
||||
@@ -420,6 +450,15 @@
|
||||
--body-font-family: times new roman, serif;
|
||||
--body-font-size: 12pt;
|
||||
|
||||
/* challenge modal */
|
||||
--challenge-modal-background-color: #d6daf0;
|
||||
--challenge-modal-border: 1px solid #b7c5d9;
|
||||
--challenge-modal-title-background-color: #98e;
|
||||
--challenge-modal-title-text-color: #000;
|
||||
--challenge-modal-title-border: 1px solid #000;
|
||||
--challenge-modal-title-font-size: 12pt;
|
||||
--challenge-modal-title-font-weight: 700;
|
||||
|
||||
/* homepage */
|
||||
--homepage-infobox-text-color: #000;
|
||||
--homepage-infobox-bar-text-color: #000;
|
||||
@@ -440,6 +479,7 @@
|
||||
--button-desktop-text-color: #34345c;
|
||||
--button-text-decoration: underline;
|
||||
--button-desktop-text-color-hover: #d00;
|
||||
--close-button-background-image: url("/public/assets/buttons/cross-blue.png");
|
||||
|
||||
/* mobile buttons */
|
||||
--button-font-size-mobile: 11pt;
|
||||
@@ -559,9 +599,19 @@
|
||||
--catalog-post-menu-btn-opacity: 0.5;
|
||||
--catalog-post-menu-btn-hover-opacity: 1;
|
||||
|
||||
/* 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-border: unset;
|
||||
--challenge-modal-title-font-size: 10pt;
|
||||
--challenge-modal-title-font-weight: 700;
|
||||
|
||||
/* desktop buttons */
|
||||
--button-desktop-text-color: #81a2be;
|
||||
--button-desktop-text-color-hover: #5f89ac;
|
||||
--close-button-background-image: url("/public/assets/buttons/cross-dark.png");
|
||||
|
||||
/* filter for inputs */
|
||||
--filter80: brightness(85%);
|
||||
@@ -691,9 +741,19 @@
|
||||
--catalog-post-menu-btn-opacity: 0.5;
|
||||
--catalog-post-menu-btn-hover-opacity: 1;
|
||||
|
||||
/* challenge modal */
|
||||
--challenge-modal-background-color: #ddd;
|
||||
--challenge-modal-border: 1px solid #ccc;
|
||||
--challenge-modal-title-background-color: #ddd;
|
||||
--challenge-modal-title-text-color: #333;
|
||||
--challenge-modal-title-border: unset;
|
||||
--challenge-modal-title-font-size: 10pt;
|
||||
--challenge-modal-title-font-weight: 700;
|
||||
|
||||
/* desktop buttons */
|
||||
--button-desktop-text-color: #f60;
|
||||
--button-desktop-text-color-hover: #f30;
|
||||
--close-button-background-image: url("/public/assets/buttons/cross-photon.png");
|
||||
|
||||
/* mobile buttons */
|
||||
--button-font-size-mobile: 10pt;
|
||||
@@ -735,7 +795,7 @@
|
||||
--post-mobile-info-border-top: 1px solid #ccc;
|
||||
--post-mobile-info-border-bottom: 1px solid #ccc;
|
||||
--post-mobile-info-background-color: #ddd;
|
||||
--post-mobile-info-text-color: #707070;
|
||||
--post-mobile-info-text-color: #333;
|
||||
--post-mobile-menu-button-color: #f60;
|
||||
--post-mobile-name-text-color: #004a99;
|
||||
--post-mobile-name-font-weight: 700;
|
||||
|
||||
@@ -3347,68 +3347,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||
|
||||
"@plebbit/plebbit-js@https://github.com/plebbit/plebbit-js.git#073d5f501ccf9521942d93f6522d1125058c196a":
|
||||
version "0.0.3"
|
||||
resolved "https://github.com/plebbit/plebbit-js.git#073d5f501ccf9521942d93f6522d1125058c196a"
|
||||
dependencies:
|
||||
"@bonfida/spl-name-service" "2.3.8"
|
||||
"@chainsafe/libp2p-gossipsub" "12.0.0"
|
||||
"@chainsafe/libp2p-noise" "15.0.0"
|
||||
"@chainsafe/libp2p-yamux" "6.0.2"
|
||||
"@ensdomains/eth-ens-namehash" "2.0.15"
|
||||
"@keyv/sqlite" "3.6.7"
|
||||
"@libp2p/autonat" "1.0.12"
|
||||
"@libp2p/bootstrap" "10.0.15"
|
||||
"@libp2p/circuit-relay-v2" "^1.0.15"
|
||||
"@libp2p/identify" "1.0.14"
|
||||
"@libp2p/kad-dht" "12.0.7"
|
||||
"@libp2p/mplex" "10.0.15"
|
||||
"@libp2p/peer-id-factory" "4.0.6"
|
||||
"@libp2p/webrtc" "4.0.19"
|
||||
"@libp2p/webtransport" "4.0.19"
|
||||
"@plebbit/plebbit-logger" "github:plebbit/plebbit-logger#355a96d7659ed820047980049dfa627d30d83a69"
|
||||
"@plebbit/proper-lockfile" "github:plebbit/node-proper-lockfile#7fd6332117340c1d3d98dd0afee2d31cc06f72b8"
|
||||
"@types/proper-lockfile" "4.1.2"
|
||||
"@types/uuid" "8.3.4"
|
||||
assert "2.1.0"
|
||||
better-sqlite3 "9.3.0"
|
||||
buffer "6.0.3"
|
||||
captcha-canvas "3.2.1"
|
||||
cbor "9.0.1"
|
||||
debounce "1.2.1"
|
||||
err-code "3.0.1"
|
||||
ethers "6.10.0"
|
||||
ext-name "5.0.0"
|
||||
file-type "16.5.4"
|
||||
hpagent "1.2.0"
|
||||
ipfs-only-hash "4.0.0"
|
||||
jose "4.11.0"
|
||||
js-sha256 "0.9.0"
|
||||
keyv "4.5.4"
|
||||
knex "3.1.0"
|
||||
kubo-rpc-client "3.0.3"
|
||||
libp2p "1.2.1"
|
||||
libp2p-crypto "0.21.2"
|
||||
limiter-es6-compat "2.1.2"
|
||||
localforage "1.10.0"
|
||||
lodash-es "4.17.21"
|
||||
lru-cache "10.1.0"
|
||||
open-graph-scraper "6.3.3"
|
||||
p-limit "4.0.0"
|
||||
p-timeout "6.1.2"
|
||||
peer-id "0.16.0"
|
||||
probe-image-size "7.2.3"
|
||||
retry "0.13.1"
|
||||
rpc-websockets "7.9.0"
|
||||
safe-stable-stringify "2.4.3"
|
||||
sha1-uint8array "0.10.7"
|
||||
skia-canvas "1.0.0"
|
||||
tiny-typed-emitter "2.1.0"
|
||||
tinycache "1.1.2"
|
||||
ts-custom-error "3.3.1"
|
||||
uuid "9.0.1"
|
||||
viem "1.5.2"
|
||||
|
||||
"@plebbit/plebbit-js@https://github.com/plebbit/plebbit-js.git#347579798478c27eea4808b923ab6f21799fce89":
|
||||
version "0.0.3"
|
||||
resolved "https://github.com/plebbit/plebbit-js.git#347579798478c27eea4808b923ab6f21799fce89"
|
||||
@@ -3484,22 +3422,6 @@
|
||||
dependencies:
|
||||
debug "4.3.4"
|
||||
|
||||
"@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#00aabcce2276c671c0f4a371d459c93eb39c936a":
|
||||
version "0.0.1"
|
||||
resolved "https://github.com/plebbit/plebbit-react-hooks.git#00aabcce2276c671c0f4a371d459c93eb39c936a"
|
||||
dependencies:
|
||||
"@plebbit/plebbit-js" "https://github.com/plebbit/plebbit-js.git#073d5f501ccf9521942d93f6522d1125058c196a"
|
||||
"@plebbit/plebbit-logger" "https://github.com/plebbit/plebbit-logger.git"
|
||||
assert "2.0.0"
|
||||
ethers "5.6.9"
|
||||
localforage "1.10.0"
|
||||
lodash.isequal "4.5.0"
|
||||
memoizee "0.4.15"
|
||||
quick-lru "5.1.1"
|
||||
uint8arrays "3.1.1"
|
||||
uuid "8.3.2"
|
||||
zustand "4.0.0"
|
||||
|
||||
"@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#6d0d38ad52ce77715cb05be6cec55d691f5f013d":
|
||||
version "0.0.1"
|
||||
resolved "https://github.com/plebbit/plebbit-react-hooks.git#6d0d38ad52ce77715cb05be6cec55d691f5f013d"
|
||||
@@ -6224,6 +6146,11 @@ clone@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
||||
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
|
||||
|
||||
clsx@^1.1.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
@@ -14777,6 +14704,14 @@ react-dom@18.2.0:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.0"
|
||||
|
||||
react-draggable@^4.4.6:
|
||||
version "4.4.6"
|
||||
resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.6.tgz#63343ee945770881ca1256a5b6fa5c9f5983fe1e"
|
||||
integrity sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==
|
||||
dependencies:
|
||||
clsx "^1.1.1"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
react-error-overlay@^6.0.11:
|
||||
version "6.0.11"
|
||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
|
||||
|
||||
Reference in New Issue
Block a user