From fe434cb6343a6a00da1467c4b9094cb507a1fbef Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Tue, 9 Jul 2024 14:59:18 +0200 Subject: [PATCH 01/14] feat(board header): add yellow offline icon for loading online status, red icon for offline status --- public/assets/icons/offline-red.png | Bin 1205 -> 1226 bytes .../icons/{offline.png => offline-yellow.png} | Bin 1270 -> 1217 bytes .../board-header/board-header.module.css | 5 -- src/components/board-header/board-header.tsx | 5 +- src/components/post-form/post-form.tsx | 4 +- src/hooks/use-is-subplebbit-offline.ts | 34 +++++++++--- src/index.css | 8 +++ src/stores/use-subplebbit-offline-store.ts | 51 ++++++++++++++++++ src/views/home/boards-box/boards-box.tsx | 5 +- src/views/home/home.module.css | 5 -- 10 files changed, 93 insertions(+), 24 deletions(-) rename public/assets/icons/{offline.png => offline-yellow.png} (71%) create mode 100644 src/stores/use-subplebbit-offline-store.ts diff --git a/public/assets/icons/offline-red.png b/public/assets/icons/offline-red.png index a02271059af19014cbc76b2eb05623f4e86aae7a..5759f7d6ca9c6c39beb4aa70840c2357b0583f42 100644 GIT binary patch delta 317 zcmV-D0mA;Z3CanumjizuNkl7Z zx~_E>3PEH+GKo~Swe!ALQ3r7xL(r=OkO^QZVoKmWaTJ2eFaYYh&Noe?-S^uUf4X1m zzN#vZNg|40S6`)s>lnYcMl#1f)icT!o2&i!j2% z9bBHuYlZbp6Dx#PlAaeGbbzLi_5&K4@GzH5c@9`NE+^nif)^!yL zfm^obdCu5GLI@`$OaSDj+5fhWwry>_*!TGv$I*hL5JWPPNu+=B)p=)rSFs9;qJW@U z1t1eZE8YV0#8C(;aR9V!o6hrWP1L?oE$=5W41;1)h@_;6=mV|n7Lvgpuyj@u1%N(U z`PPF(-3KTW_uy#3m+m<+25?!Hc$pxC+%!!u{y|DCP^IfSJC%5q?w87rkC>lUv++3h ucZ8R>Kp@C+cncuR`}M7W2mTfRV&Mi`ccvysY@;Ip0000Zt~5Zpw(f##k=L&F1-Cr~0H@dR|SsPcw9 zASp;gdEcNrA)R7W?7a>h|fk|-c$Mc z`~t*Y4y8hkF%K?h6(BLsa~Xy~PH)D=Ns=Ud))!Dn1wgKCF{_ zNJKJ;RQ6|QeNs^eS(ZW2ssoS-;3zU>;4apQ1KI8C9iVX>ZQu8rzO||S{+Pc++qM>) zLL_fOL=GG!lmV^N$tnOvca*;}po3pe*o1&Pf^VI~jRO<`EQ&&!M&$K*4iZ0+Z#^i0 zMl-QF;|x@xed;V!37r_j&mx4~)%^^1fTi#lYWz$6o)NBKbe@_iLCr@10000I*TzllK&JRjLL1B3X z1>px+8FGb{EwSJqXuR5j#sU**t~Rn(})SM&y6GE(&r0ghYVJaU2UE zNs>RH4}!$9EG3#kEHVZeL?}B8zcV}Pt%}q=&tpL)4wwu8M#(pFpx#gij>)=-gh5Ty zsH&=zvskOUrwcjp5AsVMUgymHn00000NkvXX Hu0mjf*kY=g diff --git a/src/components/board-header/board-header.module.css b/src/components/board-header/board-header.module.css index cc553a7f..dc0414d5 100644 --- a/src/components/board-header/board-header.module.css +++ b/src/components/board-header/board-header.module.css @@ -29,7 +29,6 @@ } .offlineIcon { - background-image: url('/public/assets/icons/offline.png'); display: inline-block; margin-left: 10px; width: 16px; @@ -39,10 +38,6 @@ image-rendering: pixelated; } -.redOfflineIcon { - background-image: url('/public/assets/icons/offline-red.png') !important; -} - @media (max-width: 640px) { .boardTitle { padding-top: 40px; diff --git a/src/components/board-header/board-header.tsx b/src/components/board-header/board-header.tsx index e891ac77..dbcc7bd5 100644 --- a/src/components/board-header/board-header.tsx +++ b/src/components/board-header/board-header.tsx @@ -34,8 +34,7 @@ const BoardHeader = () => { const title = isInAllView ? multisubMetadata?.title || 'all' : isInSubscriptionsView ? 'Subscriptions' : subplebbit?.title; const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : `p/${address}`; - const { isOffline, isDefinitelyOffline, offlineTitle } = useIsSubplebbitOffline(subplebbit); - const iconClass = `${styles.offlineIcon} ${isDefinitelyOffline ? styles.redOfflineIcon : ''}`; + const { isOffline, isOnlineStatusLoading, offlineIconClass, offlineTitle } = useIsSubplebbitOffline(subplebbit); return (
@@ -46,7 +45,7 @@ const BoardHeader = () => { )}
{title || `p/${shortAddress || subplebbitAddress}`} - {isOffline && } + {(isOffline || isOnlineStatusLoading) && }
{subtitle}

