diff --git a/src/components/catalog-row/catalog-row.tsx b/src/components/catalog-row/catalog-row.tsx index 539e0769..fa9d8eb7 100644 --- a/src/components/catalog-row/catalog-row.tsx +++ b/src/components/catalog-row/catalog-row.tsx @@ -7,7 +7,7 @@ import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import styles from './catalog-row.module.css'; -const CatalogPostMedia = ({ commentMediaInfo, link }: { commentMediaInfo: any; link: string }) => { +export const CatalogPostMedia = ({ commentMediaInfo }: { commentMediaInfo: any }) => { const { patternThumbnailUrl, thumbnail, type, url } = commentMediaInfo || {}; const iframeThumbnail = patternThumbnailUrl || thumbnail; const gifFrameUrl = useFetchGifFirstFrame(type === 'gif' ? url : undefined); @@ -91,7 +91,7 @@ const CatalogPost = ({ openMenu, post, toggleMenu }: CatalogPostProps) => {
{threadIcons}
- +
diff --git a/src/components/catalog-row/index.ts b/src/components/catalog-row/index.ts index d481e3d2..43c42f2c 100644 --- a/src/components/catalog-row/index.ts +++ b/src/components/catalog-row/index.ts @@ -1 +1 @@ -export { default } from './catalog-row'; +export { default, CatalogPostMedia } from './catalog-row'; diff --git a/src/views/home/home.module.css b/src/views/home/home.module.css index ce973af0..c400149d 100644 --- a/src/views/home/home.module.css +++ b/src/views/home/home.module.css @@ -25,6 +25,11 @@ padding-bottom: 0.5em; } +.boardsBox { + height: 343px; + overflow: hidden; +} + .boxBar, .infoboxBar { padding-left: 0.5em; line-height: 2em; @@ -167,6 +172,63 @@ text-decoration: underline; } +.popularThreads { + font-size: 93%; + padding: 0.5em; + padding-top: 0.25em; + padding-bottom: 0; + line-height: 130%; + text-align: center; +} + +.popularThreads .loading { + text-align: left !important; +} + +.popularThread { + vertical-align: top; + display: inline-block; + word-wrap: break-word; + overflow: hidden; + margin-top: 5px; + padding: 5px 0 3px; + position: relative; + width: 175px; + max-height: 320px; + margin-bottom: 10px; + color: #800; +} + +.popularThread .title { + font-weight: 700; + overflow: hidden; + text-overflow: ellipsis; + display: block; + white-space: nowrap; + margin-bottom: 5px; +} + +.popularThread .mediaContainer { + width: auto; + height: auto; + border: 1px solid #800; + display: inline-block; + overflow: hidden; + position: relative; + line-height: 0; +} + +.popularThread .mediaContainer img { + max-width: 150px; + max-height: 150px; +} + +.popularThread .threadContent { + margin-bottom: 5px; + padding: 0 2px; + white-space: pre-line; +} + @media (max-width: 640px) { .content { min-width: 0; diff --git a/src/views/home/home.tsx b/src/views/home/home.tsx index ce3ce533..352eec46 100644 --- a/src/views/home/home.tsx +++ b/src/views/home/home.tsx @@ -1,10 +1,13 @@ -import { useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; import styles from './home.module.css'; import { Link, useNavigate } from 'react-router-dom'; import { Trans, useTranslation } from 'react-i18next'; -import { Subplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; +import { Comment, Subplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; import packageJson from '../../../package.json'; -import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits'; +import useDefaultSubplebbits, { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits'; +import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; +import { CatalogPostMedia } from '../../components/catalog-row'; +import LoadingEllipsis from '../../components/loading-ellipsis'; const isValidAddress = (address: string): boolean => { if (address.includes('/') || address.includes('\\') || address.includes(' ')) { @@ -66,11 +69,11 @@ const InfoBox = () => { ); }; -const Boards = ({ subplebbits }: { subplebbits: (Subplebbit | undefined)[] }) => { +const Boards = ({ defaultSubplebbits }: { defaultSubplebbits: any }) => { const { t } = useTranslation(); return ( -
+

{t('boards')}

{t('options')} ▼ @@ -79,7 +82,7 @@ const Boards = ({ subplebbits }: { subplebbits: (Subplebbit | undefined)[] }) =>

Default SFW

- {subplebbits + {defaultSubplebbits .filter((subplebbit: Subplebbit | undefined): subplebbit is Subplebbit => subplebbit !== undefined) .map((subplebbit: Subplebbit) => { const address = subplebbit.address; @@ -105,15 +108,94 @@ const Boards = ({ subplebbits }: { subplebbits: (Subplebbit | undefined)[] }) => ); }; -const PopularThreads = () => { +interface PopularThreadProps { + post: Comment; + boardTitle: string | undefined; + boardShortAddress: string; +} + +const PopularThreadCard = ({ post, boardTitle, boardShortAddress }: PopularThreadProps) => { + const { cid, content, subplebbitAddress, title } = post || {}; + const commentMediaInfo = getCommentMediaInfo(post); + + return ( +
+
{boardTitle || boardShortAddress}
+
+ + + +
+
+ {title && {title}} + {content && (content.length > 99 ? `: ${content.substring(0, 99)}...` : `: ${content}`)} +
+
+ ); +}; + +const PopularThreads = ({ subplebbits }: { subplebbits: any }) => { const { t } = useTranslation(); + const [popularPosts, setPopularPosts] = useState([]); + + useEffect(() => { + let subplebbitToPost: any = {}; + + subplebbits.forEach((subplebbit: any) => { + let mostRecentPost = null; + + if (subplebbit?.posts?.pages?.hot?.comments) { + for (const comment of Object.values(subplebbit.posts.pages.hot.comments) as Comment[]) { + const { deleted, locked, pinned, removed, replyCount, timestamp } = comment; + + const commentMediaInfo = getCommentMediaInfo(comment); + const isMediaShowed = getHasThumbnail(commentMediaInfo, comment.link); + + if ( + isMediaShowed && + replyCount >= 2 && + !removed && + !deleted && + !locked && + !pinned && // criteria + timestamp > Date.now() / 1000 - 60 * 60 * 24 * 30 // 30 days + ) { + if (!mostRecentPost || comment.timestamp > mostRecentPost.timestamp) { + mostRecentPost = comment; + } + } + + if (mostRecentPost) { + subplebbitToPost[subplebbit.address] = mostRecentPost; + } + } + } + }); + + const newPopularPosts: any = Object.values(subplebbitToPost) + .sort((a: any, b: any) => b.timestamp - a.timestamp) + .slice(0, 8); + + setPopularPosts(newPopularPosts); + }, [subplebbits]); + return (

{t('popular_threads')}

{t('options')} ▼
-
+
+ {popularPosts.length < 8 ? ( + + + + ) : ( + popularPosts.map((post: any) => ( + + )) + )} +
); }; @@ -219,6 +301,7 @@ const Footer = () => { }; const Home = () => { + const defaultSubplebbits = useDefaultSubplebbits(); const subplebbitAddresses = useDefaultSubplebbitAddresses(); const { subplebbits } = useSubplebbits({ subplebbitAddresses }); @@ -231,8 +314,8 @@ const Home = () => { - - + +