diff --git a/src/components/board-header/board-header.tsx b/src/components/board-header/board-header.tsx
index dbcc7bd5..cf7f0ae9 100644
--- a/src/components/board-header/board-header.tsx
+++ b/src/components/board-header/board-header.tsx
@@ -45,7 +45,9 @@ const BoardHeader = () => {
)}
{title || `p/${shortAddress || subplebbitAddress}`}
- {(isOffline || isOnlineStatusLoading) && }
+ {(isOffline || isOnlineStatusLoading) && !isInAllView && !isInSubscriptionsView && (
+
+ )}
{subtitle}
diff --git a/src/components/markdown/markdown.module.css b/src/components/markdown/markdown.module.css
index fe6b2eec..9ecbb5e8 100644
--- a/src/components/markdown/markdown.module.css
+++ b/src/components/markdown/markdown.module.css
@@ -8,10 +8,6 @@
text-decoration: var(--post-content-link-text-decoration-hover);
}
-.markdown li {
- list-style-position: inside;
-}
-
.hrWrapper {
padding: 0.5em 0;
}
diff --git a/src/components/post-desktop/post-desktop.tsx b/src/components/post-desktop/post-desktop.tsx
index 768afb7b..1a149f92 100644
--- a/src/components/post-desktop/post-desktop.tsx
+++ b/src/components/post-desktop/post-desktop.tsx
@@ -102,9 +102,9 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
{!(isDescription || isRules) && (
<>
{isReply && author?.avatar && (
- <>
- {' '}
- >
+
+
+
)}
(u/
{
const stateString = useStateString(post);
- const loadingString = stateString && (
- {stateString !== 'Failed' ? : stateString}
+ const loadingString = (
+ {stateString !== 'Failed' ? : stateString}
);
return (
@@ -341,7 +341,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
post = editedComment;
}
- const { author, cid, content, link, postCid, subplebbitAddress } = post || {};
+ const { author, cid, link, postCid, subplebbitAddress } = post || {};
const isRouteLinkToReply = useLocation().pathname.startsWith(`/p/${subplebbitAddress}/c/${cid}`);
const { hidden } = useHide({ cid });
@@ -356,7 +356,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
>
{link && !hidden && isValidURL(link) && }
- {content && !hidden && }
+ {!hidden && }
);
@@ -434,7 +434,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
)}
)}
- {post?.replyCount === undefined && (
+ {post?.replyCount === undefined && !isInPendingPostView && (
@@ -452,14 +452,15 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
))}
- {stateString && stateString !== 'Failed' ? (
-
-
-
-
- ) : (
- state === 'failed' && {t('failed')}
- )}
+ {!isInPendingPostView &&
+ (stateString && stateString !== 'Failed' ? (
+
+
+
+
+ ) : (
+ state === 'failed' && {t('failed')}
+ ))}
);
};
diff --git a/src/components/post-mobile/post-mobile.tsx b/src/components/post-mobile/post-mobile.tsx
index 980e7ec3..0eb84770 100644
--- a/src/components/post-mobile/post-mobile.tsx
+++ b/src/components/post-mobile/post-mobile.tsx
@@ -75,9 +75,9 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
{!(isDescription || isRules) && (
<>
{isReply && author?.avatar && (
- <>
- {' '}
- >
+
+
+
)}
(u/
{
const stateString = useStateString(post);
- const loadingString = stateString && (
- {stateString !== 'Failed' ? : stateString}
+ const loadingString = (
+ {stateString !== 'Failed' ? : stateString}
);
return (
- content && (
-
- {isReply && !(removed || deleted) && state !== 'failed' && isReplyingToReply && }
- {removed ? (
+
+ {isReply && !(removed || deleted) && state !== 'failed' && isReplyingToReply && }
+ {removed ? (
+ ({t('this_post_was_removed')})}
+ content={`${_.capitalize(t('reason'))}: "${reason}"`}
+ showTooltip={!!reason}
+ />
+ ) : deleted ? (
+ {t('user_deleted_this_post')}} content={reason && `${t('reason')}: ${reason}`} />
+ ) : (
+ <>
+ {!showOriginal && }
+ {edit && original?.content !== post?.content && (
+
+ {showOriginal && }
+
+ {t('comment_edited_at_timestamp', { timestamp: getFormattedDate(edit?.timestamp), interpolation: { escapeValue: false } })}{' '}
+ {reason && <>{t('reason_reason', { reason: reason, interpolation: { escapeValue: false } })} >}
+ {showOriginal ? (
+ setShowOriginal(!showOriginal)} /> }}
+ />
+ ) : (
+ setShowOriginal(!showOriginal)} /> }}
+ />
+ )}
+
+ )}
+ >
+ )}
+ {/* TODO: commentAuthor is not available outside of editedComment, update when available */}
+ {/* {banned && (
+
+
+
({t('this_post_was_removed')})}
- content={`${_.capitalize(t('reason'))}: "${reason}"`}
- showTooltip={!!reason}
+ children={`(${t('user_banned')})`}
+ content={`${t('ban_expires_at', {
+ address: subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress),
+ timestamp: getFormattedDate(commentAuthor?.banExpiresAt),
+ interpolation: { escapeValue: false },
+ })}${reason ? `. ${_.capitalize(t('reason'))}: "${reason}"` : ''}`}
/>
- ) : deleted ? (
- {t('user_deleted_this_post')}} content={reason && `${t('reason')}: ${reason}`} />
- ) : (
- <>
- {!showOriginal && }
- {edit && original?.content !== post?.content && (
-
- {showOriginal && }
-
- {t('comment_edited_at_timestamp', { timestamp: getFormattedDate(edit?.timestamp), interpolation: { escapeValue: false } })}{' '}
- {reason && <>{t('reason_reason', { reason: reason, interpolation: { escapeValue: false } })} >}
- {showOriginal ? (
- setShowOriginal(!showOriginal)} /> }}
- />
- ) : (
- setShowOriginal(!showOriginal)} /> }}
- />
- )}
-
- )}
- >
- )}
- {/* TODO: commentAuthor is not available outside of editedComment, update when available */}
- {/* {banned && (
-
-
-
-
-
- )} */}
- {!isReply && content.length > 1000 && !isInPostView && (
-
-
- }} />
-
- )}
- {!cid && state === 'pending' && stateString !== 'Failed' && (
- <>
-
- {loadingString}
- >
- )}
-
- )
+
+ )} */}
+ {!isReply && content.length > 1000 && !isInPostView && (
+
+
+ }} />
+
+ )}
+ {!cid && state === 'pending' && stateString !== 'Failed' && (
+ <>
+
+ {loadingString}
+ >
+ )}
+
);
};
@@ -261,7 +259,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
if (editedComment) {
post = editedComment;
}
- const { author, cid, content, postCid, subplebbitAddress } = post || {};
+ const { author, cid, postCid, subplebbitAddress } = post || {};
const isRouteLinkToReply = useLocation().pathname.startsWith(`/p/${subplebbitAddress}/c/${cid}`);
const { hidden } = useHide({ cid });
@@ -275,7 +273,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
data-post-cid={postCid}
>
- {content && !hidden && }
+ {!hidden && }
@@ -348,7 +346,7 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
)}
- {post?.replyCount === undefined && (
+ {post?.replyCount === undefined && !isInPendingPostView && (
@@ -365,13 +363,14 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
))}
- {stateString && stateString !== 'Failed' ? (
-
-
-
- ) : (
- state === 'failed' && {t('failed')}
- )}
+ {!isInPendingPostView &&
+ (stateString && stateString !== 'Failed' ? (
+
+
+
+ ) : (
+ state === 'failed' && {t('failed')}
+ ))}
)}
>
diff --git a/src/components/reply-modal/reply-modal.tsx b/src/components/reply-modal/reply-modal.tsx
index b4a1a440..c8842b93 100644
--- a/src/components/reply-modal/reply-modal.tsx
+++ b/src/components/reply-modal/reply-modal.tsx
@@ -86,11 +86,16 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => {
if (ref) {
textRef.current = ref;
!isMobile && ref.focus();
- const len = ref.value.length;
- ref.setSelectionRange(len, len);
}
};
+ useEffect(() => {
+ if (textRef.current) {
+ const len = textRef.current.value.length;
+ textRef.current.setSelectionRange(len, len);
+ }
+ }, []);
+
const contentPrefix = `c/${parentCid && Plebbit.getShortCid(parentCid)}\n`;
const handleContentInput = (e: React.ChangeEvent) => {
diff --git a/src/components/settings-modal/avatar-settings/avatar-settings.module.css b/src/components/settings-modal/avatar-settings/avatar-settings.module.css
index 163afba8..409947bb 100644
--- a/src/components/settings-modal/avatar-settings/avatar-settings.module.css
+++ b/src/components/settings-modal/avatar-settings/avatar-settings.module.css
@@ -4,7 +4,6 @@
border: 1px solid #aaa;
background-color: var(--avatar-background-color, white);
margin-left: 10px;
- border-radius: 32px;
overflow: hidden;
}
diff --git a/src/hooks/use-is-subplebbit-offline.ts b/src/hooks/use-is-subplebbit-offline.ts
index 70181ff8..f94c2f64 100644
--- a/src/hooks/use-is-subplebbit-offline.ts
+++ b/src/hooks/use-is-subplebbit-offline.ts
@@ -3,11 +3,13 @@ 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';
+import useSubplebbitsLoadingStartTimestamps from './use-subplebbits-loading-start-timestamps-store';
const useIsSubplebbitOffline = (subplebbit: Subplebbit) => {
const { t } = useTranslation();
const { address, state, updatedAt, updatingState } = subplebbit || {};
const { subplebbitOfflineState, setSubplebbitOfflineState, initializesubplebbitOfflineState } = useSubplebbitOfflineStore();
+ const subplebbitsLoadingStartTimestamps = useSubplebbitsLoadingStartTimestamps([address]);
useEffect(() => {
if (address && !subplebbitOfflineState[address]) {
@@ -22,15 +24,13 @@ const useIsSubplebbitOffline = (subplebbit: Subplebbit) => {
}, [address, state, updatedAt, updatingState, setSubplebbitOfflineState]);
const subplebbitOfflineStore = subplebbitOfflineState[address] || { initialLoad: true };
+ const loadingStartTimestamp = subplebbitsLoadingStartTimestamps[0] || 0;
- const isLoading =
- updatingState === 'resolving-address' ||
- (updatingState === 'stopped' && state === 'stopped' && !updatedAt) ||
- (subplebbitOfflineStore.initialLoad && updatingState === 'fetching-ipns' && !updatedAt);
+ const isLoading = subplebbitOfflineStore.initialLoad && (!updatedAt || Date.now() / 1000 - updatedAt >= 60 * 60) && Date.now() / 1000 - loadingStartTimestamp < 30;
- const isOffline =
- !isLoading && ((updatedAt && updatedAt < Date.now() / 1000 - 60 * 60) || updatingState === 'failed' || (updatingState === 'fetching-ipns' && !updatedAt));
+ const isOffline = !isLoading && ((updatedAt && updatedAt < Date.now() / 1000 - 60 * 60) || (!updatedAt && Date.now() / 1000 - loadingStartTimestamp >= 30));
+ const isOnline = updatedAt && Date.now() / 1000 - updatedAt < 60 * 60;
const offlineIconClass = isLoading ? 'yellowOfflineIcon' : isOffline ? 'redOfflineIcon' : '';
const offlineTitle = isLoading
@@ -39,7 +39,7 @@ const useIsSubplebbitOffline = (subplebbit: Subplebbit) => {
? isOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
: t('subplebbit_offline_info');
- return { isOffline, isOnlineStatusLoading: isLoading, offlineIconClass, offlineTitle };
+ return { isOffline: !isOnline && isOffline, isOnlineStatusLoading: !isOnline && isLoading, offlineIconClass, offlineTitle };
};
export default useIsSubplebbitOffline;
diff --git a/src/hooks/use-subplebbits-loading-start-timestamps-store.ts b/src/hooks/use-subplebbits-loading-start-timestamps-store.ts
new file mode 100644
index 00000000..80ecdb5b
--- /dev/null
+++ b/src/hooks/use-subplebbits-loading-start-timestamps-store.ts
@@ -0,0 +1,42 @@
+import { useEffect, useMemo } from 'react';
+import { create } from 'zustand';
+
+interface SubplebbitsLoadingStartTimestampsState {
+ timestamps: Record;
+ addSubplebbits: (subplebbitAddresses: string[]) => void;
+}
+
+const useSubplebbitsLoadingStartTimestampsStore = create((set, get) => ({
+ timestamps: {},
+ addSubplebbits: (subplebbitAddresses) => {
+ const { timestamps } = get();
+ const newTimestamps: Record = {};
+ subplebbitAddresses.forEach((subplebbitAddress) => {
+ if (!timestamps[subplebbitAddress]) {
+ newTimestamps[subplebbitAddress] = Math.round(Date.now() / 1000);
+ }
+ });
+ if (Object.keys(newTimestamps).length) {
+ set((state) => ({ timestamps: { ...state.timestamps, ...newTimestamps } }));
+ }
+ },
+}));
+
+const useSubplebbitsLoadingStartTimestamps = (subplebbitAddresses?: string[]) => {
+ const timestampsStore = useSubplebbitsLoadingStartTimestampsStore((state) => state.timestamps);
+ const addSubplebbits = useSubplebbitsLoadingStartTimestampsStore((state) => state.addSubplebbits);
+
+ useEffect(() => {
+ if (subplebbitAddresses) {
+ addSubplebbits(subplebbitAddresses);
+ }
+ }, [subplebbitAddresses, addSubplebbits]);
+
+ const subplebbitsLoadingStartTimestamps = useMemo(() => {
+ return subplebbitAddresses?.map((subplebbitAddress) => timestampsStore[subplebbitAddress]) || [];
+ }, [timestampsStore, subplebbitAddresses]);
+
+ return subplebbitsLoadingStartTimestamps;
+};
+
+export default useSubplebbitsLoadingStartTimestamps;
diff --git a/src/views/post/post.module.css b/src/views/post/post.module.css
index 2583f8a3..5c9e6bb0 100644
--- a/src/views/post/post.module.css
+++ b/src/views/post/post.module.css
@@ -505,22 +505,23 @@
}
.authorAvatar {
- width: 22px;
- height: 22px;
- background-size: 100%;
- background-position: center;
- background-repeat: no-repeat;
+ width: 24px;
display: inline-block;
- vertical-align: top;
+ position: relative;
+ padding-right: 2px;
}
+.authorAvatar img {
+ width: 24px;
+ max-height: 24px;
+ position: absolute;
+ bottom: -5px;
+}
.stateString {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- width: calc(100vw - 28px);
- width: 100vw;
}
@media (max-width: 640px) {
@@ -542,11 +543,13 @@
}
.authorAvatar {
- vertical-align: middle;
+ width: 20px;
}
- .stateString {
- padding-left: 5px;
+ .authorAvatar img {
+ width: 20px;
+ max-height: 20px;
+ bottom: -3px;
}
}
@@ -568,8 +571,4 @@
.replyMobile {
display: none;
}
-
- .stateString {
- padding-top: 10px;
- }
}
\ No newline at end of file