diff --git a/src/components/post-form/post-form.tsx b/src/components/post-form/post-form.tsx index 287cbbf8..eb63ce62 100644 --- a/src/components/post-form/post-form.tsx +++ b/src/components/post-form/post-form.tsx @@ -277,7 +277,7 @@ const PostForm = () => { return ( <>
- {!(isInAllView || isInSubscriptionsView) && showForm && isOffline &&
{offlineTitle}
} + {!(isInAllView || isInSubscriptionsView) && showForm && (isOffline || isOffline) &&
{offlineTitle}
} {isThreadClosed ? (
{t('thread_closed')} @@ -297,7 +297,7 @@ const PostForm = () => { )}
- {!(isInAllView || isInSubscriptionsView) && showForm && isOffline &&
{offlineTitle}
} + {!(isInAllView || isInSubscriptionsView) && showForm && (isOffline || isOffline) &&
{offlineTitle}
} {isThreadClosed ? (
{t('thread_closed')} diff --git a/src/hooks/use-is-subplebbit-offline.ts b/src/hooks/use-is-subplebbit-offline.ts index 33875c20..91d914d7 100644 --- a/src/hooks/use-is-subplebbit-offline.ts +++ b/src/hooks/use-is-subplebbit-offline.ts @@ -1,19 +1,41 @@ import { useTranslation } from 'react-i18next'; +import { useEffect } from 'react'; import { Subplebbit } from '@plebbit/plebbit-react-hooks'; import { getFormattedTimeAgo } from '../lib/utils/time-utils'; +import useSubplebbitOfflineStore from '../stores/use-subplebbit-offline-store'; const useIsSubplebbitOffline = (subplebbit: Subplebbit) => { const { t } = useTranslation(); - const { updatedAt, updatingState } = subplebbit || {}; - const isProbablyOffline = !updatedAt || (updatedAt && updatedAt < Date.now() / 1000 - 60 * 60); - const isDefinitelyOffline = updatingState === 'failed'; - const isOffline = isProbablyOffline || isDefinitelyOffline; + const { address, state, updatedAt, updatingState } = subplebbit || {}; + const { subplebbitOfflineState, setSubplebbitOfflineState, initializesubplebbitOfflineState } = useSubplebbitOfflineStore(); - const offlineTitle = updatedAt + useEffect(() => { + if (address && !subplebbitOfflineState[address]) { + initializesubplebbitOfflineState(address); + } + }, [address, subplebbitOfflineState, initializesubplebbitOfflineState]); + + useEffect(() => { + if (address) { + setSubplebbitOfflineState(address, { state, updatedAt, updatingState }); + } + }, [address, state, updatedAt, updatingState, setSubplebbitOfflineState]); + + const subplebbitData = subplebbitOfflineState[address] || { initialLoad: true }; + + const isLoading = (updatingState === 'resolving-address' && state !== 'stopped') || (subplebbitData.initialLoad && updatingState === 'fetching-ipns' && !updatedAt); + const isOffline = + !isLoading && ((updatedAt && updatedAt < Date.now() / 1000 - 60 * 60) || updatingState === 'failed' || (updatingState === 'fetching-ipns' && !updatedAt)); + + const offlineIconClass = isLoading ? 'yellowOfflineIcon' : isOffline ? 'redOfflineIcon' : ''; + + const offlineTitle = isLoading + ? t('loading') + : updatedAt ? isOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } }) : t('subplebbit_offline_info'); - return { isOffline, isDefinitelyOffline, offlineTitle }; + return { isOffline, isOnlineStatusLoading: isLoading, offlineIconClass, offlineTitle }; }; export default useIsSubplebbitOffline; diff --git a/src/index.css b/src/index.css index ae102085..918e52c5 100644 --- a/src/index.css +++ b/src/index.css @@ -38,6 +38,14 @@ hr { color-scheme: dark; } +.yellowOfflineIcon { + background-image: url('/public/assets/icons/offline-yellow.png'); +} + +.redOfflineIcon { + background-image: url('/public/assets/icons/offline-red.png'); +} + @media (max-width: 640px) { .button { font-size: var(--button-font-size-mobile); diff --git a/src/stores/use-subplebbit-offline-store.ts b/src/stores/use-subplebbit-offline-store.ts new file mode 100644 index 00000000..4fcb8b0d --- /dev/null +++ b/src/stores/use-subplebbit-offline-store.ts @@ -0,0 +1,51 @@ +import { create } from 'zustand'; + +interface SubplebbitOfflineState { + state?: string; + updatedAt?: number; + updatingState?: string; + initialLoad: boolean; +} + +interface SubplebbitOfflineStore { + subplebbitOfflineState: Record; + setSubplebbitOfflineState: (address: string, state: Partial) => void; + initializesubplebbitOfflineState: (address: string) => void; +} + +const useSubplebbitOfflineStore = create((set) => ({ + subplebbitOfflineState: {}, + setSubplebbitOfflineState: (address, newState) => + set((state) => ({ + subplebbitOfflineState: { + ...state.subplebbitOfflineState, + [address]: { + ...state.subplebbitOfflineState[address], + ...newState, + }, + }, + })), + initializesubplebbitOfflineState: (address) => { + set((state) => ({ + subplebbitOfflineState: { + ...state.subplebbitOfflineState, + [address]: { + initialLoad: true, + }, + }, + })); + setTimeout(() => { + set((state) => ({ + subplebbitOfflineState: { + ...state.subplebbitOfflineState, + [address]: { + ...state.subplebbitOfflineState[address], + initialLoad: false, + }, + }, + })); + }, 7000); + }, +})); + +export default useSubplebbitOfflineStore; diff --git a/src/views/home/boards-box/boards-box.tsx b/src/views/home/boards-box/boards-box.tsx index 6f9cda02..81902c00 100644 --- a/src/views/home/boards-box/boards-box.tsx +++ b/src/views/home/boards-box/boards-box.tsx @@ -18,12 +18,11 @@ const Board = ({ subplebbit, subplebbits }: { subplebbit: Subplebbit; subplebbit const boardLink = useCatalog ? `/p/${address}/catalog` : `/p/${address}`; const subplebbitData = subplebbits && subplebbits.find((sub: Subplebbit) => sub?.address === address); - const { isDefinitelyOffline, isOffline, offlineTitle } = useIsSubplebbitOffline(subplebbitData); - const iconClass = `${styles.offlineIcon} ${isDefinitelyOffline ? styles.redOfflineIcon : ''}`; + const { isOffline, isOnlineStatusLoading, offlineIconClass, offlineTitle } = useIsSubplebbitOffline(subplebbitData); return (
- {isOffline && } + {(isOffline || isOnlineStatusLoading) && } {title || address} {nsfwTag && ({t(nsfwTag)})}
diff --git a/src/views/home/home.module.css b/src/views/home/home.module.css index 9e28a197..d3d71f61 100644 --- a/src/views/home/home.module.css +++ b/src/views/home/home.module.css @@ -176,7 +176,6 @@ } .offlineIcon { - background-image: url('/public/assets/icons/offline.png'); display: inline-block; vertical-align: text-top; margin-right: 2px; @@ -187,10 +186,6 @@ image-rendering: pixelated; } -.redOfflineIcon { - background-image: url('/public/assets/icons/offline-red.png') !important; -} - .boardsBoxContent { font-size: 93%; padding: 0.5em; From f37765ee635fa5594f67078b71b828a88c4b41fb Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Tue, 9 Jul 2024 18:55:59 +0200 Subject: [PATCH 02/14] Update use-is-subplebbit-offline.ts --- src/hooks/use-is-subplebbit-offline.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hooks/use-is-subplebbit-offline.ts b/src/hooks/use-is-subplebbit-offline.ts index 91d914d7..70181ff8 100644 --- a/src/hooks/use-is-subplebbit-offline.ts +++ b/src/hooks/use-is-subplebbit-offline.ts @@ -21,9 +21,13 @@ const useIsSubplebbitOffline = (subplebbit: Subplebbit) => { } }, [address, state, updatedAt, updatingState, setSubplebbitOfflineState]); - const subplebbitData = subplebbitOfflineState[address] || { initialLoad: true }; + const subplebbitOfflineStore = subplebbitOfflineState[address] || { initialLoad: true }; + + const isLoading = + updatingState === 'resolving-address' || + (updatingState === 'stopped' && state === 'stopped' && !updatedAt) || + (subplebbitOfflineStore.initialLoad && updatingState === 'fetching-ipns' && !updatedAt); - const isLoading = (updatingState === 'resolving-address' && state !== 'stopped') || (subplebbitData.initialLoad && updatingState === 'fetching-ipns' && !updatedAt); const isOffline = !isLoading && ((updatedAt && updatedAt < Date.now() / 1000 - 60 * 60) || updatingState === 'failed' || (updatingState === 'fetching-ipns' && !updatedAt)); From 14ef6fe1aa216e34a277634c068fbfbc8be24bf4 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Tue, 9 Jul 2024 22:36:10 +0200 Subject: [PATCH 03/14] style(settings): limit resize of textareas --- .../plebbit-options/plebbit-options.module.css | 5 ++++- src/components/settings-modal/settings-modal.module.css | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/settings-modal/plebbit-options/plebbit-options.module.css b/src/components/settings-modal/plebbit-options/plebbit-options.module.css index c1297b5f..5c5bc39d 100644 --- a/src/components/settings-modal/plebbit-options/plebbit-options.module.css +++ b/src/components/settings-modal/plebbit-options/plebbit-options.module.css @@ -18,14 +18,17 @@ } .ipfsGatewaysSettings textarea { - height: 70px; + min-height: 80px; + height: 80px; } .pubsubProvidersSettings textarea { + min-height: 50px; height: 50px; } .blockchainProvidersSettings textarea { + min-height: 50px; height: 50px; } diff --git a/src/components/settings-modal/settings-modal.module.css b/src/components/settings-modal/settings-modal.module.css index a0461b47..28fd4fb8 100644 --- a/src/components/settings-modal/settings-modal.module.css +++ b/src/components/settings-modal/settings-modal.module.css @@ -42,6 +42,10 @@ border-left: var(--settings-modal-border-left); } +.settingsModal textarea { + resize: vertical; +} + .settingsModal select, .settingsModal button, .settingsModal textarea, .settingsModal input[type='text'] { filter: var(--filter80); } From d66a0b8efe49f0401e04155e177f60d4493e289a Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Wed, 10 Jul 2024 12:36:44 +0200 Subject: [PATCH 04/14] fix(themes): inherit selected theme in pending post page --- src/hooks/use-initial-theme.ts | 8 ++++++-- src/stores/use-theme-store.ts | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/hooks/use-initial-theme.ts b/src/hooks/use-initial-theme.ts index 5ec6209c..571b06f2 100644 --- a/src/hooks/use-initial-theme.ts +++ b/src/hooks/use-initial-theme.ts @@ -1,21 +1,25 @@ import { useLocation, useParams } from 'react-router-dom'; import useThemeStore from '../stores/use-theme-store'; import useDefaultSubplebbits from './use-default-subplebbits'; -import { isAllView, isHomeView, isNotFoundView, isSubscriptionsView } from '../lib/utils/view-utils'; +import { isAllView, isHomeView, isNotFoundView, isPendingPostView, isSubscriptionsView } from '../lib/utils/view-utils'; import { nsfwTags } from '../views/home/home'; const useInitialTheme = () => { const location = useLocation(); const { subplebbitAddress } = useParams<{ subplebbitAddress: string }>(); const getTheme = useThemeStore((state) => state.getTheme); + const currentTheme = useThemeStore((state) => state.currentTheme); const subplebbits = useDefaultSubplebbits(); const params = useParams(); const isInHomeView = isHomeView(location.pathname); const isInNotFoundView = isNotFoundView(location.pathname, params); const isInAllView = isAllView(location.pathname, params); const isInSubscriptionsView = isSubscriptionsView(location.pathname, params); + const isInPendingPostView = isPendingPostView(location.pathname, params); - if (isInAllView) { + if (isInPendingPostView) { + return currentTheme || 'yotsuba'; + } else if (isInAllView) { return getTheme('all') || 'yotsuba-b'; } else if (isInSubscriptionsView) { return getTheme('subscriptions') || 'yotsuba-b'; diff --git a/src/stores/use-theme-store.ts b/src/stores/use-theme-store.ts index 95fe3941..cda02a4f 100644 --- a/src/stores/use-theme-store.ts +++ b/src/stores/use-theme-store.ts @@ -8,6 +8,7 @@ interface ThemeState { all: string; subscriptions: string; }; + currentTheme: string | null; setTheme: (category: keyof ThemeState['themes'], theme: string) => void; getTheme: (category: keyof ThemeState['themes']) => string | null; loadThemes: () => Promise; @@ -25,15 +26,18 @@ const useThemeStore = create((set: StoreApi['setState'], all: 'yotsuba-b', subscriptions: 'yotsuba-b', }, + currentTheme: null, setTheme: async (category, theme) => { const currentThemes = get().themes; const updatedThemes = { ...currentThemes, [category]: theme }; await themeStore.setItem(category, theme); - set({ themes: updatedThemes }); + set({ themes: updatedThemes, currentTheme: theme }); }, getTheme: (category) => { const currentThemes = get().themes; - return currentThemes[category] || null; + const theme = currentThemes[category] || null; + set({ currentTheme: theme }); + return theme; }, loadThemes: async () => { const entries: [keyof ThemeState['themes'], string][] = await themeStore.entries(); @@ -46,7 +50,7 @@ const useThemeStore = create((set: StoreApi['setState'], entries.forEach(([key, value]) => { themes[key] = value; }); - set({ themes }); + set({ themes, currentTheme: null }); }, })); From a31beee6318047e3bed5f02820468360e6b3db5c Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Wed, 10 Jul 2024 17:42:38 +0200 Subject: [PATCH 05/14] fix(topbar): empty brackets would show for sub category if empty --- src/components/topbar/topbar.tsx | 75 +++++++++++++++++--------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/src/components/topbar/topbar.tsx b/src/components/topbar/topbar.tsx index aa4a138d..f13a99f5 100644 --- a/src/components/topbar/topbar.tsx +++ b/src/components/topbar/topbar.tsx @@ -63,46 +63,49 @@ const TopBarDesktop = () => { const { plebbitSubs, interestsSubs, randomSubs, internationalSubs, projectsSubs } = categorizeSubplebbits(subplebbits); - const renderSubplebbits = (subplebbits: any) => { - return subplebbits.map((sub: any, index: any) => ( - - {index === 0 ? null : ' '} - {sub.address.includes('.') ? sub.address : sub.address.slice(0, 10).concat('...')} - {index !== subplebbits.length - 1 ? ' /' : null} - - )); - }; + const renderSubplebbits = (subplebbits: any) => + subplebbits.length > 0 && ( + <> + [ + {subplebbits.map((sub: any, index: any) => ( + + {index === 0 ? null : ' '} + {sub.address.includes('.') ? sub.address : sub.address.slice(0, 10).concat('...')} + {index !== subplebbits.length - 1 ? ' /' : null} + + ))} + ]{' '} + + ); return (
- [all / subscriptions]{' '} - {subplebbits && ( - <> - [{renderSubplebbits(plebbitSubs)}] [{renderSubplebbits(projectsSubs)}] [{renderSubplebbits(interestsSubs)}] [{renderSubplebbits(randomSubs)}] [ - {renderSubplebbits(internationalSubs)}] [ - { - e.preventDefault(); - alert('work in progress'); - }} - > - Create - - ] [ - { - e.preventDefault(); - alert('work in progress'); - }} - > - Vote - - ] - - )} + [all / subscriptions] {renderSubplebbits(plebbitSubs)} + {renderSubplebbits(projectsSubs)} + {renderSubplebbits(interestsSubs)} + {renderSubplebbits(randomSubs)} + {renderSubplebbits(internationalSubs)}[ + { + e.preventDefault(); + alert('work in progress'); + }} + > + Create + + ] [ + { + e.preventDefault(); + alert('work in progress'); + }} + > + Vote + + ] [{t('settings')}] [ From 811405dea9d72ef41a115d7a0e110c57b1040f89 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Wed, 10 Jul 2024 17:51:58 +0200 Subject: [PATCH 06/14] fix(subplebbit stats): stats box appeared even if stats are undefined --- src/components/subplebbit-stats/subplebbit-stats.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/subplebbit-stats/subplebbit-stats.tsx b/src/components/subplebbit-stats/subplebbit-stats.tsx index 42de8e08..4b527b46 100644 --- a/src/components/subplebbit-stats/subplebbit-stats.tsx +++ b/src/components/subplebbit-stats/subplebbit-stats.tsx @@ -15,16 +15,16 @@ const SubplebbitStats = () => { const subplebbit = useSubplebbit({ subplebbitAddress }); const { address, createdAt } = subplebbit || {}; + const stats = useSubplebbitStats({ subplebbitAddress: address }); + const [showStats, setShowStats] = useState(true); + const location = useLocation(); const isInDescriptionView = isDescriptionView(location.pathname, params); const isInRulesView = isRulesView(location.pathname, params); const comment = useComment({ commentCid: params?.commentCid }); const { deleted, locked, removed } = comment || {}; - const hideStats = deleted || locked || removed || isInDescriptionView || isInRulesView; - - const stats = useSubplebbitStats({ subplebbitAddress: address }); - const [showStats, setShowStats] = useState(true); + const hideStats = !stats.allPostCount || deleted || locked || removed || isInDescriptionView || isInRulesView; const unixToMMDDYYYY = (timestamp: number) => { const date = new Date(timestamp * 1000); From 15462f14ede7b0b3920ae62305b2bc3b112476da Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Wed, 10 Jul 2024 19:10:32 +0200 Subject: [PATCH 07/14] fix(edit menu): reason field would reset at menu close --- src/components/edit-menu/edit-menu.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/edit-menu/edit-menu.tsx b/src/components/edit-menu/edit-menu.tsx index cf83432b..c5e673af 100644 --- a/src/components/edit-menu/edit-menu.tsx +++ b/src/components/edit-menu/edit-menu.tsx @@ -43,6 +43,7 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po deleted: isAccountCommentAuthor ? deleted : undefined, locked: isAccountMod ? locked : undefined, pinned: isAccountMod ? pinned : undefined, + reason, removed: isAccountMod ? removed : undefined, spoiler, subplebbitAddress, @@ -82,8 +83,7 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po })); }; - const onReason = (e: React.ChangeEvent) => - setPublishCommentEditOptions((state) => ({ ...state, reason: e.target.value ? e.target.value : undefined })); + const onReason = (e: React.ChangeEvent) => setPublishCommentEditOptions((state) => ({ ...state, reason: e.target.value })); const { refs, floatingStyles, context } = useFloating({ placement: 'bottom-start', @@ -206,7 +206,7 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po )}
{_.capitalize(t('reason'))}? ({t('optional')}) - +
)}
+ {replyCount === undefined && ( + + + + )} {!(pinned && !isInPostView) && !isInPendingPostView && !isDescription && diff --git a/src/views/post/post.module.css b/src/views/post/post.module.css index 72d448fa..384084d5 100644 --- a/src/views/post/post.module.css +++ b/src/views/post/post.module.css @@ -185,6 +185,11 @@ color: var(--post-mobile-abbr-text-color); } +.loadingString { + display: block; + color: var(--post-mobile-abbr-text-color); +} + .postDesktop .summary .omittedRepliesButtonWrapper { position: absolute; top: 8px; @@ -511,6 +516,11 @@ .replyDesktop { display: none; } + + .loadingString { + margin-top: 10px; + margin-left: 5px; + } } @media (min-width: 640px) { From 9960e400e822214377842cf43789a20c5324caf8 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Fri, 12 Jul 2024 16:58:37 +0200 Subject: [PATCH 09/14] fix(catalog post): it was not possible to scroll past the floating post preview --- src/components/catalog-row/catalog-row.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/catalog-row/catalog-row.tsx b/src/components/catalog-row/catalog-row.tsx index f8981461..6f8e89d3 100644 --- a/src/components/catalog-row/catalog-row.tsx +++ b/src/components/catalog-row/catalog-row.tsx @@ -141,7 +141,6 @@ const CatalogPost = ({ post }: { post: Comment }) => { open: showPortal, placement: placementRef.current, middleware: [ - shift({ padding: 10 }), offset({ mainAxis: 5 }), size({ apply({ elements }) { From f2e4f14a33ac2d41e029f54ae05000f31468f8f8 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Fri, 12 Jul 2024 20:22:09 +0200 Subject: [PATCH 10/14] feat(settings): add avatar setting --- public/translations/ar/default.json | 7 +- public/translations/bn/default.json | 7 +- public/translations/cs/default.json | 5 +- public/translations/da/default.json | 5 +- public/translations/de/default.json | 5 +- public/translations/el/default.json | 5 +- public/translations/en/default.json | 5 +- public/translations/es/default.json | 5 +- public/translations/fa/default.json | 7 +- public/translations/fi/default.json | 7 +- public/translations/fil/default.json | 7 +- public/translations/fr/default.json | 5 +- public/translations/he/default.json | 5 +- public/translations/hi/default.json | 5 +- public/translations/hu/default.json | 5 +- public/translations/id/default.json | 7 +- public/translations/it/default.json | 5 +- public/translations/ja/default.json | 5 +- public/translations/ko/default.json | 5 +- public/translations/mr/default.json | 7 +- public/translations/nl/default.json | 5 +- public/translations/no/default.json | 5 +- public/translations/pl/default.json | 5 +- public/translations/pt/default.json | 5 +- public/translations/ro/default.json | 5 +- public/translations/ru/default.json | 7 +- public/translations/sq/default.json | 5 +- public/translations/sv/default.json | 5 +- public/translations/te/default.json | 7 +- public/translations/th/default.json | 5 +- public/translations/tr/default.json | 5 +- public/translations/uk/default.json | 7 +- public/translations/ur/default.json | 5 +- public/translations/vi/default.json | 5 +- public/translations/zh/default.json | 7 +- src/components/catalog-row/catalog-row.tsx | 2 +- .../account-settings/account-settings.tsx | 1 + .../avatar-settings.module.css | 86 ++++++++ .../avatar-settings/avatar-settings.tsx | 200 ++++++++++++++++++ .../settings-modal/avatar-settings/index.ts | 1 + .../plebbit-options/plebbit-options.tsx | 1 + .../settings-modal/settings-modal.module.css | 4 + .../settings-modal/settings-modal.tsx | 10 + .../subplebbit-description.tsx | 1 + .../subplebbit-rules/subplebbit-rules.tsx | 1 + src/lib/init-translations.ts | 1 + src/themes.css | 9 + 47 files changed, 467 insertions(+), 47 deletions(-) create mode 100644 src/components/settings-modal/avatar-settings/avatar-settings.module.css create mode 100644 src/components/settings-modal/avatar-settings/avatar-settings.tsx create mode 100644 src/components/settings-modal/avatar-settings/index.ts diff --git a/public/translations/ar/default.json b/public/translations/ar/default.json index bf145003..5ae4ea9d 100644 --- a/public/translations/ar/default.json +++ b/public/translations/ar/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "طي جميع الإعدادات", "refresh": "تحديث", "no_board_selected": "لم يتم تحديد أية منتديات", - "none": "بلا", + "none": "لا شيء", "not_subscribed_to_any_board": "لم تشترك في أي منتديات بعد.", "board_mods": "مشرفو المنتدى", "this_post_was_removed": "تمت إزالة هذا المنشور", @@ -213,5 +213,8 @@ "user_banned": "تم حظر المستخدم لهذا المنشور", "loading_comments": "تحميل التعليقات", "replies": "الردود", - "links": "الروابط" + "links": "الروابط", + "avatar": "الصورة الرمزية", + "token_address_whitelist": "عنوان الرمز (فقط على الـ <1>قائمة البيضاء)", + "token_id": "تعريف الرمز" } \ No newline at end of file diff --git a/public/translations/bn/default.json b/public/translations/bn/default.json index 6aaf0197..a885326d 100644 --- a/public/translations/bn/default.json +++ b/public/translations/bn/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "সমস্ত সেটিংস সঙ্কুচিত করুন", "refresh": "পুনরায় লোড করুন", "no_board_selected": "কোনো ফোরাম নির্বাচিত হয়নি", - "none": "নাই", + "none": "কিছু না", "not_subscribed_to_any_board": "আপনি এখনো কোনো ফোরামে সদস্য হননি।", "board_mods": "বোর্ড মডস", "this_post_was_removed": "এই পোস্টটি সরানো হয়েছে", @@ -213,5 +213,8 @@ "user_banned": "এই পোস্টের জন্য ব্যবহারকারী নিষিদ্ধ হয়েছে", "loading_comments": "মন্তব্য লোড হচ্ছে", "replies": "উত্তর", - "links": "লিঙ্কগুলি" + "links": "লিঙ্কগুলি", + "avatar": "অবতার", + "token_address_whitelist": "টোকেন ঠিকানা (<1>সাফল্যবান কেবল)", + "token_id": "টোকেন আইডি" } \ No newline at end of file diff --git a/public/translations/cs/default.json b/public/translations/cs/default.json index db60cd7f..31e6d675 100644 --- a/public/translations/cs/default.json +++ b/public/translations/cs/default.json @@ -213,5 +213,8 @@ "user_banned": "Uživatel byl zablokován za tento příspěvek", "loading_comments": "Načítání komentářů", "replies": "Odpovědi", - "links": "Odkazy" + "links": "Odkazy", + "avatar": "avatar", + "token_address_whitelist": "Tokenová adresa (<1>jen bílý seznam)", + "token_id": "Token ID" } \ No newline at end of file diff --git a/public/translations/da/default.json b/public/translations/da/default.json index 92078999..7466cc99 100644 --- a/public/translations/da/default.json +++ b/public/translations/da/default.json @@ -213,5 +213,8 @@ "user_banned": "Brugeren blev blokeret for dette indlæg", "loading_comments": "Indlæser kommentarer", "replies": "Svar", - "links": "Links" + "links": "Links", + "avatar": "avatar", + "token_address_whitelist": "Tokenadresse (<1>kun hvidliste)", + "token_id": "Token ID" } \ No newline at end of file diff --git a/public/translations/de/default.json b/public/translations/de/default.json index a1a7965e..a7652785 100644 --- a/public/translations/de/default.json +++ b/public/translations/de/default.json @@ -213,5 +213,8 @@ "user_banned": "Benutzer wurde für diesen Beitrag gesperrt", "loading_comments": "Lade Kommentare", "replies": "Antworten", - "links": "Links" + "links": "Links", + "avatar": "Avatar", + "token_address_whitelist": "Tokenadresse (<1>nur Weiße Liste)", + "token_id": "Token-ID" } \ No newline at end of file diff --git a/public/translations/el/default.json b/public/translations/el/default.json index 3e5046cf..ac81502e 100644 --- a/public/translations/el/default.json +++ b/public/translations/el/default.json @@ -213,5 +213,8 @@ "user_banned": "Ο χρήστης αποκλείστηκε για αυτή τη δημοσίευση", "loading_comments": "Φόρτωση σχολίων", "replies": "Απαντήσεις", - "links": "Σύνδεσμοι" + "links": "Σύνδεσμοι", + "avatar": "εικόνα προφίλ", + "token_address_whitelist": "Διεύθυνση του token (<1>μόνο λευκή λίστα)", + "token_id": "Token ID" } \ No newline at end of file diff --git a/public/translations/en/default.json b/public/translations/en/default.json index 9b50598e..d9e0a327 100644 --- a/public/translations/en/default.json +++ b/public/translations/en/default.json @@ -213,5 +213,8 @@ "user_banned": "User was banned for this post", "loading_comments": "Loading comments", "replies": "replies", - "links": "links" + "links": "links", + "avatar": "avatar", + "token_address_whitelist": "Token address (<1>whitelist only)", + "token_id": "token id" } \ No newline at end of file diff --git a/public/translations/es/default.json b/public/translations/es/default.json index 4b15b1cf..99a79296 100644 --- a/public/translations/es/default.json +++ b/public/translations/es/default.json @@ -213,5 +213,8 @@ "user_banned": "El usuario fue baneado por esta publicación", "loading_comments": "Cargando comentarios", "replies": "respuestas", - "links": "enlaces" + "links": "enlaces", + "avatar": "avatar", + "token_address_whitelist": "Dirección del token (<1>solo lista blanca)", + "token_id": "ID de token" } \ No newline at end of file diff --git a/public/translations/fa/default.json b/public/translations/fa/default.json index 919a46fd..6b211207 100644 --- a/public/translations/fa/default.json +++ b/public/translations/fa/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "تايید همه تنظیمات", "refresh": "تازه‌سازی", "no_board_selected": "هیچ تالاری انتخاب نشده است", - "none": "هیچ‌کدام", + "none": "هیچکدام", "not_subscribed_to_any_board": "هنوز به هیچ تالاری مشترک نشده‌اید.", "board_mods": "مدیران تالار", "this_post_was_removed": "این پست حذف شد", @@ -213,5 +213,8 @@ "user_banned": "این کاربر برای این پست مسدود شد", "loading_comments": "بارگذاری نظرات", "replies": "پاسخ‌ها", - "links": "لینک‌ها" + "links": "لینک‌ها", + "avatar": "آواتار", + "token_address_whitelist": "آدرس توکن (<1>فقط سفیدپوشان)", + "token_id": "شناسه توکن" } \ No newline at end of file diff --git a/public/translations/fi/default.json b/public/translations/fi/default.json index baa5d19b..37b35f43 100644 --- a/public/translations/fi/default.json +++ b/public/translations/fi/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "Sulje kaikki asetukset", "refresh": "Päivitä", "no_board_selected": "ei foorumeja valittu", - "none": "ei mikään", + "none": "ei mitään", "not_subscribed_to_any_board": "Et ole vielä tilannut mitään foorumeita.", "board_mods": "Hallituksen Mods", "this_post_was_removed": "tämä viesti on poistettu", @@ -213,5 +213,8 @@ "user_banned": "Käyttäjä on estetty tästä viestistä", "loading_comments": "Ladataan kommentteja", "replies": "vastaukset", - "links": "linkit" + "links": "linkit", + "avatar": "avatar", + "token_address_whitelist": "Token-osoite (<1>vain valkoinen lista)", + "token_id": "Token-id" } \ No newline at end of file diff --git a/public/translations/fil/default.json b/public/translations/fil/default.json index 6ee111e9..31ef7200 100644 --- a/public/translations/fil/default.json +++ b/public/translations/fil/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "I-collapse ang lahat ng mga setting", "refresh": "I-refresh", "no_board_selected": "walang mga board na napiling", - "none": "wala", + "none": "walang anuman", "not_subscribed_to_any_board": "Hindi ka pa naka-subscribe sa anumang mga board.", "board_mods": "Board Mods", "this_post_was_removed": "tinanggal ang post na ito", @@ -213,5 +213,8 @@ "user_banned": "Banal ang user para sa post na ito", "loading_comments": "Naglo-load ng mga komento", "replies": "mga tugon", - "links": "mga link" + "links": "mga link", + "avatar": "avatar", + "token_address_whitelist": "Address ng token (<1>whitelist lang)", + "token_id": "Token ID" } \ No newline at end of file diff --git a/public/translations/fr/default.json b/public/translations/fr/default.json index d4aec8a7..b3484b75 100644 --- a/public/translations/fr/default.json +++ b/public/translations/fr/default.json @@ -213,5 +213,8 @@ "user_banned": "L'utilisateur a été banni pour ce post", "loading_comments": "Chargement des commentaires", "replies": "réponses", - "links": "liens" + "links": "liens", + "avatar": "avatar", + "token_address_whitelist": "Adresse du token (<1>liste blanche seulement)", + "token_id": "Identifiant de jeton" } \ No newline at end of file diff --git a/public/translations/he/default.json b/public/translations/he/default.json index 211f5de2..e6ced4c6 100644 --- a/public/translations/he/default.json +++ b/public/translations/he/default.json @@ -213,5 +213,8 @@ "user_banned": "המשתמש נחסם עבור הפוסט הזה", "loading_comments": "טוען תגובות", "replies": "תגובות", - "links": "קישורים" + "links": "קישורים", + "avatar": "אוואטר", + "token_address_whitelist": "כתובת הטוקן (<1>רק רשימה לבנה)", + "token_id": "מזהה טוקן" } \ No newline at end of file diff --git a/public/translations/hi/default.json b/public/translations/hi/default.json index 3ddec35f..22b6cabc 100644 --- a/public/translations/hi/default.json +++ b/public/translations/hi/default.json @@ -213,5 +213,8 @@ "user_banned": "इस पोस्ट के लिए उपयोगकर्ता पर प्रतिबंध लगा दिया गया था", "loading_comments": "टिप्पणियाँ लोड हो रही हैं", "replies": "जवाब", - "links": "लिंक" + "links": "लिंक", + "avatar": "अवतार", + "token_address_whitelist": "टोकन पता (<1>केवल सफेद सूची)", + "token_id": "टोकन आईडी" } \ No newline at end of file diff --git a/public/translations/hu/default.json b/public/translations/hu/default.json index 72da7376..5a201f02 100644 --- a/public/translations/hu/default.json +++ b/public/translations/hu/default.json @@ -213,5 +213,8 @@ "user_banned": "A felhasználót letiltották ennek a posztnak a kapcsán", "loading_comments": "Megjegyzések betöltése", "replies": "válaszok", - "links": "linkek" + "links": "linkek", + "avatar": "avatár", + "token_address_whitelist": "Token cím (<1>csak fehérlista)", + "token_id": "Token azonosító" } \ No newline at end of file diff --git a/public/translations/id/default.json b/public/translations/id/default.json index b5aa0fdd..54b1a4ba 100644 --- a/public/translations/id/default.json +++ b/public/translations/id/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "Ciutkan Semua Pengaturan", "refresh": "Segarkan", "no_board_selected": "tidak ada papan pesan yang dipilih", - "none": "tak ada", + "none": "tidak ada", "not_subscribed_to_any_board": "Anda belum berlangganan ke papan pesan mana pun.", "board_mods": "Papan Pesan Mods", "this_post_was_removed": "posting ini telah dihapus", @@ -213,5 +213,8 @@ "user_banned": "Pengguna diblokir untuk pos ini", "loading_comments": "Memuat komentar", "replies": "balasan", - "links": "tautan" + "links": "tautan", + "avatar": "avatar", + "token_address_whitelist": "Alamat token (<1>hanya daftar putih)", + "token_id": "ID token" } \ No newline at end of file diff --git a/public/translations/it/default.json b/public/translations/it/default.json index b35c86f2..c8ccf3fa 100644 --- a/public/translations/it/default.json +++ b/public/translations/it/default.json @@ -213,5 +213,8 @@ "user_banned": "L'utente è stato bannato per questo post", "loading_comments": "Caricamento commenti", "replies": "commenti", - "links": "link" + "links": "link", + "avatar": "avatar", + "token_address_whitelist": "Indirizzo del token (solo se sulla <1>whitelist)", + "token_id": "token id" } \ No newline at end of file diff --git a/public/translations/ja/default.json b/public/translations/ja/default.json index fad1099d..b686d48d 100644 --- a/public/translations/ja/default.json +++ b/public/translations/ja/default.json @@ -213,5 +213,8 @@ "user_banned": "この投稿のためにユーザーが禁止されました", "loading_comments": "コメントを読み込み中", "replies": "返信", - "links": "リンク" + "links": "リンク", + "avatar": "アバター", + "token_address_whitelist": "トークンアドレス(<1>ホワイトリストのみ)", + "token_id": "トークンID" } \ No newline at end of file diff --git a/public/translations/ko/default.json b/public/translations/ko/default.json index f22b1989..25495d57 100644 --- a/public/translations/ko/default.json +++ b/public/translations/ko/default.json @@ -213,5 +213,8 @@ "user_banned": "이 게시물로 인해 사용자가 차단되었습니다", "loading_comments": "댓글 로드 중", "replies": "답글", - "links": "링크" + "links": "링크", + "avatar": "아바타", + "token_address_whitelist": "토큰 주소 (<1>화이트리스트만)", + "token_id": "토큰 ID" } \ No newline at end of file diff --git a/public/translations/mr/default.json b/public/translations/mr/default.json index a478f18f..d5ab8ebb 100644 --- a/public/translations/mr/default.json +++ b/public/translations/mr/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "सर्व सेटिंग्ज संक्षेपित", "refresh": "ताजेतर करा", "no_board_selected": "कोणतेही संदेश फलक निवडले नाहीत", - "none": "काहीही नाही", + "none": "काही नाही", "not_subscribed_to_any_board": "तुम्ही कोणत्याही संदेश फलकांवर अद्याप सदस्यता घेतली नाही.", "board_mods": "बोर्ड मॉड्स", "this_post_was_removed": "हा पोस्ट काढून टाकला गेला आहे", @@ -213,5 +213,8 @@ "user_banned": "या पोस्टसाठी वापरकर्ता ब्लॉक केला गेला होता", "loading_comments": "टिप्पणी लोड होत आहे", "replies": "उत्तर", - "links": "लिंक" + "links": "लिंक", + "avatar": "अवतार", + "token_address_whitelist": "टोकन पत्ता (<1>केवळ सफेद सूची)", + "token_id": "टोकन आयडी" } \ No newline at end of file diff --git a/public/translations/nl/default.json b/public/translations/nl/default.json index 4dcf93b2..bb73645b 100644 --- a/public/translations/nl/default.json +++ b/public/translations/nl/default.json @@ -213,5 +213,8 @@ "user_banned": "Gebruiker is verbannen voor deze post", "loading_comments": "Reacties laden", "replies": "reacties", - "links": "links" + "links": "links", + "avatar": "avatar", + "token_address_whitelist": "Tokenadres (<1>alleen whitelist)", + "token_id": "Token-ID" } \ No newline at end of file diff --git a/public/translations/no/default.json b/public/translations/no/default.json index 7ea58dc4..8623c9f2 100644 --- a/public/translations/no/default.json +++ b/public/translations/no/default.json @@ -213,5 +213,8 @@ "user_banned": "Brukeren ble utestengt for dette innlegget", "loading_comments": "Laster inn kommentarer", "replies": "svar", - "links": "lenker" + "links": "lenker", + "avatar": "avatar", + "token_address_whitelist": "Tokenadresse (<1>kun hvitelisten)", + "token_id": "Token ID" } \ No newline at end of file diff --git a/public/translations/pl/default.json b/public/translations/pl/default.json index f64e2f7b..26ff4d42 100644 --- a/public/translations/pl/default.json +++ b/public/translations/pl/default.json @@ -213,5 +213,8 @@ "user_banned": "Użytkownik został zablokowany za ten post", "loading_comments": "Ładowanie komentarzy", "replies": "odpowiedzi", - "links": "linki" + "links": "linki", + "avatar": "avatar", + "token_address_whitelist": "Adres tokenu (<1>tylko biała lista)", + "token_id": "Identyfikator tokena" } \ No newline at end of file diff --git a/public/translations/pt/default.json b/public/translations/pt/default.json index 3db5bc9e..1982062d 100644 --- a/public/translations/pt/default.json +++ b/public/translations/pt/default.json @@ -213,5 +213,8 @@ "user_banned": "O usuário foi banido por este post", "loading_comments": "Carregando comentários", "replies": "respostas", - "links": "links" + "links": "links", + "avatar": "avatar", + "token_address_whitelist": "Endereço do token (<1>apenas lista branca)", + "token_id": "ID do token" } \ No newline at end of file diff --git a/public/translations/ro/default.json b/public/translations/ro/default.json index 3aa14997..04471447 100644 --- a/public/translations/ro/default.json +++ b/public/translations/ro/default.json @@ -213,5 +213,8 @@ "user_banned": "Utilizatorul a fost interzis pentru acest mesaj", "loading_comments": "Se încarcă comentariile", "replies": "răspunsuri", - "links": "linkuri" + "links": "linkuri", + "avatar": "avatar", + "token_address_whitelist": "Adresa tokenului (<1>doar lista albă)", + "token_id": "ID token" } \ No newline at end of file diff --git a/public/translations/ru/default.json b/public/translations/ru/default.json index 57a3e0da..191fd78e 100644 --- a/public/translations/ru/default.json +++ b/public/translations/ru/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "Свернуть все настройки", "refresh": "Обновить", "no_board_selected": "не выбрано ни одного форума", - "none": "нет", + "none": "ничего", "not_subscribed_to_any_board": "Вы еще не подписаны ни на один форум.", "board_mods": "Модераторы форума", "this_post_was_removed": "этот пост был удален", @@ -213,5 +213,8 @@ "user_banned": "Пользователь был заблокирован за этот пост", "loading_comments": "Загрузка комментариев", "replies": "ответы", - "links": "ссылки" + "links": "ссылки", + "avatar": "аватар", + "token_address_whitelist": "Адрес токена (<1>только белый список)", + "token_id": "Идентификатор токена" } \ No newline at end of file diff --git a/public/translations/sq/default.json b/public/translations/sq/default.json index b2cf7750..7136d309 100644 --- a/public/translations/sq/default.json +++ b/public/translations/sq/default.json @@ -213,5 +213,8 @@ "user_banned": "Përdoruesi u ndalua për këtë postim", "loading_comments": "Duke u ngarkuar komentet", "replies": "përgjigje", - "links": "lidhje" + "links": "lidhje", + "avatar": "avatar", + "token_address_whitelist": "Adresa e tokenit (<1>vetëm lista e bardhë)", + "token_id": "ID e tokenit" } \ No newline at end of file diff --git a/public/translations/sv/default.json b/public/translations/sv/default.json index bb810909..ef37850a 100644 --- a/public/translations/sv/default.json +++ b/public/translations/sv/default.json @@ -213,5 +213,8 @@ "user_banned": "Användaren blev blockerad för detta inlägg", "loading_comments": "Laddar kommentarer", "replies": "svar", - "links": "länkar" + "links": "länkar", + "avatar": "avatar", + "token_address_whitelist": "Tokenadress (<1>endast vitlista)", + "token_id": "Token ID" } \ No newline at end of file diff --git a/public/translations/te/default.json b/public/translations/te/default.json index dfc07058..316478a8 100644 --- a/public/translations/te/default.json +++ b/public/translations/te/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "అన్ని సెట్టింగ్‌లను సంక్షిప్తము చేయండి", "refresh": "రీఫ్రెష్", "no_board_selected": "ఏటీ ఎలాంటి సందేశ బోర్డులు ఎంచుకోలేదు", - "none": "ఏమీ లేదు", + "none": "ఎవరూ లేరు", "not_subscribed_to_any_board": "మీరు ఇంకా ఏకైక సందేశ బోర్డులకు చేరలేదు.", "board_mods": "సందేశ బోర్డుల మాడ్స్", "this_post_was_removed": "ఈ పోస్టు తొలగించబడింది", @@ -213,5 +213,8 @@ "user_banned": "ఈ పోస్టు కోసం వాడు బ్యాన్ చేయబడింది", "loading_comments": "వ్యాఖ్యలను లోడ్ అవుతోంది", "replies": "సమాధానాలు", - "links": "లింక్లు" + "links": "లింక్లు", + "avatar": "అవతార్", + "token_address_whitelist": "టోకెన్ చిరునామా (<1>కేవలం వెలుపల్లి)", + "token_id": "టోకెన్ ఐడి" } \ No newline at end of file diff --git a/public/translations/th/default.json b/public/translations/th/default.json index 4ba836b4..6812dcb1 100644 --- a/public/translations/th/default.json +++ b/public/translations/th/default.json @@ -213,5 +213,8 @@ "user_banned": "ผู้ใช้ถูกห้ามใช้งานสำหรับโพสต์นี้", "loading_comments": "กำลังโหลดความคิดเห็น", "replies": "คำตอบ", - "links": "ลิงก์" + "links": "ลิงก์", + "avatar": "อวตาร์", + "token_address_whitelist": "ที่อยู่โทเค็น (<1>รายชื่อที่ได้รับอนุญาตเท่านั้น)", + "token_id": "รหัสโทเค็น" } \ No newline at end of file diff --git a/public/translations/tr/default.json b/public/translations/tr/default.json index 3b46f5ab..52652d2d 100644 --- a/public/translations/tr/default.json +++ b/public/translations/tr/default.json @@ -213,5 +213,8 @@ "user_banned": "Kullanıcı bu gönderi için yasaklandı", "loading_comments": "Yorumlar yükleniyor", "replies": "cevaplar", - "links": "bağlantılar" + "links": "bağlantılar", + "avatar": "avatar", + "token_address_whitelist": "Token adresi (<1>yalnızca beyaz liste)", + "token_id": "Token kimliği" } \ No newline at end of file diff --git a/public/translations/uk/default.json b/public/translations/uk/default.json index ed2bf6d0..697c3c9f 100644 --- a/public/translations/uk/default.json +++ b/public/translations/uk/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "Згорнути всі налаштування", "refresh": "Оновити", "no_board_selected": "не обрано жодного форуму", - "none": "немає", + "none": "ніхто", "not_subscribed_to_any_board": "Ви ще не підписалися на жоден форум.", "board_mods": "Дошка Моди", "this_post_was_removed": "цей пост було видалено", @@ -213,5 +213,8 @@ "user_banned": "Користувач був заблокований за цей пост", "loading_comments": "Завантаження коментарів", "replies": "відповіді", - "links": "посилання" + "links": "посилання", + "avatar": "аватар", + "token_address_whitelist": "Адреса токена (<1>тільки білий список)", + "token_id": "Ідентифікатор токена" } \ No newline at end of file diff --git a/public/translations/ur/default.json b/public/translations/ur/default.json index c527946e..e1fb0874 100644 --- a/public/translations/ur/default.json +++ b/public/translations/ur/default.json @@ -213,5 +213,8 @@ "user_banned": "اس پوسٹ کے لئے صارف کو پابندی عائد کردی گئی تھی", "loading_comments": "تبصرے لوڈ ہو رہے ہیں", "replies": "جوابات", - "links": "لنکس" + "links": "لنکس", + "avatar": "اوتار", + "token_address_whitelist": "ٹوکن کا پتا (<1>صرف سفید فہرست)", + "token_id": "ٹوکن شناخت" } \ No newline at end of file diff --git a/public/translations/vi/default.json b/public/translations/vi/default.json index 602d13c8..b97c72cd 100644 --- a/public/translations/vi/default.json +++ b/public/translations/vi/default.json @@ -213,5 +213,8 @@ "user_banned": "Người dùng đã bị cấm vì bài đăng này", "loading_comments": "Đang tải bình luận", "replies": "trả lời", - "links": "liên kết" + "links": "liên kết", + "avatar": "avatar", + "token_address_whitelist": "Địa chỉ token (<1>chỉ danh sách trắng)", + "token_id": "ID token" } \ No newline at end of file diff --git a/public/translations/zh/default.json b/public/translations/zh/default.json index 55e28bb2..65c715d9 100644 --- a/public/translations/zh/default.json +++ b/public/translations/zh/default.json @@ -136,7 +136,7 @@ "collapse_all_settings": "折叠所有设置", "refresh": "刷新", "no_board_selected": "没有选择任何论坛", - "none": "无", + "none": "没有", "not_subscribed_to_any_board": "您尚未订阅任何论坛。", "board_mods": "董事會版主", "this_post_was_removed": "此帖已被删除", @@ -213,5 +213,8 @@ "user_banned": "用户因此帖子被禁止", "loading_comments": "正在加载评论", "replies": "回复", - "links": "链接" + "links": "链接", + "avatar": "头像", + "token_address_whitelist": "代币地址(<1>仅限白名单)", + "token_id": "令牌ID" } \ No newline at end of file diff --git a/src/components/catalog-row/catalog-row.tsx b/src/components/catalog-row/catalog-row.tsx index 6f8e89d3..e72c8c16 100644 --- a/src/components/catalog-row/catalog-row.tsx +++ b/src/components/catalog-row/catalog-row.tsx @@ -3,7 +3,7 @@ import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; import { Link, useLocation, useParams } from 'react-router-dom'; import { Comment, useComment } from '@plebbit/plebbit-react-hooks'; -import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react'; +import { useFloating, offset, size, autoUpdate, Placement } from '@floating-ui/react'; import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getFormattedTimeAgo } from '../../lib/utils/time-utils'; import { isAllView } from '../../lib/utils/view-utils'; diff --git a/src/components/settings-modal/account-settings/account-settings.tsx b/src/components/settings-modal/account-settings/account-settings.tsx index 2ddef995..df7e74b6 100644 --- a/src/components/settings-modal/account-settings/account-settings.tsx +++ b/src/components/settings-modal/account-settings/account-settings.tsx @@ -130,6 +130,7 @@ const AccountSettings = () => { await importAccount(fileContent); setSwitchToLastAccount(true); alert(`Imported ${newAccount.account?.name}`); + window.location.reload(); }; reader.readAsText(file); } catch (error) { diff --git a/src/components/settings-modal/avatar-settings/avatar-settings.module.css b/src/components/settings-modal/avatar-settings/avatar-settings.module.css new file mode 100644 index 00000000..a719afdd --- /dev/null +++ b/src/components/settings-modal/avatar-settings/avatar-settings.module.css @@ -0,0 +1,86 @@ +.avatar { + width: 70px; + height: 70px; + border: 1px solid #aaa; + background-color: var(--avatar-background-color, white); + margin-left: 10px; +} + +.avatarPreview { + display: inline-block; +} + +.avatar img { + width: 70px; + height: 70px; +} + +.emptyAvatar { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + height: 100%; + color: var(--avatar-text-color); + cursor: pointer; +} + +.avatarSettingsForm { + padding: 10px 0 15px 10px; +} + +.avatarSettingsForm input { + width: 200px; + padding: 2px; +} + +.avatarSettingInput input { + margin-bottom: 10px; + display: block; +} + +.avatarSettingInput a { + color: var(--link-primary); +} + +.avatarSettingInput a { + color: var(--post-link-text-color); + text-decoration: var(--post-content-link-text-decoration); +} + +.avatarSettingInput a:hover { + color: var(--post-link-text-color-hover); + text-decoration: var(--post-content-link-text-decoration-hover); +} + +.settingTitle { + font-style: italic; + text-transform: lowercase; +} + +.copyMessage { + padding-bottom: 10px; +} + +.pasteSignature span { + display: block; +} + +.pasteSignature button { + margin-left: 5px; +} + +.state { + padding-top: 10px; + padding-left: 10px; + max-width: 300px; + color: var(--post-mobile-abbr-text-color); +} + +.copyMessage a { + color: var(--text-primary); +} + +.copyMessage a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/src/components/settings-modal/avatar-settings/avatar-settings.tsx b/src/components/settings-modal/avatar-settings/avatar-settings.tsx new file mode 100644 index 00000000..c5d91c34 --- /dev/null +++ b/src/components/settings-modal/avatar-settings/avatar-settings.tsx @@ -0,0 +1,200 @@ +import { useMemo, useState } from 'react'; +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 LoadingEllipsis from '../../loading-ellipsis'; + +const AvatarPreview = ({ avatar }: any) => { + const { t } = useTranslation(); + const account = useAccount(); + let author = useMemo(() => ({ ...account?.author, avatar }), [account, avatar]); + + const { imageUrl, state, error } = useAuthorAvatar({ author }); + + // if avatar already set, and user hasn't typed anything yet, preview already set author + if (account?.author?.avatar && !avatar?.chainTicker && !avatar?.address && !avatar?.id && !avatar?.signature) { + author = account.author; + } + + // not enough data to preview yet + if (!author?.avatar?.address && !author?.avatar?.signature) { + return; + } + + const stateText = state !== 'succeeded' ? : undefined; + + return ( + <> +
+ {imageUrl && state !== 'initializing' ? : {t('none')}} +
+ {state !== 'succeeded' && account?.author?.avatar && ( +
+ {stateText} {error?.message} +
+ )} + + ); +}; + +const AvatarSettings = () => { + const { t } = useTranslation(); + const account = useAccount(); + const authorAddress = account?.author?.address; + const [chainTicker, setChainTicker] = useState(account?.author?.avatar?.chainTicker); + const [tokenAddress, setTokenAddress] = useState(account?.author?.avatar?.address); + 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 getNftMessageToSign = (authorAddress: string, timestamp: number, tokenAddress: string, tokenId: string) => { + let messageToSign: any = {}; + // the property names must be in this order for the signature to match + // insert props one at a time otherwise babel/webpack will reorder + messageToSign.domainSeparator = 'plebbit-author-avatar'; + messageToSign.authorAddress = authorAddress; + messageToSign.timestamp = timestamp; + messageToSign.tokenAddress = tokenAddress; + messageToSign.tokenId = String(tokenId); // must be a type string, not number + // use plain JSON so the user can read what he's signing + messageToSign = JSON.stringify(messageToSign); + return messageToSign; + }; + + const [hasCopied, setHasCopied] = useState(false); + + const copyMessageToSign = () => { + if (!chainTicker) { + return alert(t('missing_chain_ticker')); + } + if (!tokenAddress) { + return alert(t('missing_token_address')); + } + if (!tokenId) { + return alert(t('missing_token_id')); + } + const newTimestamp = Math.floor(Date.now() / 1000); + const messageToSign = getNftMessageToSign(authorAddress, newTimestamp, tokenAddress, tokenId); + // update timestamp every time the user gets a new message to sign + setTimestamp(newTimestamp); + navigator.clipboard.writeText(messageToSign); + setHasCopied(true); + setTimeout(() => { + setHasCopied(false); + }, 2000); + }; + + // how to resolve and verify NFT signatures https://github.com/plebbit/plebbit-js/blob/master/docs/nft.md + const avatar = { + chainTicker: chainTicker?.toLowerCase() || account?.author?.avatar?.chainTicker, + timestamp, + address: tokenAddress || account?.author?.avatar?.address, + id: tokenId || account?.author?.avatar?.id, + signature: { + signature: signature || account?.author?.avatar?.signature?.signature, + type: 'eip191', + }, + }; + + const save = () => { + if (!chainTicker) { + return alert(t('missing_chain_ticker')); + } + if (!tokenAddress) { + return alert(t('missing_token_address')); + } + if (!tokenId) { + return alert(t('missing_token_id')); + } + if (!signature) { + return alert(t('missing_signature')); + } + setAccount({ ...account, author: { ...account?.author, avatar } }); + alert(`saved`); + }; + + return ( +
+ +
+
+ {t('chain_ticker')} + setChainTicker(e.target.value)} + /> +
+
+ + + ), + }} + /> + + setTokenAddress(e.target.value)} + /> +
+
+ {t('token_id')} + setTokenId(e.target.value)} + /> +
+
+ , + // eslint-disable-next-line + 2: , + }} + /> +
+
+ {t('paste_signature')} + setSignature(e.target.value)} + /> + +
+
+
+ ); +}; + +export default AvatarSettings; diff --git a/src/components/settings-modal/avatar-settings/index.ts b/src/components/settings-modal/avatar-settings/index.ts new file mode 100644 index 00000000..5e1715cd --- /dev/null +++ b/src/components/settings-modal/avatar-settings/index.ts @@ -0,0 +1 @@ +export { default } from './avatar-settings'; diff --git a/src/components/settings-modal/plebbit-options/plebbit-options.tsx b/src/components/settings-modal/plebbit-options/plebbit-options.tsx index 1fcc4bf2..1654603a 100644 --- a/src/components/settings-modal/plebbit-options/plebbit-options.tsx +++ b/src/components/settings-modal/plebbit-options/plebbit-options.tsx @@ -193,6 +193,7 @@ const PlebbitOptions = () => { }, }); alert('Options saved.'); + window.location.reload(); } catch (e) { if (e instanceof Error) { alert('Error saving options: ' + e.message); diff --git a/src/components/settings-modal/settings-modal.module.css b/src/components/settings-modal/settings-modal.module.css index 28fd4fb8..7c6ca6bd 100644 --- a/src/components/settings-modal/settings-modal.module.css +++ b/src/components/settings-modal/settings-modal.module.css @@ -22,6 +22,10 @@ padding: 2px 4px 3px; } +.settingsModal input[type="text"]:focus, .settingsModal textarea:focus { + border: var(--reply-modal-field-input-border-focus, revert); +} + .settingsModal { top: 25px; left: 50%; diff --git a/src/components/settings-modal/settings-modal.tsx b/src/components/settings-modal/settings-modal.tsx index 3245ba06..00ef90b2 100644 --- a/src/components/settings-modal/settings-modal.tsx +++ b/src/components/settings-modal/settings-modal.tsx @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import styles from './settings-modal.module.css'; import AccountSettings from './account-settings'; +import AvatarSettings from './avatar-settings'; import BlockedAddressesSetting from './blocked-addresses-setting'; import CryptoAddressSetting from './crypto-address-setting'; import CryptoWalletsSetting from './crypto-wallets-setting'; @@ -19,6 +20,7 @@ const SettingsModal = () => { const [showInterfaceSettings, setShowInterfaceSettings] = useState(false); const [showAccountSettings, setShowAccountSettings] = useState(false); + const [showAvatarSettings, setShowAvatarSettings] = useState(false); const [showCryptoAddressSetting, setShowCryptoAddressSetting] = useState(false); const [showCryptoWalletSettings, setShowCryptoWalletSettings] = useState(false); const [showBlockedAddressesSetting, setShowBlockedAddressesSetting] = useState(false); @@ -30,6 +32,7 @@ const SettingsModal = () => { setExpandAll(newExpandState); setShowInterfaceSettings(newExpandState); setShowAccountSettings(newExpandState); + setShowAvatarSettings(newExpandState); setShowCryptoAddressSetting(newExpandState); setShowCryptoWalletSettings(newExpandState); setShowBlockedAddressesSetting(newExpandState); @@ -61,6 +64,13 @@ const SettingsModal = () => {
{showAccountSettings && } +
+ +
+ {showAvatarSettings && }