mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat: use red offline icon for subplebbits that are most likely offline (ipns record fails to update)
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -39,6 +39,10 @@
|
|||||||
image-rendering: pixelated;
|
image-rendering: pixelated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.redOfflineIcon {
|
||||||
|
background-image: url('/public/assets/icons/offline-red.png') !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.boardTitle {
|
.boardTitle {
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useAccountComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
import { useAccountComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||||
import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
|
||||||
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import styles from './board-header.module.css';
|
import styles from './board-header.module.css';
|
||||||
import { useMultisubMetadata } from '../../hooks/use-default-subplebbits';
|
import { useMultisubMetadata } from '../../hooks/use-default-subplebbits';
|
||||||
import useIsMobile from '../../hooks/use-is-mobile';
|
import useIsMobile from '../../hooks/use-is-mobile';
|
||||||
|
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||||
|
|
||||||
const totalBanners = 60;
|
const totalBanners = 60;
|
||||||
|
|
||||||
@@ -20,10 +19,8 @@ const ImageBanner = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const BoardHeader = () => {
|
const BoardHeader = () => {
|
||||||
const { t } = useTranslation();
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|
||||||
const isInAllView = isAllView(location.pathname, params);
|
const isInAllView = isAllView(location.pathname, params);
|
||||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||||
|
|
||||||
@@ -31,18 +28,14 @@ const BoardHeader = () => {
|
|||||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||||
|
|
||||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||||
const { address, shortAddress, updatedAt } = subplebbit || {};
|
const { address, shortAddress } = subplebbit || {};
|
||||||
|
|
||||||
const multisubMetadata = useMultisubMetadata();
|
const multisubMetadata = useMultisubMetadata();
|
||||||
|
|
||||||
const title = isInAllView ? multisubMetadata?.title || 'all' : isInSubscriptionsView ? 'Subscriptions' : subplebbit?.title;
|
const title = isInAllView ? multisubMetadata?.title || 'all' : isInSubscriptionsView ? 'Subscriptions' : subplebbit?.title;
|
||||||
const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : `p/${address}`;
|
const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : `p/${address}`;
|
||||||
|
|
||||||
const isBoardOffline = updatedAt && updatedAt < Date.now() / 1000 - 60 * 60;
|
const { isOffline, isDefinitelyOffline, offlineTitle } = useIsSubplebbitOffline(subplebbit);
|
||||||
|
const iconClass = `${styles.offlineIcon} ${isDefinitelyOffline ? styles.redOfflineIcon : ''}`;
|
||||||
const offlineMessage = updatedAt
|
|
||||||
? isBoardOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
|
|
||||||
: t('subplebbit_offline_info');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
@@ -53,7 +46,7 @@ const BoardHeader = () => {
|
|||||||
)}
|
)}
|
||||||
<div className={styles.boardTitle}>
|
<div className={styles.boardTitle}>
|
||||||
{title || `p/${shortAddress || subplebbitAddress}`}
|
{title || `p/${shortAddress || subplebbitAddress}`}
|
||||||
{isBoardOffline && <span className={styles.offlineIcon} title={offlineMessage} />}
|
{isOffline && <span className={`${styles.offlineIcon} ${iconClass}`} title={offlineTitle} />}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.boardSubtitle}>{subtitle}</div>
|
<div className={styles.boardSubtitle}>{subtitle}</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import useReply from '../../hooks/use-reply';
|
|||||||
import useChallengesStore from '../../stores/use-challenges-store';
|
import useChallengesStore from '../../stores/use-challenges-store';
|
||||||
import styles from './post-form.module.css';
|
import styles from './post-form.module.css';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||||
|
|
||||||
type SubmitState = {
|
type SubmitState = {
|
||||||
subplebbitAddress: string | undefined;
|
subplebbitAddress: string | undefined;
|
||||||
@@ -272,17 +272,12 @@ const PostForm = () => {
|
|||||||
const [showForm, setShowForm] = useState(false);
|
const [showForm, setShowForm] = useState(false);
|
||||||
|
|
||||||
const subplebbit = useSubplebbit({ subplebbitAddress: params?.subplebbitAddress });
|
const subplebbit = useSubplebbit({ subplebbitAddress: params?.subplebbitAddress });
|
||||||
const { updatedAt } = subplebbit || {};
|
const { isOffline, offlineTitle } = useIsSubplebbitOffline(subplebbit);
|
||||||
const isBoardOffline = updatedAt && updatedAt < Date.now() / 1000 - 60 * 60;
|
|
||||||
|
|
||||||
const offlineMessage = updatedAt
|
|
||||||
? isBoardOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
|
|
||||||
: t('subplebbit_offline_info');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.postFormDesktop}>
|
<div className={styles.postFormDesktop}>
|
||||||
{!(isInAllView || isInSubscriptionsView) && showForm && isBoardOffline && <div className={styles.offlineBoard}>{offlineMessage}</div>}
|
{!(isInAllView || isInSubscriptionsView) && showForm && isOffline && <div className={styles.offlineBoard}>{offlineTitle}</div>}
|
||||||
{isThreadClosed ? (
|
{isThreadClosed ? (
|
||||||
<div className={styles.closed}>
|
<div className={styles.closed}>
|
||||||
{t('thread_closed')}
|
{t('thread_closed')}
|
||||||
@@ -302,7 +297,7 @@ const PostForm = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.postFormMobile}>
|
<div className={styles.postFormMobile}>
|
||||||
{!(isInAllView || isInSubscriptionsView) && showForm && isBoardOffline && <div className={styles.offlineBoard}>{offlineMessage}</div>}
|
{!(isInAllView || isInSubscriptionsView) && showForm && isOffline && <div className={styles.offlineBoard}>{offlineTitle}</div>}
|
||||||
{isThreadClosed ? (
|
{isThreadClosed ? (
|
||||||
<div className={styles.closed}>
|
<div className={styles.closed}>
|
||||||
{t('thread_closed')}
|
{t('thread_closed')}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Subplebbit } from '@plebbit/plebbit-react-hooks';
|
||||||
|
import { getFormattedTimeAgo } from '../lib/utils/time-utils';
|
||||||
|
|
||||||
|
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 offlineTitle = updatedAt
|
||||||
|
? isOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
|
||||||
|
: t('subplebbit_offline_info');
|
||||||
|
|
||||||
|
return { isOffline, isDefinitelyOffline, offlineTitle };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useIsSubplebbitOffline;
|
||||||
@@ -30,6 +30,10 @@ hr {
|
|||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,14 +72,14 @@ const Board = () => {
|
|||||||
const loadingString = (
|
const loadingString = (
|
||||||
<div className={styles.stateString}>
|
<div className={styles.stateString}>
|
||||||
{state === 'failed' ? (
|
{state === 'failed' ? (
|
||||||
state
|
<span className='red'>{state}</span>
|
||||||
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
|
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
|
||||||
t('not_subscribed_to_any_board')
|
t('not_subscribed_to_any_board')
|
||||||
) : (
|
) : (
|
||||||
<LoadingEllipsis string={loadingStateString} />
|
<LoadingEllipsis string={loadingStateString} />
|
||||||
)}
|
)}
|
||||||
{error && (
|
{error && (
|
||||||
<div style={{ color: 'red' }}>
|
<div className='red'>
|
||||||
<br />
|
<br />
|
||||||
{error.message}
|
{error.message}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { Link } from 'react-router-dom';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Subplebbit, useAccount, useAccountSubplebbits } from '@plebbit/plebbit-react-hooks';
|
import { Subplebbit, useAccount, useAccountSubplebbits } from '@plebbit/plebbit-react-hooks';
|
||||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||||
import { getFormattedTimeAgo } from '../../../lib/utils/time-utils';
|
|
||||||
import useHomeFiltersStore from '../../../stores/use-home-filters-store';
|
import useHomeFiltersStore from '../../../stores/use-home-filters-store';
|
||||||
import { useMultisubMetadata } from '../../../hooks/use-default-subplebbits';
|
import { useMultisubMetadata } from '../../../hooks/use-default-subplebbits';
|
||||||
import styles from '../home.module.css';
|
import styles from '../home.module.css';
|
||||||
import { nsfwTags } from '../home';
|
import { nsfwTags } from '../home';
|
||||||
import BoxModal from '../box-modal';
|
import BoxModal from '../box-modal';
|
||||||
|
import useIsSubplebbitOffline from '../../../hooks/use-is-subplebbit-offline';
|
||||||
|
|
||||||
const Board = ({ subplebbit, subplebbits }: { subplebbit: Subplebbit; subplebbits: any }) => {
|
const Board = ({ subplebbit, subplebbits }: { subplebbit: Subplebbit; subplebbits: any }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -18,15 +18,12 @@ const Board = ({ subplebbit, subplebbits }: { subplebbit: Subplebbit; subplebbit
|
|||||||
const boardLink = useCatalog ? `/p/${address}/catalog` : `/p/${address}`;
|
const boardLink = useCatalog ? `/p/${address}/catalog` : `/p/${address}`;
|
||||||
|
|
||||||
const subplebbitData = subplebbits && subplebbits.find((sub: Subplebbit) => sub?.address === address);
|
const subplebbitData = subplebbits && subplebbits.find((sub: Subplebbit) => sub?.address === address);
|
||||||
const updatedAt = subplebbitData?.updatedAt;
|
const { isDefinitelyOffline, isOffline, offlineTitle } = useIsSubplebbitOffline(subplebbitData);
|
||||||
const isOffline = updatedAt && updatedAt < Date.now() / 1000 - 60 * 60;
|
const iconClass = `${styles.offlineIcon} ${isDefinitelyOffline ? styles.redOfflineIcon : ''}`;
|
||||||
const offlineTitle = updatedAt
|
|
||||||
? isOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
|
|
||||||
: t('subplebbit_offline_info');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.subplebbit} key={address}>
|
<div className={styles.subplebbit} key={address}>
|
||||||
{isOffline && <span className={styles.offlineIcon} title={offlineTitle} />}
|
{isOffline && <span className={`${styles.offlineIcon} ${iconClass}`} title={offlineTitle} />}
|
||||||
<Link to={boardLink}>{title || address}</Link>
|
<Link to={boardLink}>{title || address}</Link>
|
||||||
{nsfwTag && <span className={styles.nsfw}> ({t(nsfwTag)})</span>}
|
{nsfwTag && <span className={styles.nsfw}> ({t(nsfwTag)})</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -187,6 +187,10 @@
|
|||||||
image-rendering: pixelated;
|
image-rendering: pixelated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.redOfflineIcon {
|
||||||
|
background-image: url('/public/assets/icons/offline-red.png') !important;
|
||||||
|
}
|
||||||
|
|
||||||
.boardsBoxContent {
|
.boardsBoxContent {
|
||||||
font-size: 93%;
|
font-size: 93%;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
|||||||
Reference in New Issue
Block a user