Merge pull request #437 from plebbit/development

Development
This commit is contained in:
Tom (plebeius.eth)
2024-12-04 15:13:25 +01:00
committed by GitHub
51 changed files with 272 additions and 135 deletions

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>إنشاء</1> حساب جديد",
"wallet_number": "المحفظة #{{index}}",
"view_more": "عرض المزيد",
"submit_community": "قدم مجتمعك"
"submit_community": "قدم مجتمعك",
"hide_avatars_from_replies": "إخفاء الصور الرمزية من الردود"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>নতুন তৈরি করুন</1> অ্যাকাউন্ট",
"wallet_number": "ওয়ালেট #{{index}}",
"view_more": "আরও দেখুন",
"submit_community": "আপনার সম্প্রদায় জমা দিন"
"submit_community": "আপনার সম্প্রদায় জমা দিন",
"hide_avatars_from_replies": "প্রতিক্রিয়া থেকে অ্যাভাটারগুলি লুকান"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>vytvořit</1> nový účet",
"wallet_number": "peněženka #{{index}}",
"view_more": "zobrazit více",
"submit_community": "Odešlete svou komunitu"
"submit_community": "Odešlete svou komunitu",
"hide_avatars_from_replies": "Skrýt avatary v odpovědích"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>oprette</1> en ny konto",
"wallet_number": "tegneboks #{{index}}",
"view_more": "se mere",
"submit_community": "Indsend dit fællesskab"
"submit_community": "Indsend dit fællesskab",
"hide_avatars_from_replies": "Skjul avatarer fra svar"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>erstelle</1> ein neues Konto",
"wallet_number": "Wallet #{{index}}",
"view_more": "mehr anzeigen",
"submit_community": "Reichen Sie Ihre Gemeinschaft ein"
"submit_community": "Reichen Sie Ihre Gemeinschaft ein",
"hide_avatars_from_replies": "Avatare in Antworten ausblenden"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>δημιουργία</1> νέου λογαριασμού",
"wallet_number": "πορτοφόλι #{{index}}",
"view_more": "δείτε περισσότερα",
"submit_community": "Υποβάλετε την κοινότητά σας"
"submit_community": "Υποβάλετε την κοινότητά σας",
"hide_avatars_from_replies": "Απόκρυψη avatar από τις απαντήσεις"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>create</1> a new account",
"wallet_number": "wallet #{{index}}",
"view_more": "view more",
"submit_community": "Submit your community"
"submit_community": "Submit your community",
"hide_avatars_from_replies": "Hide avatars from replies"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>crear</1> una nueva cuenta",
"wallet_number": "billetera #{{index}}",
"view_more": "ver más",
"submit_community": "Envía tu comunidad"
"submit_community": "Envía tu comunidad",
"hide_avatars_from_replies": "Ocultar avatares de las respuestas"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>ایجاد</1> یک حساب جدید",
"wallet_number": "کیف پول #{{index}}",
"view_more": "مشاهده بیشتر",
"submit_community": "جامعه خود را ارسال کنید"
"submit_community": "جامعه خود را ارسال کنید",
"hide_avatars_from_replies": "تصاویر پروفایل را از پاسخ‌ها پنهان کن"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>luo</1> uusi tili",
"wallet_number": "lompakko #{{index}}",
"view_more": "näytä lisää",
"submit_community": "Lähetä yhteisösi"
"submit_community": "Lähetä yhteisösi",
"hide_avatars_from_replies": "Piilota avatarit vastauksista"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>lumikha</1> ng bagong account",
"wallet_number": "wallet #{{index}}",
"view_more": "tingnan pa",
"submit_community": "I-submit ang iyong komunidad"
"submit_community": "I-submit ang iyong komunidad",
"hide_avatars_from_replies": "Itago ang mga avatar mula sa mga sagot"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>créer</1> un nouveau compte",
"wallet_number": "portefeuille #{{index}}",
"view_more": "voir plus",
"submit_community": "Soumettez votre communauté"
"submit_community": "Soumettez votre communauté",
"hide_avatars_from_replies": "Cacher les avatars des réponses"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>צור</1> חשבון חדש",
"wallet_number": "ארנק #{{index}}",
"view_more": "ראה עוד",
"submit_community": "שלח את הקהילה שלך"
"submit_community": "שלח את הקהילה שלך",
"hide_avatars_from_replies": "הסתרת תמונות פרופיל בתשובות"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>नया बनाएं</1> खाता",
"wallet_number": "वॉलेट #{{index}}",
"view_more": "और देखें",
"submit_community": "अपनी समुदाय सबमिट करें"
"submit_community": "अपनी समुदाय सबमिट करें",
"hide_avatars_from_replies": "उत्तर से अवतार छुपाएं"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>hozzon létre</1> egy új fiókot",
"wallet_number": "tárca #{{index}}",
"view_more": "több megtekintése",
"submit_community": "Küldje el közösségét"
"submit_community": "Küldje el közösségét",
"hide_avatars_from_replies": "Rejtse el az avatarokat a válaszokból"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>buat</1> akun baru",
"wallet_number": "dompet #{{index}}",
"view_more": "lihat lebih banyak",
"submit_community": "Kirim komunitas Anda"
"submit_community": "Kirim komunitas Anda",
"hide_avatars_from_replies": "Sembunyikan avatar dari balasan"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>crea</1> un nuovo account",
"wallet_number": "wallet #{{index}}",
"view_more": "altri",
"submit_community": "Invia la tua comunità"
"submit_community": "Invia la tua comunità",
"hide_avatars_from_replies": "Nascondi avatar da commenti"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>新しい</1>アカウントを作成",
"wallet_number": "ウォレット #{{index}}",
"view_more": "もっと見る",
"submit_community": "コミュニティを提出してください"
"submit_community": "コミュニティを提出してください",
"hide_avatars_from_replies": "返信からアバターを非表示にする"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>새로 만들기</1> 계정",
"wallet_number": "지갑 #{{index}}",
"view_more": "더보기",
"submit_community": "커뮤니티를 제출하세요"
"submit_community": "커뮤니티를 제출하세요",
"hide_avatars_from_replies": "답글에서 아바타 숨기기"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>नवीन तयार करा</1> खाता",
"wallet_number": "वॉलेट #{{index}}",
"view_more": "अधिक पाहा",
"submit_community": "तुमच्या समुदायाला सबमिट करा"
"submit_community": "तुमच्या समुदायाला सबमिट करा",
"hide_avatars_from_replies": "उत्तरांमधून अवतार लपवा"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>maak</1> een nieuw account aan",
"wallet_number": "portemonnee #{{index}}",
"view_more": "meer bekijken",
"submit_community": "Dien uw gemeenschap in"
"submit_community": "Dien uw gemeenschap in",
"hide_avatars_from_replies": "Verberg avatars van reacties"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>opprett</1> en ny konto",
"wallet_number": "lommebok #{{index}}",
"view_more": "vis mer",
"submit_community": "Send inn ditt fellesskap"
"submit_community": "Send inn ditt fellesskap",
"hide_avatars_from_replies": "Skjul avatarer fra svar"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>stwórz</1> nowe konto",
"wallet_number": "portfel #{{index}}",
"view_more": "zobacz więcej",
"submit_community": "Prześlij swoją społeczność"
"submit_community": "Prześlij swoją społeczność",
"hide_avatars_from_replies": "Ukryj avatary w odpowiedziach"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>criar</1> uma nova conta",
"wallet_number": "carteira #{{index}}",
"view_more": "ver mais",
"submit_community": "Envie sua comunidade"
"submit_community": "Envie sua comunidade",
"hide_avatars_from_replies": "Esconder avatares das respostas"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>creați</1> un cont nou",
"wallet_number": "portofel #{{index}}",
"view_more": "vezi mai mult",
"submit_community": "Trimite comunitatea ta"
"submit_community": "Trimite comunitatea ta",
"hide_avatars_from_replies": "Ascunde avatarele din răspunsuri"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>создать</1> новую учетную запись",
"wallet_number": "кошелек #{{index}}",
"view_more": "смотреть больше",
"submit_community": "Отправьте ваше сообщество"
"submit_community": "Отправьте ваше сообщество",
"hide_avatars_from_replies": "Скрыть аватары в ответах"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>krijo</1> një llogari të re",
"wallet_number": "portofol #{{index}}",
"view_more": "shiko më shumë",
"submit_community": "Dorëzo komunitetin tuaj"
"submit_community": "Dorëzo komunitetin tuaj",
"hide_avatars_from_replies": "Fshih avatarët nga përgjigjet"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>skapa</1> ett nytt konto",
"wallet_number": "plånbok #{{index}}",
"view_more": "visa mer",
"submit_community": "Skicka in ditt samhälle"
"submit_community": "Skicka in ditt samhälle",
"hide_avatars_from_replies": "Dölj avatarer från svar"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>తరువాత</1> కొత్త ఖాతా",
"wallet_number": "వాలెట్ #{{index}}",
"view_more": "మరింత చూడండి",
"submit_community": "మీ కమ్యూనిటి పంపించండి"
"submit_community": "మీ కమ్యూనిటి పంపించండి",
"hide_avatars_from_replies": "ప్రతిస్పందనల నుండి అవతార్లను దాచు"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>สร้าง</1> บัญชีใหม่",
"wallet_number": "กระเป๋าเงิน #{{index}}",
"view_more": "ดูเพิ่มเติม",
"submit_community": "ส่งชุมชนของคุณ"
"submit_community": "ส่งชุมชนของคุณ",
"hide_avatars_from_replies": "ซ่อนอวาตาร์จากคำตอบ"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>oluştur</1> yeni bir hesap",
"wallet_number": "cüzdan #{{index}}",
"view_more": "daha fazla görüntüle",
"submit_community": "Topluluğunuzu gönderin"
"submit_community": "Topluluğunuzu gönderin",
"hide_avatars_from_replies": "Yanıtlardan avatarları gizle"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>створити</1> новий обліковий запис",
"wallet_number": "гаманець #{{index}}",
"view_more": "переглянути більше",
"submit_community": "Надішліть своє співтовариство"
"submit_community": "Надішліть своє співтовариство",
"hide_avatars_from_replies": "Сховати аватари в відповідях"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>نیا بنائیں</1> اکاؤنٹ",
"wallet_number": "والٹ #{{index}}",
"view_more": "مزید دیکھیں",
"submit_community": "اپنی کمیونٹی جمع کروائیں"
"submit_community": "اپنی کمیونٹی جمع کروائیں",
"hide_avatars_from_replies": "جوابوں سے اوتار چھپائیں"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>tạo</1> tài khoản mới",
"wallet_number": "ví #{{index}}",
"view_more": "xem thêm",
"submit_community": "Gửi cộng đồng của bạn"
"submit_community": "Gửi cộng đồng của bạn",
"hide_avatars_from_replies": "Ẩn avatar trong các câu trả lời"
}

