diff --git a/public/assets/buttons/close-x-button.png b/public/assets/buttons/close-x-button.png new file mode 100644 index 00000000..07aa2128 Binary files /dev/null and b/public/assets/buttons/close-x-button.png differ diff --git a/public/translations/ar/default.json b/public/translations/ar/default.json index d146c6c7..1437c5c8 100644 --- a/public/translations/ar/default.json +++ b/public/translations/ar/default.json @@ -303,5 +303,6 @@ "show": "اظهر", "plebbit_options": "خيارات plebbit", "general": "عام", - "own_communities": "المجتمعات الخاصة بي" + "own_communities": "المجتمعات الخاصة بي", + "invalid_community_address": "عنوان المجتمع غير صالح" } \ No newline at end of file diff --git a/public/translations/bn/default.json b/public/translations/bn/default.json index 08c3dda6..dac44a14 100644 --- a/public/translations/bn/default.json +++ b/public/translations/bn/default.json @@ -303,5 +303,6 @@ "show": "দেখান", "plebbit_options": "প্লেবিট বিকল্প", "general": "সাধারণ", - "own_communities": "নিজস্ব সম্প্রদায়" + "own_communities": "নিজস্ব সম্প্রদায়", + "invalid_community_address": "অবৈধ সম্প্রদায় ঠিকানা" } \ No newline at end of file diff --git a/public/translations/cs/default.json b/public/translations/cs/default.json index 6db59c80..df1be12c 100644 --- a/public/translations/cs/default.json +++ b/public/translations/cs/default.json @@ -303,5 +303,6 @@ "show": "ukázat", "plebbit_options": "plebbit možnosti", "general": "obecné", - "own_communities": "vlastní komunity" + "own_communities": "vlastní komunity", + "invalid_community_address": "Neplatná adresa komunity" } \ No newline at end of file diff --git a/public/translations/da/default.json b/public/translations/da/default.json index 95197a07..54f40e11 100644 --- a/public/translations/da/default.json +++ b/public/translations/da/default.json @@ -303,5 +303,6 @@ "show": "vise", "plebbit_options": "plebbit indstillinger", "general": "almindelig", - "own_communities": "egne fællesskaber" + "own_communities": "egne fællesskaber", + "invalid_community_address": "Ugyldig fællesskabsadresse" } \ No newline at end of file diff --git a/public/translations/de/default.json b/public/translations/de/default.json index 7af80197..75c82c90 100644 --- a/public/translations/de/default.json +++ b/public/translations/de/default.json @@ -303,5 +303,6 @@ "show": "zeigen", "plebbit_options": "plebbit optionen", "general": "allgemein", - "own_communities": "eigene Gemeinschaften" + "own_communities": "eigene Gemeinschaften", + "invalid_community_address": "Ungültige Gemeindeadresse" } \ No newline at end of file diff --git a/public/translations/el/default.json b/public/translations/el/default.json index 709d0982..c2d50198 100644 --- a/public/translations/el/default.json +++ b/public/translations/el/default.json @@ -303,5 +303,6 @@ "show": "εμφάνιση", "plebbit_options": "επιλογές plebbit", "general": "γενικός", - "own_communities": "δικές μου κοινότητες" + "own_communities": "δικές μου κοινότητες", + "invalid_community_address": "Μη έγκυρη διεύθυνση κοινότητας" } \ No newline at end of file diff --git a/public/translations/en/default.json b/public/translations/en/default.json index 803a822d..f8b44050 100644 --- a/public/translations/en/default.json +++ b/public/translations/en/default.json @@ -303,5 +303,6 @@ "show": "show", "plebbit_options": "plebbit options", "general": "general", - "own_communities": "own communities" + "own_communities": "own communities", + "invalid_community_address": "Invalid community address" } \ No newline at end of file diff --git a/public/translations/es/default.json b/public/translations/es/default.json index 8443369e..4feddba4 100644 --- a/public/translations/es/default.json +++ b/public/translations/es/default.json @@ -303,5 +303,6 @@ "show": "mostrar", "plebbit_options": "opciones plebbit", "general": "general", - "own_communities": "comunidades propias" + "own_communities": "comunidades propias", + "invalid_community_address": "Dirección de comunidad no válida" } \ No newline at end of file diff --git a/public/translations/fa/default.json b/public/translations/fa/default.json index 4dc44161..4f00f52b 100644 --- a/public/translations/fa/default.json +++ b/public/translations/fa/default.json @@ -303,5 +303,6 @@ "show": "نمایش", "plebbit_options": "گزینه های plebbit", "general": "عمومی", - "own_communities": "انجمن‌های خودم" + "own_communities": "انجمن‌های خودم", + "invalid_community_address": "آدرس انجمن نامعتبر است" } \ No newline at end of file diff --git a/public/translations/fi/default.json b/public/translations/fi/default.json index 4743ab81..2da6b41b 100644 --- a/public/translations/fi/default.json +++ b/public/translations/fi/default.json @@ -303,5 +303,6 @@ "show": "näyttää", "plebbit_options": "plebbit-vaihtoehdot", "general": "yleinen", - "own_communities": "omat yhteisöt" + "own_communities": "omat yhteisöt", + "invalid_community_address": "Virheellinen yhteisön osoite" } \ No newline at end of file diff --git a/public/translations/fil/default.json b/public/translations/fil/default.json index 8ac721fa..98f1945e 100644 --- a/public/translations/fil/default.json +++ b/public/translations/fil/default.json @@ -303,5 +303,6 @@ "show": "ipakita", "plebbit_options": "mga pagpipilian ng plebbit", "general": "pangkalahatan", - "own_communities": "sariling mga pamayanan" + "own_communities": "sariling mga pamayanan", + "invalid_community_address": "Hindi wastong address ng pamayanan" } \ No newline at end of file diff --git a/public/translations/fr/default.json b/public/translations/fr/default.json index 8dddb11e..9da034b3 100644 --- a/public/translations/fr/default.json +++ b/public/translations/fr/default.json @@ -303,5 +303,6 @@ "show": "montrer", "plebbit_options": "options plebbit", "general": "général", - "own_communities": "communautés propres" + "own_communities": "communautés propres", + "invalid_community_address": "Adresse de la communauté non valide" } \ No newline at end of file diff --git a/public/translations/he/default.json b/public/translations/he/default.json index 3e79849c..f22ac893 100644 --- a/public/translations/he/default.json +++ b/public/translations/he/default.json @@ -303,5 +303,6 @@ "show": "תצוגה", "plebbit_options": "אפשרויות plebbit", "general": "כללי", - "own_communities": "הקהילות שלי" + "own_communities": "הקהילות שלי", + "invalid_community_address": "כתובת הקהילה אינה חוקית" } \ No newline at end of file diff --git a/public/translations/hi/default.json b/public/translations/hi/default.json index dfe1bf01..7f4db9ee 100644 --- a/public/translations/hi/default.json +++ b/public/translations/hi/default.json @@ -303,5 +303,6 @@ "show": "दिखाएँ", "plebbit_options": "plebbit विकल्प", "general": "सामान्य", - "own_communities": "खुद की समुदायें" + "own_communities": "खुद की समुदायें", + "invalid_community_address": "अमान्य समुदाय पता" } \ No newline at end of file diff --git a/public/translations/hu/default.json b/public/translations/hu/default.json index 04dcfd28..c686121d 100644 --- a/public/translations/hu/default.json +++ b/public/translations/hu/default.json @@ -303,5 +303,6 @@ "show": "mutat", "plebbit_options": "plebbit lehetőségek", "general": "általános", - "own_communities": "saját közösségek" + "own_communities": "saját közösségek", + "invalid_community_address": "Érvénytelen közösségi cím" } \ No newline at end of file diff --git a/public/translations/id/default.json b/public/translations/id/default.json index 347a6e08..725e3a84 100644 --- a/public/translations/id/default.json +++ b/public/translations/id/default.json @@ -303,5 +303,6 @@ "show": "menunjukkan", "plebbit_options": "opsi plebbit", "general": "umum", - "own_communities": "komunitas sendiri" + "own_communities": "komunitas sendiri", + "invalid_community_address": "Alamat komunitas tidak valid" } \ No newline at end of file diff --git a/public/translations/it/default.json b/public/translations/it/default.json index c7628d73..5a869e76 100644 --- a/public/translations/it/default.json +++ b/public/translations/it/default.json @@ -303,5 +303,6 @@ "show": "mostra", "plebbit_options": "opzioni plebbit", "general": "generali", - "own_communities": "comunità che possiedo" + "own_communities": "comunità che possiedo", + "invalid_community_address": "Indirizzo comunità non valido" } \ No newline at end of file diff --git a/public/translations/ja/default.json b/public/translations/ja/default.json index 6a6d3e94..783f9629 100644 --- a/public/translations/ja/default.json +++ b/public/translations/ja/default.json @@ -303,5 +303,6 @@ "show": "表示", "plebbit_options": "plebbitのオプション", "general": "一般的な", - "own_communities": "自分のコミュニティ" + "own_communities": "自分のコミュニティ", + "invalid_community_address": "無効なコミュニティアドレス" } \ No newline at end of file diff --git a/public/translations/ko/default.json b/public/translations/ko/default.json index 3b575b52..3d042d85 100644 --- a/public/translations/ko/default.json +++ b/public/translations/ko/default.json @@ -303,5 +303,6 @@ "show": "보여주다", "plebbit_options": "plebbit 옵션", "general": "일반", - "own_communities": "나의 커뮤니티" + "own_communities": "나의 커뮤니티", + "invalid_community_address": "잘못된 커뮤니티 주소" } \ No newline at end of file diff --git a/public/translations/mr/default.json b/public/translations/mr/default.json index 2b9afe0a..6af94f8a 100644 --- a/public/translations/mr/default.json +++ b/public/translations/mr/default.json @@ -303,5 +303,6 @@ "show": "दाखवा", "plebbit_options": "प्लेबिट पर्याय", "general": "सामान्य", - "own_communities": "स्वत: समुदाये" + "own_communities": "स्वत: समुदाये", + "invalid_community_address": "अवैध समुदाय पत्ता" } \ No newline at end of file diff --git a/public/translations/nl/default.json b/public/translations/nl/default.json index 8cef5c4b..4fb9c5ae 100644 --- a/public/translations/nl/default.json +++ b/public/translations/nl/default.json @@ -303,5 +303,6 @@ "show": "tonen", "plebbit_options": "plebbit-opties", "general": "algemeen", - "own_communities": "eigen gemeenschappen" + "own_communities": "eigen gemeenschappen", + "invalid_community_address": "Ongeldig gemeenschapsadres" } \ No newline at end of file diff --git a/public/translations/no/default.json b/public/translations/no/default.json index 9a5da4e2..cdda3f88 100644 --- a/public/translations/no/default.json +++ b/public/translations/no/default.json @@ -303,5 +303,6 @@ "show": "vise", "plebbit_options": "plebbit alternativer", "general": "generell", - "own_communities": "egne fellesskap" + "own_communities": "egne fellesskap", + "invalid_community_address": "Ugyldig fellesskapsadresse" } \ No newline at end of file diff --git a/public/translations/pl/default.json b/public/translations/pl/default.json index 84aef444..0d14a53c 100644 --- a/public/translations/pl/default.json +++ b/public/translations/pl/default.json @@ -303,5 +303,6 @@ "show": "pokazać", "plebbit_options": "opcje plebbit", "general": "ogólny", - "own_communities": "własne społeczności" + "own_communities": "własne społeczności", + "invalid_community_address": "Nieprawidłowy adres społeczności" } \ No newline at end of file diff --git a/public/translations/pt/default.json b/public/translations/pt/default.json index 7b856031..f95a86ad 100644 --- a/public/translations/pt/default.json +++ b/public/translations/pt/default.json @@ -303,5 +303,6 @@ "show": "mostrar", "plebbit_options": "opções plebbit", "general": "geral", - "own_communities": "comunidades próprias" + "own_communities": "comunidades próprias", + "invalid_community_address": "Endereço da comunidade inválido" } \ No newline at end of file diff --git a/public/translations/ro/default.json b/public/translations/ro/default.json index f8936269..bd3b1035 100644 --- a/public/translations/ro/default.json +++ b/public/translations/ro/default.json @@ -303,5 +303,6 @@ "show": "arată", "plebbit_options": "opțiuni plebbit", "general": "general", - "own_communities": "comunități proprii" + "own_communities": "comunități proprii", + "invalid_community_address": "Adresă comunitară nevalidă" } \ No newline at end of file diff --git a/public/translations/ru/default.json b/public/translations/ru/default.json index 0f251866..b4d320d8 100644 --- a/public/translations/ru/default.json +++ b/public/translations/ru/default.json @@ -303,5 +303,6 @@ "show": "показать", "plebbit_options": "опции plebbit", "general": "общий", - "own_communities": "собственные сообщества" + "own_communities": "собственные сообщества", + "invalid_community_address": "Недействительный адрес сообщества" } \ No newline at end of file diff --git a/public/translations/sq/default.json b/public/translations/sq/default.json index 0efa1026..3144682c 100644 --- a/public/translations/sq/default.json +++ b/public/translations/sq/default.json @@ -303,5 +303,6 @@ "show": "shfaq", "plebbit_options": "opsione plebbit", "general": "i përgjithshëm", - "own_communities": "komunitete të mia" + "own_communities": "komunitete të mia", + "invalid_community_address": "Adresa e komunitetit e pavlefshme" } \ No newline at end of file diff --git a/public/translations/sv/default.json b/public/translations/sv/default.json index fe279cb2..fd9c4e74 100644 --- a/public/translations/sv/default.json +++ b/public/translations/sv/default.json @@ -303,5 +303,6 @@ "show": "visa", "plebbit_options": "plebbit-alternativ", "general": "allmän", - "own_communities": "egna samhällen" + "own_communities": "egna samhällen", + "invalid_community_address": "Ogiltig samhällsadress" } \ No newline at end of file diff --git a/public/translations/te/default.json b/public/translations/te/default.json index 01e9c748..37709d95 100644 --- a/public/translations/te/default.json +++ b/public/translations/te/default.json @@ -303,5 +303,6 @@ "show": "చూపించు", "plebbit_options": "plebbit ఎంపికలు", "general": "సాధారణ", - "own_communities": "నా సముదాయాలు" + "own_communities": "నా సముదాయాలు", + "invalid_community_address": "అమాన్యమైన సముదాయ చిరునామా" } \ No newline at end of file diff --git a/public/translations/th/default.json b/public/translations/th/default.json index f46b3bde..d22a40f0 100644 --- a/public/translations/th/default.json +++ b/public/translations/th/default.json @@ -303,5 +303,6 @@ "show": "แสดง", "plebbit_options": "ตัวเลือก plebbit", "general": "ทั่วไป", - "own_communities": "ชุมชนของฉัน" + "own_communities": "ชุมชนของฉัน", + "invalid_community_address": "ที่อยู่ชุมชนไม่ถูกต้อง" } \ No newline at end of file diff --git a/public/translations/tr/default.json b/public/translations/tr/default.json index efde2ecd..6aaf6daa 100644 --- a/public/translations/tr/default.json +++ b/public/translations/tr/default.json @@ -303,5 +303,6 @@ "show": "göstermek", "plebbit_options": "plebbit seçenekleri", "general": "genel", - "own_communities": "kendi topluluklarım" + "own_communities": "kendi topluluklarım", + "invalid_community_address": "Geçersiz topluluk adresi" } \ No newline at end of file diff --git a/public/translations/uk/default.json b/public/translations/uk/default.json index 9da4132e..eb8de81d 100644 --- a/public/translations/uk/default.json +++ b/public/translations/uk/default.json @@ -303,5 +303,6 @@ "show": "показати", "plebbit_options": "плебіт варіанти", "general": "загальний", - "own_communities": "власні спільноти" + "own_communities": "власні спільноти", + "invalid_community_address": "Недійсна адреса спільноти" } \ No newline at end of file diff --git a/public/translations/ur/default.json b/public/translations/ur/default.json index d3fe3d9c..a9acf943 100644 --- a/public/translations/ur/default.json +++ b/public/translations/ur/default.json @@ -303,5 +303,6 @@ "show": "دکھائیں", "plebbit_options": "پلیبٹ اختیارات", "general": "عام", - "own_communities": "اپنی کمیونٹیاں" + "own_communities": "اپنی کمیونٹیاں", + "invalid_community_address": "غیر درست مجتمع کا پتہ" } \ No newline at end of file diff --git a/public/translations/vi/default.json b/public/translations/vi/default.json index 983dff8d..82b949dd 100644 --- a/public/translations/vi/default.json +++ b/public/translations/vi/default.json @@ -303,5 +303,6 @@ "show": "hiển thị", "plebbit_options": "tùy chọn plebbit", "general": "chung", - "own_communities": "cộng đồng của riêng tôi" + "own_communities": "cộng đồng của riêng tôi", + "invalid_community_address": "Địa chỉ cộng đồng không hợp lệ" } \ No newline at end of file diff --git a/public/translations/zh/default.json b/public/translations/zh/default.json index 4293737a..9ed2ecf8 100644 --- a/public/translations/zh/default.json +++ b/public/translations/zh/default.json @@ -303,5 +303,6 @@ "show": "显示", "plebbit_options": "plebbit选项", "general": "一般", - "own_communities": "自己的社区" + "own_communities": "自己的社区", + "invalid_community_address": "无效的社区地址" } \ No newline at end of file diff --git a/src/app.tsx b/src/app.tsx index fcea846f..ce449717 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -26,16 +26,13 @@ import TopBar from './components/topbar'; export const sortTypes = ['hot', 'new', 'active', 'controversialAll', 'topAll']; const CheckRouteParams = () => { - const { accountCommentIndex, commentCid, sortType, subplebbitAddress, timeFilterName } = useParams(); - + const { accountCommentIndex, sortType, timeFilterName } = useParams(); const isValidAccountCommentIndex = !accountCommentIndex || (!isNaN(parseInt(accountCommentIndex)) && parseInt(accountCommentIndex) >= 0); - const isValidCommentCid = !commentCid || /^Qm[a-zA-Z0-9]{44}$/.test(commentCid); - const isValidSubplebbitAddress = !subplebbitAddress || subplebbitAddress.includes('.') || /^12D3K[a-zA-Z0-9]{44}$/.test(subplebbitAddress); const isSortTypeValid = !sortType || sortTypes.includes(sortType); const isTimeFilterNameValid = !timeFilterName || timeFilterNames.includes(timeFilterName as any); const isAccountCommentIndexValid = !accountCommentIndex || !isNaN(parseInt(accountCommentIndex)); - if (!isValidAccountCommentIndex || !isValidCommentCid || !isValidSubplebbitAddress || !isSortTypeValid || !isTimeFilterNameValid || !isAccountCommentIndexValid) { + if (!isValidAccountCommentIndex || !isSortTypeValid || !isTimeFilterNameValid || !isAccountCommentIndexValid) { return ; } @@ -95,6 +92,7 @@ const App = () => { } /> } /> } /> + } /> } /> } /> diff --git a/src/components/account-bar/account-bar.tsx b/src/components/account-bar/account-bar.tsx index 890de39c..5b1d3c76 100644 --- a/src/components/account-bar/account-bar.tsx +++ b/src/components/account-bar/account-bar.tsx @@ -13,9 +13,9 @@ const AccountBar = () => { const location = useLocation(); const params = useParams(); const subplebbitAddress = params.subplebbitAddress; - const isSubplebbit = isSubplebbitView(location.pathname, params); - const isSubmit = isSubmitView(location.pathname); - const isSettings = isSettingsView(location.pathname); + const isInSubplebbitView = isSubplebbitView(location.pathname, params); + const isInSubmitView = isSubmitView(location.pathname); + const isInSettingsView = isSettingsView(location.pathname); const [searchVisible, setSearchVisible] = useState(false); const toggleSearchVisible = () => setSearchVisible(!searchVisible); @@ -33,7 +33,7 @@ const AccountBar = () => { const mailClass = unreadNotificationCount ? styles.mailIconUnread : styles.mailIconRead; let submitLink = '/submit'; - if (isSubplebbit) { + if (isInSubplebbitView) { submitLink = `/p/${subplebbitAddress}/submit`; } @@ -102,7 +102,7 @@ const AccountBar = () => { | - + {t('submit')} @@ -123,7 +123,7 @@ const AccountBar = () => { )} | - + {t('preferences')} diff --git a/src/components/header/header.tsx b/src/components/header/header.tsx index d6c970a4..e7ed9227 100644 --- a/src/components/header/header.tsx +++ b/src/components/header/header.tsx @@ -22,6 +22,7 @@ import { isProfileCommentsView, isProfileDownvotedView, isProfileSubmittedView, + isProfileHiddenView, isSettingsView, isSubmitView, isSubplebbitView, @@ -124,6 +125,7 @@ const AuthorHeaderTabs = () => { const isInProfileCommentsView = isProfileCommentsView(location.pathname); const isInProfileSubmittedView = isProfileSubmittedView(location.pathname); const isInProfileUpvotedView = isProfileUpvotedView(location.pathname); + const isInProfileHiddenView = isProfileHiddenView(location.pathname); const authorRoute = `/u/${params.authorAddress}/c/${params.commentCid}`; const overviewSelectedClass = @@ -173,12 +175,12 @@ const AuthorHeaderTabs = () => { {t('downvoted')} - {/* TODO: implement functionality from API once available
  • - e.preventDefault()}> + {t('hidden')}
  • + {/* TODO: implement functionality from API once available
  • e.preventDefault()}> {t('saved')} diff --git a/src/components/newer-posts-button/index.ts b/src/components/newer-posts-button/index.ts new file mode 100644 index 00000000..02138c92 --- /dev/null +++ b/src/components/newer-posts-button/index.ts @@ -0,0 +1 @@ +export { default } from './newer-posts-button'; diff --git a/src/components/newer-posts-button/newer-posts-button.module.css b/src/components/newer-posts-button/newer-posts-button.module.css new file mode 100644 index 00000000..62e7581a --- /dev/null +++ b/src/components/newer-posts-button/newer-posts-button.module.css @@ -0,0 +1,43 @@ +.newerPostsButton { + position: fixed; + left: 10%; + border-radius: 25px; + background-color: green; + color: white; + z-index: 5; + transition: top 0.3s ease-in-out; + font-size: 13px; +} + +.resetButton { + display: inline-block; + cursor: pointer; + font-weight: 700; + padding: 5px 10px; +} + +.resetButton:hover { + opacity: 0.8; +} + +.hide { + display: none; +} + +.hideButton { + display: inline-block; + cursor: pointer; + background-image: url("/public/assets/buttons/close-x-button.png"); + background-size: cover; + height: 12px; + width: 12px; + transform: translateY(1px); +} + +.hideButtonWrapper { + padding-right: 10px; +} + +.hideButton:hover { + opacity: 0.8; +} \ No newline at end of file diff --git a/src/components/newer-posts-button/newer-posts-button.tsx b/src/components/newer-posts-button/newer-posts-button.tsx new file mode 100644 index 00000000..922ee958 --- /dev/null +++ b/src/components/newer-posts-button/newer-posts-button.tsx @@ -0,0 +1,51 @@ +import { useState, useEffect } from 'react'; +import styles from './newer-posts-button.module.css'; + +interface NewerPostsButtonProps { + subplebbitAddressesWithNewerPosts: string[]; + reset: () => void; +} + +const NewerPostsButton = ({ reset, subplebbitAddressesWithNewerPosts }: NewerPostsButtonProps) => { + const [hideButton, setHideButton] = useState(false); + const [buttonPosition, setButtonPosition] = useState(80); + const hide = hideButton || subplebbitAddressesWithNewerPosts.length === 0; + + const handleNewerPostsButtonClick = () => { + window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); + // Delay the reset and hide actions to ensure smooth scrolling completes first + setTimeout(() => { + reset(); + setHideButton(true); + }, 300); // Adjust the delay as needed + }; + + const handleScroll = () => { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + if (scrollTop > 60) { + setButtonPosition(20); + } else { + setButtonPosition(80 - scrollTop); + } + }; + + useEffect(() => { + window.addEventListener('scroll', handleScroll); + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, []); + + return ( +
    + + Newer Posts + + + setHideButton(true)} /> + +
    + ); +}; + +export default NewerPostsButton; diff --git a/src/components/post/comment-tools/hide-menu/hide-menu.tsx b/src/components/post/comment-tools/hide-menu/hide-menu.tsx index c4ee7ac9..12f03c57 100644 --- a/src/components/post/comment-tools/hide-menu/hide-menu.tsx +++ b/src/components/post/comment-tools/hide-menu/hide-menu.tsx @@ -1,9 +1,11 @@ import { useState } from 'react'; +import { useLocation } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import { Author, useBlock } from '@plebbit/plebbit-react-hooks'; +import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import { autoUpdate, flip, FloatingFocusManager, offset, shift, useClick, useDismiss, useFloating, useId, useInteractions, useRole } from '@floating-ui/react'; +import { isProfileHiddenView } from '../../../../lib/utils/view-utils'; import styles from './hide-menu.module.css'; -import { useTranslation } from 'react-i18next'; -import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; type HideMenuProps = { author?: Author | undefined; @@ -43,7 +45,7 @@ const BlockSubplebbitButton = ({ subplebbitAddress }: HideMenuProps) => { const BlockCommentButton = ({ cid }: HideMenuProps) => { const { t } = useTranslation(); - const { blocked, unblock, block } = useBlock({ address: cid }); + const { blocked, unblock, block } = useBlock({ cid }); return (
    @@ -57,6 +59,9 @@ const HideMenu = ({ author, cid, isAccountMod, subplebbitAddress }: HideMenuProp const [isHideMenuOpen, setIsHideMenuOpen] = useState(false); const toggleIsMenuOpen = () => setIsHideMenuOpen(!isHideMenuOpen); + const isInProfileHiddenView = isProfileHiddenView(useLocation().pathname); + const { unblock } = useBlock({ cid }); + const { refs, floatingStyles, context } = useFloating({ placement: 'bottom-start', open: isHideMenuOpen, @@ -76,9 +81,9 @@ const HideMenu = ({ author, cid, isAccountMod, subplebbitAddress }: HideMenuProp return ( <>
  • - cid && setIsHideMenuOpen(!isHideMenuOpen)}>{t('hide')} + {isInProfileHiddenView ? {t('unhide')} : cid && setIsHideMenuOpen(!isHideMenuOpen)}>{t('hide')}}
  • - {isHideMenuOpen && ( + {isHideMenuOpen && !isInProfileHiddenView && (
    diff --git a/src/components/post/post.tsx b/src/components/post/post.tsx index 2dd3c0c0..97e43645 100644 --- a/src/components/post/post.tsx +++ b/src/components/post/post.tsx @@ -3,7 +3,7 @@ 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, isSubplebbitView } from '../../lib/utils/view-utils'; +import { isAllView, isPostView, isProfileHiddenView, isSubplebbitView } from '../../lib/utils/view-utils'; import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getHostname } from '../../lib/utils/url-utils'; import { getFormattedTimeAgo } from '../../lib/utils/time-utils'; @@ -114,6 +114,7 @@ const Post = ({ index, post = {} }: PostProps) => { const isInAllView = isAllView(location.pathname); const isInPostView = isPostView(location.pathname, params); + const isInProfileHiddenView = isProfileHiddenView(location.pathname); const isInSubplebbitView = isSubplebbitView(location.pathname, params); const [isExpanded, setIsExpanded] = useState(isInPostView); @@ -133,7 +134,7 @@ const Post = ({ index, post = {} }: PostProps) => { const linkUrl = getHostname(link); const linkClass = `${isInPostView ? (link ? styles.externalLink : styles.internalLink) : styles.link} ${pinned ? styles.pinnedLink : ''}`; - const { blocked, unblock } = useBlock({ address: cid }); + const { blocked, unblock } = useBlock({ cid }); const [hasClickedSubscribe, setHasClickedSubscribe] = useState(false); const { subscribe, subscribed } = useSubscribe({ subplebbitAddress }); @@ -153,13 +154,13 @@ const Post = ({ index, post = {} }: PostProps) => { return (
    -
    +
    {t('post_hidden').charAt(0).toUpperCase() + t('post_hidden').slice(1)}
    {t('undo')}
    -
    +
    diff --git a/src/components/reply/reply.tsx b/src/components/reply/reply.tsx index 1aba91ae..e6015a6e 100644 --- a/src/components/reply/reply.tsx +++ b/src/components/reply/reply.tsx @@ -265,7 +265,7 @@ const Reply = ({ cidOfReplyWithContext, depth = 0, isSingleComment, isSingleRepl const [showSpoiler, setShowSpoiler] = useState(false); - const { blocked, unblock } = useBlock({ address: cid }); + const { blocked, unblock } = useBlock({ cid }); const [collapsed, setCollapsed] = useState(blocked); useEffect(() => { if (blocked) { diff --git a/src/components/topbar/topbar.tsx b/src/components/topbar/topbar.tsx index 56f0df08..6a559eb0 100644 --- a/src/components/topbar/topbar.tsx +++ b/src/components/topbar/topbar.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { useAccount, useAccountSubplebbits } from '@plebbit/plebbit-react-hooks'; +import { useAccount } from '@plebbit/plebbit-react-hooks'; import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import styles from './topbar.module.css'; import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits'; @@ -121,8 +121,6 @@ const TopBar = () => { } }; - const { accountSubplebbits } = useAccountSubplebbits(); - return (
    @@ -137,11 +135,9 @@ const TopBar = () => { {t('create_community')} - {accountSubplebbits && Object.keys(accountSubplebbits).length > 0 && ( - - {t('own_communities')} - - )} + + {t('my_communities')} + {t('default_communities')} diff --git a/src/hooks/use-challenge-settings.ts b/src/hooks/use-challenge-settings.ts new file mode 100644 index 00000000..921dace2 --- /dev/null +++ b/src/hooks/use-challenge-settings.ts @@ -0,0 +1,10 @@ +import { usePlebbitRpcSettings } from '@plebbit/plebbit-react-hooks'; + +const useChallengeSettings = (challengeName: string) => { + const { challenges } = usePlebbitRpcSettings().plebbitRpcSettings || {}; + if (challenges) { + return challenges[challengeName] || {}; + } +}; + +export default useChallengeSettings; diff --git a/src/hooks/use-challenges-options.ts b/src/hooks/use-challenges-options.ts new file mode 100644 index 00000000..5362747e --- /dev/null +++ b/src/hooks/use-challenges-options.ts @@ -0,0 +1,21 @@ +import { usePlebbitRpcSettings } from '@plebbit/plebbit-react-hooks'; + +const useChallengesOptions = () => { + const { challenges } = usePlebbitRpcSettings().plebbitRpcSettings || {}; + + const options = Object.keys(challenges || {}).reduce( + (acc, challengeName) => { + const challengeSettings = challenges[challengeName]; + acc[challengeName] = challengeSettings.optionInputs.reduce((optionsAcc: any, input: any) => { + optionsAcc[input.option] = input.default || ''; + return optionsAcc; + }, {}); + return acc; + }, + {} as Record>, + ); + + return options; +}; + +export default useChallengesOptions; diff --git a/src/lib/utils/challenge-utils.ts b/src/lib/utils/challenge-utils.ts index 36f09f82..f0692746 100644 --- a/src/lib/utils/challenge-utils.ts +++ b/src/lib/utils/challenge-utils.ts @@ -61,219 +61,3 @@ export const getPublicationPreview = (publication: any) => { } return publicationPreview; }; - -export const getDefaultChallengeDescription = (challengeType: string) => { - switch (challengeType) { - case 'text-math': - return 'Ask a plain text math question, insecure, use ONLY for testing.'; - case 'captcha-canvas-v3': - return 'make custom image captcha'; - case 'fail': - return 'A challenge that automatically fails with a custom error message.'; - case 'blacklist': - return 'Blacklist author addresses.'; - case 'question': - return "Ask a question, like 'What is the password?'"; - case 'evm-contract-call': - return 'The response from an EVM contract call passes a condition, e.g. a token balance challenge.'; - default: - return ''; - } -}; - -export const getDefaultChallengeOptions = (challengeType: string) => { - switch (challengeType) { - case 'text-math': - return { - difficulty: '', - }; - case 'captcha-canvas-v3': - return { - characters: '', - height: '', - width: '', - color: '', - }; - case 'fail': - return { - error: '', - }; - case 'blacklist': - return { - blacklist: '', - error: '', - }; - case 'question': - return { - question: '', - answer: '', - }; - case 'evm-contract-call': - return { - chainTicker: '', - address: '', - abi: '', - condition: '', - error: '', - }; - default: - return {}; - } -}; - -export type OptionInput = { - option: string; - label: string; - default?: string; - description: string; - placeholder?: string; - required?: boolean; -}; - -export type Exclude = { - postScore?: number; - replyScore?: number; - firstCommentTimestamp?: number; - challenges?: number[]; - post?: boolean; - reply?: boolean; - vote?: boolean; - role?: string[]; - address?: string[]; - rateLimit?: number; - rateLimitChallengeSuccess?: boolean; -}; - -export const getDefaultChallengeSettings = (challengeType: string) => { - switch (challengeType) { - case 'text-math': - return [ - { - option: 'difficulty', - label: 'Difficulty', - default: '1', - description: 'The math difficulty of the challenge between 1-3.', - placeholder: '1', - }, - ]; - case 'captcha-canvas-v3': - return [ - { - option: 'characters', - label: 'Characters', - description: 'Amount of characters of the captcha.', - default: '6', - placeholder: 'example: 6', - }, - { - option: 'height', - label: 'Height', - description: 'Height of the captcha.', - default: '100', - placeholder: 'example: 100', - }, - { - option: 'width', - label: 'Width', - description: 'Width of the captcha.', - default: '300', - placeholder: 'example: 300', - }, - { - option: 'color', - label: 'Color', - description: 'Color of the captcha.', - default: '#32cf7e', - placeholder: 'example: #ff0000,#00ff00,#0000ff', - }, - ]; - case 'fail': - return [ - { - option: 'error', - label: 'Error', - default: "You're not allowed to publish.", - description: 'The error to display to the author.', - placeholder: "You're not allowed to publish.", - }, - ]; - case 'blacklist': - return [ - { - option: 'blacklist', - label: 'Blacklist', - default: '', - description: 'Comma separated list of author addresses to be blacklisted.', - placeholder: 'address1.eth,address2.eth,address3.eth', - }, - { - option: 'error', - label: 'Error', - default: "You're blacklisted.", - description: 'The error to display to the author.', - placeholder: "You're blacklisted.", - }, - ]; - case 'question': - return [ - { - option: 'question', - label: 'Question', - default: '', - description: 'The question to answer.', - placeholder: '', - }, - { - option: 'answer', - label: 'Answer', - default: '', - description: 'The answer to the question.', - placeholder: '', - required: true, - }, - ]; - case 'evm-contract-call': - return [ - { - option: 'chainTicker', - label: 'chainTicker', - default: 'eth', - description: 'The chain ticker', - placeholder: 'eth', - required: true, - }, - { - option: 'address', - label: 'Address', - default: '', - description: 'The contract address.', - placeholder: '0x...', - required: true, - }, - { - option: 'abi', - label: 'ABI', - default: '', - description: 'The ABI of the contract method.', - placeholder: '{"constant":true,"inputs":[{"internalType":"address","name":"account...', - required: true, - }, - { - option: 'condition', - label: 'Condition', - default: '', - description: 'The condition the contract call response must pass.', - placeholder: '>1000', - required: true, - }, - { - option: 'error', - label: 'Error', - default: "Contract call response doesn't pass condition.", - description: 'The error to display to the author.', - }, - ]; - default: - return []; - } -}; diff --git a/src/lib/utils/view-utils.ts b/src/lib/utils/view-utils.ts index e31bbb2a..5aeb2efa 100644 --- a/src/lib/utils/view-utils.ts +++ b/src/lib/utils/view-utils.ts @@ -122,8 +122,12 @@ export const isProfileUpvotedView = (pathname: string): boolean => { return pathname === '/profile/upvoted'; }; +export const isProfileHiddenView = (pathname: string): boolean => { + return pathname === '/profile/hidden'; +}; + export const isSettingsView = (pathname: string): boolean => { - return pathname === '/settings'; + return pathname === '/settings' || pathname === '/settings/plebbit-options'; }; export const isSettingsPlebbitOptionsView = (pathname: string): boolean => { diff --git a/src/views/home/home.module.css b/src/views/home/home.module.css index 5e4b8bff..2a004bca 100644 --- a/src/views/home/home.module.css +++ b/src/views/home/home.module.css @@ -6,6 +6,10 @@ text-transform: lowercase; } +.feed { + position: relative; +} + @media (max-width: 640px) { .content { padding: 7px 2px 0px 2px; diff --git a/src/views/home/home.tsx b/src/views/home/home.tsx index 038472d0..7f05cc87 100644 --- a/src/views/home/home.tsx +++ b/src/views/home/home.tsx @@ -5,6 +5,7 @@ import { useFeed } from '@plebbit/plebbit-react-hooks'; import { useTranslation } from 'react-i18next'; import styles from './home.module.css'; import LoadingEllipsis from '../../components/loading-ellipsis'; +import NewerPostsButton from '../../components/newer-posts-button'; import Post from '../../components/post'; import Sidebar from '../../components/sidebar'; import { useDefaultAndSubscriptionsSubplebbitAddresses } from '../../hooks/use-default-subplebbits'; @@ -21,11 +22,11 @@ const Home = () => { const timeFilterName = params.timeFilterName as TimeFilterKey; const { timeFilter } = useTimeFilter(sortType, timeFilterName); - const { feed, hasMore, loadMore } = useFeed({ - subplebbitAddresses: subplebbitAddresses || [], - sortType, - postsPerPage: 10, + const { feed, hasMore, loadMore, reset, subplebbitAddressesWithNewerPosts } = useFeed({ filter: timeFilter, + postsPerPage: 10, + sortType, + subplebbitAddresses: subplebbitAddresses || [], }); let loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading'); @@ -72,6 +73,7 @@ const Home = () => {
    + {
    {!isSingleComment && (
    - {replyCount !== undefined ? commentCount : t('loading_comments')} + {replyCount !== undefined ? commentCount : `${t('loading_comments')}...`}
    )}
    diff --git a/src/views/profile/profile.tsx b/src/views/profile/profile.tsx index db04d3c6..fd926274 100644 --- a/src/views/profile/profile.tsx +++ b/src/views/profile/profile.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { useLocation, useParams } from 'react-router-dom'; import { StateSnapshot, Virtuoso, VirtuosoHandle } from 'react-virtuoso'; import { useAccount, useAccountComments, useAccountVotes, useComments } from '@plebbit/plebbit-react-hooks'; -import { isProfileDownvotedView, isProfileUpvotedView, isProfileCommentsView, isProfileSubmittedView } from '../../lib/utils/view-utils'; +import { isProfileDownvotedView, isProfileUpvotedView, isProfileCommentsView, isProfileSubmittedView, isProfileHiddenView } from '../../lib/utils/view-utils'; import useWindowWidth from '../../hooks/use-window-width'; import AuthorSidebar from '../../components/author-sidebar'; import Post from '../../components/post'; @@ -17,7 +17,7 @@ type SortDropdownProps = { onSortChange: (sortType: string) => void; }; -const SortDropdown: React.FC = ({ onSortChange }) => { +const SortDropdown = ({ onSortChange }: SortDropdownProps) => { const { t } = useTranslation(); const sortLabels: string[] = sortTypes.map((sortType) => t(sortType)); const [selectedSort, setSelectedSort] = useState(sortTypes[0]); @@ -77,17 +77,21 @@ const Profile = () => { const { accountVotes } = useAccountVotes(); const isInProfileUpvotedView = isProfileUpvotedView(location.pathname); const isInProfileDownvotedView = isProfileDownvotedView(location.pathname); + const isInProfileHiddenView = isProfileHiddenView(location.pathname); const isInCommentsView = isProfileCommentsView(location.pathname); const isInSubmittedView = isProfileSubmittedView(location.pathname); const isMobile = useWindowWidth() < 640; // get comments for upvoted/downvoted/comments/submitted pages + const postComments = useMemo(() => accountComments?.filter((comment) => !comment.parentCid) || [], [accountComments]); + const replyComments = useMemo(() => accountComments?.filter((comment) => comment.parentCid) || [], [accountComments]); const upvotedCommentCids = useMemo(() => accountVotes?.filter((vote) => vote.vote === 1).map((vote) => vote.commentCid) || [], [accountVotes]); const downvotedCommentCids = useMemo(() => accountVotes?.filter((vote) => vote.vote === -1).map((vote) => vote.commentCid) || [], [accountVotes]); - const replyComments = useMemo(() => accountComments?.filter((comment) => comment.parentCid) || [], [accountComments]); - const postComments = useMemo(() => accountComments?.filter((comment) => !comment.parentCid) || [], [accountComments]); + const hiddenCommentCids = useMemo(() => Object.keys(account?.blockedCids ?? {}), [account?.blockedCids]); + const { comments: upvotedComments } = useComments({ commentCids: upvotedCommentCids }); const { comments: downvotedComments } = useComments({ commentCids: downvotedCommentCids }); + const { comments: hiddenComments } = useComments({ commentCids: hiddenCommentCids }); const [sortType, setSortType] = useState('new'); const handleSortChange = (newSortType: string) => { @@ -103,18 +107,22 @@ const Profile = () => { return replyComments; } else if (isInSubmittedView) { return postComments; + } else if (isInProfileHiddenView) { + return hiddenComments; } else { return accountComments; } }, [ isInProfileUpvotedView, isInProfileDownvotedView, + isInProfileHiddenView, isInCommentsView, isInSubmittedView, upvotedComments, downvotedComments, replyComments, postComments, + hiddenComments, accountComments, ]); diff --git a/src/views/settings/plebbit-options/plebbit-options.module.css b/src/views/settings/plebbit-options/plebbit-options.module.css index b19aa818..7dc9f937 100644 --- a/src/views/settings/plebbit-options/plebbit-options.module.css +++ b/src/views/settings/plebbit-options/plebbit-options.module.css @@ -38,11 +38,22 @@ } .content textarea { - height: 80px; font-size: 13px; font-family: Arial, Helvetica, sans-serif; } +.ipfsGatewaysSettings textarea { + height: 80px; +} + +.pubsubProvidersSettings textarea { + height: 50px; +} + +.blockchainProvidersSettings textarea { + height: 50px; +} + .content button { vertical-align: top; margin-left: 5px; @@ -67,6 +78,11 @@ padding-left: 40px; } +.saveOptions { + text-transform: lowercase; + margin-top: 10px; +} + @media (max-width: 640px) { .categoryTitle { flex: 0 0 65px; diff --git a/src/views/settings/plebbit-options/plebbit-options.tsx b/src/views/settings/plebbit-options/plebbit-options.tsx index 1625bcfc..c318ae3f 100644 --- a/src/views/settings/plebbit-options/plebbit-options.tsx +++ b/src/views/settings/plebbit-options/plebbit-options.tsx @@ -1,75 +1,105 @@ -import { useState } from 'react'; -import { useAccount } from '@plebbit/plebbit-react-hooks'; -import styles from './plebbit-options.module.css'; +import { RefObject, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { setAccount, useAccount, usePlebbitRpcSettings } from '@plebbit/plebbit-react-hooks'; +import styles from './plebbit-options.module.css'; -const isElectron = window.isElectron === true; +interface SettingsProps { + ipfsGatewayUrlsRef?: RefObject; + mediaIpfsGatewayUrlRef?: RefObject; + pubsubProvidersRef?: RefObject; + ethRpcRef?: RefObject; + solRpcRef?: RefObject; + maticRpcRef?: RefObject; + avaxRpcRef?: RefObject; + plebbitRpcRef?: RefObject; + nodeDataPathRef?: RefObject; +} -const IPFSGatewaysSettings = ({ ipfsGatewayUrls, mediaIpfsGatewayUrl }: { ipfsGatewayUrls: any; mediaIpfsGatewayUrl: any }) => { - const { t } = useTranslation(); +const IPFSGatewaysSettings = ({ ipfsGatewayUrlsRef, mediaIpfsGatewayUrlRef }: SettingsProps) => { + const account = useAccount(); + const { plebbitOptions, mediaIpfsGatewayUrl } = account || {}; + const { ipfsGatewayUrls } = plebbitOptions || {}; + const plebbitRpc = usePlebbitRpcSettings(); + const isConnectedToRpc = plebbitRpc?.state === 'succeeded'; const ipfsGatewayUrlsDefaultValue = ipfsGatewayUrls?.join('\n'); return (
    -