View File

@@ -322,5 +322,6 @@
"create_new_account": "<1>创建</1>新账户",
"wallet_number": "钱包 #{{index}}",
"view_more": "查看更多",
"submit_community": "提交您的社区"
"submit_community": "提交您的社区",
"hide_avatars_from_replies": "隐藏回复中的头像"
}

View File

@@ -41,8 +41,7 @@
width: 84px;
max-height: 26px;
margin-top: 16px;
margin-right: 5px;
padding-right: 1ex;
padding-right: 5px;
filter: var(--filter90);
}

View File

@@ -364,7 +364,7 @@ const Header = () => {
(isInProfileView && !isInHomeAboutView) ||
(isInAllView && !isInAllAboutView) ||
(isInAuthorView && !isInHomeAboutView);
const logoSrc = isInSubplebbitView ? suggested?.avatarUrl : 'assets/logo/seedit.png';
const logoSrc = isInSubplebbitView && suggested?.avatarUrl ? suggested?.avatarUrl : 'assets/logo/seedit.png';
const logoIsAvatar = isInSubplebbitView && suggested?.avatarUrl;
const logoLink = isInSubplebbitView ? `/p/${params.subplebbitAddress}` : isInProfileView ? '/profile' : '/';
@@ -377,10 +377,10 @@ const Header = () => {
>
<div className={styles.logoContainer}>
<Link to={logoLink} className={styles.logoLink}>
{(logoIsAvatar || (!isInSubplebbitView && !isInProfileView && !isInAuthorView)) && (
{(logoIsAvatar || (!isInSubplebbitView && !isInProfileView && !isInAuthorView) || (isInSubplebbitView && !suggested?.avatarUrl)) && (
<img className={`${logoIsAvatar ? styles.avatar : styles.logo}`} src={logoSrc} alt='' />
)}
{!isInSubplebbitView && !isInProfileView && !isInAuthorView && (
{((!isInSubplebbitView && !isInProfileView && !isInAuthorView) || (isInSubplebbitView && !suggested?.avatarUrl)) && (
<img src={`assets/logo/seedit-text-${theme === 'dark' ? 'dark' : 'light'}.svg`} className={styles.logoText} alt='' />
)}
</Link>

View File

@@ -1,21 +1,52 @@
.ellipsis:after {
overflow: hidden;
.nowrap {
white-space: nowrap;
}
.ellipsis {
display: inline-block;
vertical-align: text-bottom;
-webkit-animation: ellipsis steps(4,end) 1500ms infinite;
animation: ellipsis steps(4,end) 1500ms infinite;
content: "\2026"; /* ascii code for the ellipsis character */
width: 0px;
width: 4ch;
}
.ellipsis:after {
display: inline-block;
vertical-align: bottom;
-webkit-animation: ellipsis 1500ms steps(4, end) infinite;
animation: ellipsis 1500ms steps(4, end) infinite;
content: "";
}
@keyframes ellipsis {
to {
width: 1.25em;
0% {
content: "";
}
25% {
content: ".";
}
50% {
content: "..";
}
75% {
content: "...";
}
100% {
content: "";
}
}
@-webkit-keyframes ellipsis {
to {
width: 1.25em;
0% {
content: "";
}
25% {
content: ".";
}
50% {
content: "..";
}
75% {
content: "...";
}
100% {
content: "";
}
}

View File

@@ -5,7 +5,20 @@ interface LoadingEllipsisProps {
}
const LoadingEllipsis = ({ string }: LoadingEllipsisProps) => {
return <span className={styles.ellipsis}>{string}</span>;
const words = string.split(' ');
const lastWord = words.pop();
const restOfString = words.join(' ');
return (
<span>
{restOfString}
{restOfString && ' '}
<span className={styles.nowrap}>
{lastWord}
<span className={styles.ellipsis} />
</span>
</span>
);
};
export default LoadingEllipsis;

View File

@@ -62,4 +62,8 @@
.banInput {
width: 3.5em;
}
}
.modal .menuItem label {
cursor: pointer;
}

View File

@@ -1,10 +1,10 @@
import { useEffect, useState } from 'react';
import { useState } from 'react';
import styles from './post.module.css';
import { Link, useLocation, useParams } from 'react-router-dom';
import { Comment, useAuthorAddress, useBlock, useComment, useEditedComment, useSubplebbit, useSubscribe } from '@plebbit/plebbit-react-hooks';
import { useTranslation } from 'react-i18next';
import { isAllView, isPostView, isProfileHiddenView, isSubplebbitView } from '../../lib/utils/view-utils';
import { CommentMediaInfo, fetchWebpageThumbnailIfNeeded, getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { getHasThumbnail } from '../../lib/utils/media-utils';
import { getPostScore } from '../../lib/utils/post-utils';
import { getHostname } from '../../lib/utils/url-utils';
import { getFormattedTimeAgo, formatLocalizedUTCTimestamp } from '../../lib/utils/time-utils';
@@ -17,6 +17,7 @@ import Thumbnail from './thumbnail';
import useDownvote from '../../hooks/use-downvote';
import useUpvote from '../../hooks/use-upvote';
import _ from 'lodash';
import { useCommentMediaInfo } from '../../hooks/use-comment-media-info';
interface PostAuthorProps {
authorAddress: string;
@@ -70,33 +71,6 @@ interface PostProps {
post: Comment | undefined;
}
const ThumbnailLoader = ({ post }: PostProps) => {
const { cid } = post || {};
// Reset state by remounting component when post changes
return useThumbnailContent(cid, post);
};
const useThumbnailContent = (key: string, post: any) => {
const [commentMediaInfo, setCommentMediaInfo] = useState<CommentMediaInfo | undefined>();
useEffect(() => {
const loadThumbnail = async () => {
const initialInfo = getCommentMediaInfo(post);
// some sites have CORS access, so the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false
if (initialInfo?.type === 'webpage' && !initialInfo.thumbnail) {
const newMediaInfo = await fetchWebpageThumbnailIfNeeded(initialInfo);
setCommentMediaInfo(newMediaInfo);
} else {
setCommentMediaInfo(initialInfo);
}
};
loadThumbnail();
}, [post]);
return commentMediaInfo;
};
const Post = ({ index, post = {} }: PostProps) => {
// handle single comment thread
const op = useComment({ commentCid: post?.parentCid ? post?.postCid : '' });
@@ -147,7 +121,7 @@ const Post = ({ index, post = {} }: PostProps) => {
const isInProfileHiddenView = isProfileHiddenView(location.pathname);
const isInSubplebbitView = isSubplebbitView(location.pathname, params);
const commentMediaInfo = ThumbnailLoader({ post });
const commentMediaInfo = useCommentMediaInfo(post);
const [isExpanded, setIsExpanded] = useState(isInPostView);
const toggleExpanded = () => setIsExpanded(!isExpanded);

View File

@@ -87,6 +87,7 @@ const ReplyForm = ({ cid, isReplyingToReply, hideReplyForm, subplebbitAddress, p
const { t } = useTranslation();
const [showOptions, setShowOptions] = useState(false);
const [showFormattingHelp, setShowFormattingHelp] = useState(false);
const [isTextareaFocused, setIsTextareaFocused] = useState(false);
const { setContent, resetContent, replyIndex, publishReply } = usePublishReply({ cid, subplebbitAddress, postCid });
const mdContainerClass = isReplyingToReply ? `${styles.mdContainer} ${styles.mdContainerReplying}` : styles.mdContainer;
@@ -149,7 +150,7 @@ const ReplyForm = ({ cid, isReplyingToReply, hideReplyForm, subplebbitAddress, p
return (
<div className={mdContainerClass}>
<div className={styles.md}>
{isOffline && <div className={styles.infobar}>{offlineTitle}</div>}
{isOffline && isTextareaFocused && <div className={styles.infobar}>{offlineTitle}</div>}
<div className={styles.options}>
<span className={urlClass}>
{t('media_url')}: <input className={`${styles.url} ${urlClass}`} ref={urlRef} onChange={(e) => setContent.link(e.target.value)} />
@@ -160,7 +161,13 @@ const ReplyForm = ({ cid, isReplyingToReply, hideReplyForm, subplebbitAddress, p
</label>
</span>
</div>
<textarea className={styles.textarea} ref={textRef} onChange={(e) => setContent.content(e.target.value)} />
<textarea
className={styles.textarea}
ref={textRef}
onChange={(e) => setContent.content(e.target.value)}
onFocus={() => setIsTextareaFocused(true)}
onBlur={() => setIsTextareaFocused(false)}
/>
</div>
<div className={styles.bottomArea}>
<button className={styles.save} onClick={onPublish}>

View File

@@ -67,10 +67,17 @@
}
.tagline {
display: inline-block;
color: var(--text);
font-size: x-small;
}
@media (max-width: 640px) {
.tagline {
line-height: 1.5;
}
}
.expand {
margin-right: 3px;
padding: 1px;
@@ -220,6 +227,7 @@
.collapsedEntry {
padding-left: 25px;
min-height: 16px;
}
.parent {
@@ -354,4 +362,11 @@
.md {
padding-right: 5px;
}
}
.stamp {
font-family: inherit;
font-size: x-small;
line-height: normal;
vertical-align: middle;
}

View File

@@ -1,11 +1,12 @@
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
import { Fragment, useEffect, useMemo, useState } from 'react';
import { Comment, useAccountComment, useAuthorAddress, useAuthorAvatar, useBlock, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils';
import { Link, useLocation, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import styles from './reply.module.css';
import { useCommentMediaInfo } from '../../hooks/use-comment-media-info';
import useReplies from '../../hooks/use-replies';
import { CommentMediaInfo, fetchWebpageThumbnailIfNeeded, getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { CommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { formatLocalizedUTCTimestamp, getFormattedTimeAgo } from '../../lib/utils/time-utils';
import CommentEditForm from '../comment-edit-form';
import LoadingEllipsis from '../loading-ellipsis/';
@@ -23,6 +24,7 @@ import { isInboxView, isPostContextView, isPostView } from '../../lib/utils/view
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
import Markdown from '../markdown';
import { getHostname } from '../../lib/utils/url-utils';
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
interface ReplyAuthorProps {
address: string;
@@ -38,20 +40,20 @@ interface ReplyAuthorProps {
const ReplyAuthor = ({ address, authorRole, cid, deleted, displayName, imageUrl, isAvatarDefined, removed, shortAuthorAddress }: ReplyAuthorProps) => {
const { t } = useTranslation();
const { hideAvatars } = useAvatarVisibilityStore();
const isAuthorAdmin = authorRole === 'admin';
const isAuthorOwner = authorRole === 'owner';
const isAuthorModerator = authorRole === 'moderator';
const authorRoleInitial = (isAuthorOwner && 'O') || (isAuthorAdmin && 'A') || (isAuthorModerator && 'M') || '';
const moderatorClass = `${isAuthorOwner ? styles.owner : isAuthorAdmin ? styles.admin : isAuthorModerator ? styles.moderator : ''}`;
const shortDisplayName = displayName?.length > 20 ? displayName?.slice(0, 20) + '...' : displayName;
return (
<>
{removed || deleted ? (
<span className={styles.removedUsername}>[{removed ? t('removed') : deleted ? t('deleted') : ''}]</span>
) : (
<>
{isAvatarDefined && (
{!hideAvatars && isAvatarDefined && (
<span className={styles.authorAvatar}>
<img src={imageUrl} alt='' />
</span>
@@ -299,21 +301,7 @@ const Reply = ({ cidOfReplyWithContext, depth = 0, isSingleComment, isSingleRepl
const showCommentEditForm = () => setIsEditing(true);
const hideCommentEditForm = () => setIsEditing(false);
// some sites have CORS access, so the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false
const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(reply), [reply]);
const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo);
const fetchThumbnail = useCallback(async () => {
if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) {
const newMediaInfo = await fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo);
setCommentMediaInfo(newMediaInfo);
}
}, [initialCommentMediaInfo]);
useEffect(() => {
fetchThumbnail();
}, [fetchThumbnail]);
const commentMediaInfo = useCommentMediaInfo(reply);
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
const { t, i18n } = useTranslation();
@@ -329,16 +317,6 @@ const Reply = ({ cidOfReplyWithContext, depth = 0, isSingleComment, isSingleRepl
const [upvoted, upvote] = useUpvote(reply);
const [downvoted, downvote] = useDownvote(reply);
const stateLabel = (
<span className={styles.stateLabel}>
{state === 'failed' && <Label color='red' text={t('failed')} />}
{cid === undefined && state !== 'failed' && <Label color='yellow' text={t('pending')} />}
{editState === 'failed' && <Label color='red' text={t('failed_edit')} />}
{editState === 'pending' && <Label color='yellow' text={t('pending_edit')} />}
{spoiler && <Label color='black' text={t('spoiler')} />}
</span>
);
const unnestedReplies = useMemo(() => flattenCommentsPages(reply.replies), [reply.replies]);
const childrenCount = unnestedReplies.length;
const childrenString = childrenCount === 1 ? t('child', { childrenCount }) : t('children', { childrenCount });
@@ -357,6 +335,16 @@ const Reply = ({ cidOfReplyWithContext, depth = 0, isSingleComment, isSingleRepl
setCollapsed(!collapsed);
};
const stateLabel = (
<span className={`${styles.stateLabel} ${collapsed ? styles.collapsedStateLabel : ''}`}>
{state === 'failed' && <Label color='red' text={t('failed')} />}
{cid === undefined && state !== 'failed' && <Label color='yellow' text={t('pending')} />}
{editState === 'failed' && <Label color='red' text={t('failed_edit')} />}
{editState === 'pending' && <Label color='yellow' text={t('pending_edit')} />}
{spoiler && <Label color='black' text={t('spoiler')} />}
</span>
);
return (
<div className={styles.reply}>
{isSingleReply && !isInInboxView && <ParentLink postCid={cid ? postCid : parentOfPendingReply?.postCid} />}
@@ -392,15 +380,19 @@ const Reply = ({ cidOfReplyWithContext, depth = 0, isSingleComment, isSingleRepl
{edit && <span className={styles.timeEdited}> {t('edited_timestamp', { timestamp: getFormattedTimeAgo(edit.timestamp) })}</span>}
</span>{' '}
{pinned && <span className={styles.pinned}>- {t('stickied_comment')}</span>}
{collapsed && <span className={styles.children}> ({childrenString})</span>}
{stateLabel}{' '}
{collapsed && (
<>
<span className={styles.children}>({childrenString})</span> {stateLabel} {state === 'pending' && loadingString}
</>
)}
{!collapsed && stateLabel}
{!collapsed && flair && (
<>
{' '}
<Flair flair={flair} />
</>
)}
{state === 'pending' && loadingString}
{state === 'pending' && !collapsed && <> {loadingString}</>}
</p>
)}
{isInInboxView && (

View File

@@ -0,0 +1,20 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Comment } from '@plebbit/plebbit-react-hooks';
import { getCommentMediaInfo, fetchWebpageThumbnailIfNeeded } from '../lib/utils/media-utils';
export const useCommentMediaInfo = (comment: Comment) => {
// some sites have CORS access, so the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false
const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(comment), [comment]);
const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo);
const fetchThumbnail = useCallback(async () => {
if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) {
const newMediaInfo = await fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo);
setCommentMediaInfo(newMediaInfo);
}
}, [initialCommentMediaInfo]);
useEffect(() => {
fetchThumbnail();
}, [fetchThumbnail]);
return commentMediaInfo;
};

View File

@@ -0,0 +1,21 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface AvatarVisibilityState {
hideAvatars: boolean;
setHideAvatars: (hide: boolean) => void;
}
const useAvatarVisibilityStore = create<AvatarVisibilityState>()(
persist(
(set) => ({
hideAvatars: false,
setHideAvatars: (hide) => set({ hideAvatars: hide }),
}),
{
name: 'avatar-visibility-storage',
},
),
);
export default useAvatarVisibilityStore;

View File

@@ -96,7 +96,7 @@ const FAQ = () => {
Seedit desktop
</a>
, which automatically runs a full node and lets you create communities with the ease of a reddit-like graphical user interface. You can also open a remote
connection to an <HashLink to='/settings/plebbit-options#nodeRpc'>RPC node</HashLink> to create communities even on web and on mobile devices. In the near
connection to an <HashLink to='/settings/plebbit-options#plebbitRpc'>RPC node</HashLink> to create communities even on web and on mobile devices. In the near
future, we plan to include a public RPC connection turned on by default, so you can create communities on any device without running your own node.
</p>
<hr />

View File

@@ -62,7 +62,7 @@ const All = () => {
footerContent = (
<>
{subplebbitAddressesWithNewerPosts.length > 0 ? (
<div className={styles.stateString}>
<div className={styles.morePostsSuggestion}>
<Trans
i18nKey='newer_posts_available'
components={{
@@ -74,7 +74,7 @@ const All = () => {
showMorePostsSuggestion &&
monthlyFeed.length > feed.length &&
(weeklyFeed.length > feed.length ? (
<div className={styles.stateString}>
<div className={styles.morePostsSuggestion}>
<Trans
i18nKey='more_posts_last_week'
values={{ currentTimeFilterName }}
@@ -84,7 +84,7 @@ const All = () => {
/>
</div>
) : (
<div className={styles.stateString}>
<div className={styles.morePostsSuggestion}>
<Trans
i18nKey='more_posts_last_month'
values={{ currentTimeFilterName }}

View File

@@ -74,4 +74,18 @@
.copyMessage a:hover {
text-decoration: underline;
}
}
.hideAvatarsCheckbox {
padding-top: 10px;
display: inline-block;
text-transform: lowercase;
}
.hideAvatarsCheckbox label {
cursor: pointer;
}
.hideAvatarsCheckbox input {
margin-right: .5em;
}

View File

@@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
import { setAccount, useAccount, useAuthorAvatar } from '@plebbit/plebbit-react-hooks';
import styles from './avatar-settings.module.css';
import { Trans, useTranslation } from 'react-i18next';
import useAvatarVisibilityStore from '../../../stores/use-avatar-visibility-store';
interface AvatarSettingsProps {
areSettingsShown?: boolean;
@@ -57,6 +58,7 @@ const AvatarSettings = () => {
const [tokenId, setTokenId] = useState(account?.author?.avatar?.id);
const [timestamp, setTimestamp] = useState(account?.author?.avatar?.timestamp);
const [signature, setSignature] = useState(account?.author?.avatar?.signature?.signature);
const { hideAvatars, setHideAvatars } = useAvatarVisibilityStore();
const getNftMessageToSign = (authorAddress: string, timestamp: number, tokenAddress: string, tokenId: string) => {
let messageToSign: any = {};
@@ -205,6 +207,12 @@ const AvatarSettings = () => {
</div>
</div>
)}
<div className={styles.hideAvatarsCheckbox}>
<label>
<input type='checkbox' checked={hideAvatars} onChange={(e) => setHideAvatars(e.target.checked)} />
{t('hide_avatars_from_replies')}
</label>
</div>
</div>
);
};

View File

@@ -13,7 +13,7 @@ interface SettingsProps {
maticRpcRef?: RefObject<HTMLTextAreaElement>;
avaxRpcRef?: RefObject<HTMLTextAreaElement>;
plebbitRpcRef?: RefObject<HTMLInputElement>;
nodeDataPathRef?: RefObject<HTMLInputElement>;
plebbitDataPathRef?: RefObject<HTMLInputElement>;
}
const IPFSGatewaysSettings = ({ ipfsGatewayUrlsRef, mediaIpfsGatewayUrlRef }: SettingsProps) => {
@@ -129,21 +129,23 @@ const PlebbitRPCSettings = ({ plebbitRpcRef }: SettingsProps) => {
);
};
const NodeDataPathSettings = ({ nodeDataPathRef }: SettingsProps) => {
const PlebbitDataPathSettings = ({ plebbitDataPathRef }: SettingsProps) => {
const plebbitRpc = usePlebbitRpcSettings();
const { plebbitRpcSettings } = plebbitRpc || {};
const isConnectedToRpc = plebbitRpc?.state === 'succeeded';
const path = plebbitRpcSettings?.plebbitOptions?.dataPath || '';
return (
<div className={styles.nodeDataPathSettings}>
<div className={styles.plebbitDataPathSettings}>
<div>
<input type='text' defaultValue={path} disabled={!isConnectedToRpc} ref={nodeDataPathRef} />
<input type='text' defaultValue={path} disabled={!isConnectedToRpc} ref={plebbitDataPathRef} />
</div>
</div>
);
};
const isElectron = window.isElectron === true;
const PlebbitOptions = () => {
const { t } = useTranslation();
const location = useLocation();
@@ -158,7 +160,7 @@ const PlebbitOptions = () => {
const maticRpcRef = useRef<HTMLTextAreaElement>(null);
const avaxRpcRef = useRef<HTMLTextAreaElement>(null);
const plebbitRpcRef = useRef<HTMLInputElement>(null);
const nodeDataPathRef = useRef<HTMLInputElement>(null);
const plebbitDataPathRef = useRef<HTMLInputElement>(null);
const handleSave = async () => {
const ipfsGatewayUrls = ipfsGatewayUrlsRef.current?.value.split('\n').map((url) => url.trim());
@@ -169,7 +171,7 @@ const PlebbitOptions = () => {
const maticRpcUrls = maticRpcRef.current?.value.split('\n').map((url) => url.trim());
const avaxRpcUrls = avaxRpcRef.current?.value.split('\n').map((url) => url.trim());
const plebbitRpcClientsOptions = plebbitRpcRef.current?.value.trim();
const dataPath = nodeDataPathRef.current?.value.trim();
const dataPath = plebbitDataPathRef.current?.value.trim();
const chainProviders = {
eth: {
@@ -234,18 +236,20 @@ const PlebbitOptions = () => {
<BlockchainProvidersSettings ethRpcRef={ethRpcRef} solRpcRef={solRpcRef} maticRpcRef={maticRpcRef} avaxRpcRef={avaxRpcRef} />
</span>
</div>
<div className={`${styles.category} ${location.hash === '#nodeRpc' ? styles.highlightedSetting : ''}`} id='nodeRpc'>
<span className={styles.categoryTitle}>node rpc</span>
<div className={`${styles.category} ${location.hash === '#plebbitRpc' ? styles.highlightedSetting : ''}`} id='plebbitRpc'>
<span className={styles.categoryTitle}>plebbit rpc</span>
<span className={styles.categorySettings}>
<PlebbitRPCSettings plebbitRpcRef={plebbitRpcRef} />
</span>
</div>
<div className={styles.category}>
<span className={styles.categoryTitle}>node data path</span>
<span className={styles.categorySettings}>
<NodeDataPathSettings nodeDataPathRef={nodeDataPathRef} />
</span>
</div>
{isElectron && (
<div className={styles.category}>
<span className={styles.categoryTitle}>plebbit data path</span>
<span className={styles.categorySettings}>
<PlebbitDataPathSettings plebbitDataPathRef={plebbitDataPathRef} />
</span>
</div>
)}
<button className={styles.saveOptions} onClick={handleSave}>
{t('save_options')}
</button>