mirror of
https://github.com/plebbit/seedit.git
synced 2026-02-15 08:21:19 -05:00
refactor(feed post): move functions to utils, move expando and button code to new components, remove repetitions
This commit is contained in:
36
src/components/expand-button/expand-button.module.css
Normal file
36
src/components/expand-button/expand-button.module.css
Normal file
@@ -0,0 +1,36 @@
|
||||
.buttonWrapper {
|
||||
padding: 2px 5px 2px 0;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.buttonCommon {
|
||||
background-size: cover;
|
||||
height: 23px;
|
||||
width: 23px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.textButton {
|
||||
background-image: var(--text-button);
|
||||
}
|
||||
|
||||
.textButton:hover {
|
||||
background-image: var(--text-button-hover);
|
||||
}
|
||||
|
||||
.playButton {
|
||||
background-image: var(--play-button);
|
||||
}
|
||||
|
||||
.playButton:hover {
|
||||
background-image: var(--play-button-hover);
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
background-image: var(--close-button);
|
||||
}
|
||||
|
||||
.closeButton:hover {
|
||||
background-image: var(--close-button-hover);
|
||||
}
|
||||
31
src/components/expand-button/expand-button.tsx
Normal file
31
src/components/expand-button/expand-button.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { FC } from 'react';
|
||||
import { useComment } from '@plebbit/plebbit-react-hooks';
|
||||
import styles from './expand-button.module.css';
|
||||
import utils from '../../lib/utils';
|
||||
|
||||
interface ExpandButtonProps {
|
||||
commentCid: string;
|
||||
expanded: boolean;
|
||||
hasThumbnail: boolean;
|
||||
toggleExpanded: () => void;
|
||||
}
|
||||
|
||||
const ExpandButton: FC<ExpandButtonProps> = ({ commentCid, expanded, hasThumbnail, toggleExpanded }) => {
|
||||
const comment = useComment({ commentCid });
|
||||
const { content, link } = comment || {};
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemoized(comment);
|
||||
|
||||
const initialButtonType = hasThumbnail || commentMediaInfo?.type === 'audio' || commentMediaInfo?.type === 'iframe' ? 'playButton' : 'textButton';
|
||||
|
||||
const buttonType = expanded ? 'closeButton' : initialButtonType;
|
||||
|
||||
return (
|
||||
((content && !link) || link) && (
|
||||
<div className={styles.buttonWrapper} onClick={toggleExpanded}>
|
||||
<div className={`${styles.buttonCommon} ${styles[buttonType]}`}></div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ExpandButton;
|
||||
1
src/components/expand-button/index.ts
Normal file
1
src/components/expand-button/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {default} from './expand-button';
|
||||
44
src/components/expando/expando.module.css
Normal file
44
src/components/expando/expando.module.css
Normal file
@@ -0,0 +1,44 @@
|
||||
.expandoHidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.expando {
|
||||
display: block;
|
||||
padding: 5px 0 5px 0;
|
||||
clear: left;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.usertext {
|
||||
unicode-bidi: isolate;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.markdown {
|
||||
background-color: var(--background-markdown);
|
||||
border: 1px solid var(--text-primary);
|
||||
border-radius: 7px;
|
||||
padding: 5px 10px;
|
||||
font-weight: 400;
|
||||
color: var(--text-markdown);
|
||||
max-width: 60em;
|
||||
word-wrap: break-word;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.mediaPreview {
|
||||
max-width: 354px;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mediaPreview img, .mediaPreview video {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.mediaPreview iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
67
src/components/expando/expando.tsx
Normal file
67
src/components/expando/expando.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { FC } from 'react';
|
||||
import { useComment } from '@plebbit/plebbit-react-hooks';
|
||||
import utils from '../../lib/utils';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './expando.module.css';
|
||||
import Embed from '../embed';
|
||||
|
||||
interface ExpandoProps {
|
||||
commentCid: string;
|
||||
expanded: boolean;
|
||||
}
|
||||
|
||||
const Expando: FC<ExpandoProps> = ({ commentCid, expanded }) => {
|
||||
const comment = useComment({ commentCid });
|
||||
const { cid, content, link, subplebbitAddress } = comment || {};
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemoized(comment);
|
||||
|
||||
return (
|
||||
<div className={expanded ? styles.expando : styles.expandoHidden}>
|
||||
{link && (
|
||||
<div className={styles.mediaPreview}>
|
||||
<Link to={`p/${subplebbitAddress}/c/${cid}`} onClick={(e) => e.preventDefault()}>
|
||||
{commentMediaInfo?.type === 'image' && (
|
||||
<img
|
||||
src={commentMediaInfo.url}
|
||||
alt='thumbnail'
|
||||
onError={(e) => {
|
||||
e.currentTarget.alt = '';
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{commentMediaInfo?.type === 'video' &&
|
||||
(commentMediaInfo.thumbnail ? (
|
||||
<img
|
||||
src={commentMediaInfo.thumbnail}
|
||||
alt='thumbnail'
|
||||
onError={(e) => {
|
||||
e.currentTarget.alt = '';
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<video src={commentMediaInfo.url} controls />
|
||||
))}
|
||||
{commentMediaInfo?.type === 'webpage' && commentMediaInfo.thumbnail && (
|
||||
<img
|
||||
src={commentMediaInfo.thumbnail}
|
||||
alt='thumbnail'
|
||||
onError={(e) => {
|
||||
e.currentTarget.alt = '';
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{commentMediaInfo?.type === 'audio' && <audio src={commentMediaInfo.url} controls />}
|
||||
{commentMediaInfo?.type === 'iframe' && expanded && <Embed url={commentMediaInfo.url} />}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{content && (
|
||||
<div className={styles.usertext}>
|
||||
<div className={styles.markdown}>{content}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Expando;
|
||||
1
src/components/expando/index.ts
Normal file
1
src/components/expando/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {default} from './expando';
|
||||
@@ -91,87 +91,4 @@
|
||||
|
||||
.tagline .subplebbit:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.buttonWrapper {
|
||||
padding: 2px 5px 2px 0;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.buttonCommon {
|
||||
background-size: cover;
|
||||
height: 23px;
|
||||
width: 23px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.textButton {
|
||||
background-image: var(--text-button);
|
||||
}
|
||||
|
||||
.textButton:hover {
|
||||
background-image: var(--text-button-hover);
|
||||
}
|
||||
|
||||
.playButton {
|
||||
background-image: var(--play-button);
|
||||
}
|
||||
|
||||
.playButton:hover {
|
||||
background-image: var(--play-button-hover);
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
background-image: var(--close-button);
|
||||
}
|
||||
|
||||
.closeButton:hover {
|
||||
background-image: var(--close-button-hover);
|
||||
}
|
||||
|
||||
|
||||
.expandoHidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.expando {
|
||||
display: block;
|
||||
padding: 5px 0 5px 0;
|
||||
clear: left;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.usertext {
|
||||
unicode-bidi: isolate;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.markdown {
|
||||
background-color: var(--background-markdown);
|
||||
border: 1px solid var(--text-primary);
|
||||
border-radius: 7px;
|
||||
padding: 5px 10px;
|
||||
font-weight: 400;
|
||||
color: var(--text-markdown);
|
||||
max-width: 60em;
|
||||
word-wrap: break-word;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.mediaPreview {
|
||||
max-width: 354px;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mediaPreview img, .mediaPreview video {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.mediaPreview iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
@@ -4,7 +4,8 @@ import { Link } from 'react-router-dom';
|
||||
import utils from '../../lib/utils';
|
||||
import { Comment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Embed from '../embed';
|
||||
import ExpandButton from '../expand-button';
|
||||
import Expando from '../expando';
|
||||
import Flair from '../flair';
|
||||
import PostTools from '../post-tools';
|
||||
import Thumbnail from '../thumbnail';
|
||||
@@ -16,26 +17,15 @@ interface FeedPostProps {
|
||||
|
||||
const FeedPost: FC<FeedPostProps> = ({ post, index }) => {
|
||||
const { author, cid, content, downvoteCount, flair, link, subplebbitAddress, timestamp, title, upvoteCount } = post || {};
|
||||
const { t } = useTranslation();
|
||||
const [expandoVisible, setExpandoVisible] = useState(false);
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemo(post);
|
||||
const iframeThumbnail = commentMediaInfo?.patternThumbnailUrl || commentMediaInfo?.thumbnail;
|
||||
const hasThumbnail =
|
||||
link &&
|
||||
commentMediaInfo &&
|
||||
(commentMediaInfo.type === 'image' ||
|
||||
commentMediaInfo.type === 'video' ||
|
||||
(commentMediaInfo.type === 'webpage' && commentMediaInfo.thumbnail) ||
|
||||
(commentMediaInfo.type === 'iframe' && iframeThumbnail))
|
||||
? true
|
||||
: false;
|
||||
const initialButtonType = hasThumbnail || commentMediaInfo?.type === 'audio' || commentMediaInfo?.type === 'iframe' ? 'playButton' : 'textButton';
|
||||
const [buttonType, setButtonType] = useState<'textButton' | 'playButton' | 'closeButton'>(initialButtonType);
|
||||
const toggleExpando = () => {
|
||||
setExpandoVisible(!expandoVisible);
|
||||
setButtonType(buttonType === 'closeButton' ? 'textButton' : 'closeButton');
|
||||
};
|
||||
const { t } = useTranslation();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const toggleExpanded = () => setExpanded(!expanded);
|
||||
const postTitleOrContent = (title?.length > 90 ? title?.slice(0, 90) + '...' : title) || (content?.length > 90 ? content?.slice(0, 90) + '...' : content);
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemoized(content);
|
||||
const hasThumbnail = utils.hasThumbnail(commentMediaInfo, link);
|
||||
|
||||
// TEMPORARY: e.preventDefault() in Link elements because routes aren't implemented yet
|
||||
|
||||
return (
|
||||
<div className={styles.container} key={index}>
|
||||
@@ -53,7 +43,7 @@ const FeedPost: FC<FeedPostProps> = ({ post, index }) => {
|
||||
<div className={styles.topMatter}>
|
||||
<p className={styles.title}>
|
||||
<Link className={styles.link} to={`p/${subplebbitAddress}/c/${cid}`} onClick={(e) => e.preventDefault()}>
|
||||
{(title?.length > 90 ? title?.slice(0, 90) + '...' : title) || (content?.length > 90 ? content?.slice(0, 90) + '...' : content)}
|
||||
{postTitleOrContent}
|
||||
</Link>
|
||||
{flair && (
|
||||
<>
|
||||
@@ -72,16 +62,7 @@ const FeedPost: FC<FeedPostProps> = ({ post, index }) => {
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
{content && !link && (
|
||||
<div className={styles.buttonWrapper} onClick={toggleExpando}>
|
||||
<div className={`${styles.buttonCommon} ${styles[buttonType]}`}></div>
|
||||
</div>
|
||||
)}
|
||||
{link && (
|
||||
<div className={styles.buttonWrapper} onClick={toggleExpando}>
|
||||
<div className={`${styles.buttonCommon} ${styles[buttonType]}`}></div>
|
||||
</div>
|
||||
)}
|
||||
<ExpandButton commentCid={cid} expanded={expanded} hasThumbnail={hasThumbnail} toggleExpanded={toggleExpanded} />
|
||||
<p className={styles.tagline}>
|
||||
{t('feed_post_submitted')} {utils.getFormattedTime(timestamp)} {t('feed_post_by')}
|
||||
<Link className={styles.author} to={`u/${author.shortAddress}`} onClick={(e) => e.preventDefault()}>
|
||||
@@ -94,51 +75,7 @@ const FeedPost: FC<FeedPostProps> = ({ post, index }) => {
|
||||
</p>
|
||||
<PostTools commentCid={cid} />
|
||||
</div>
|
||||
<div className={expandoVisible ? styles.expando : styles.expandoHidden}>
|
||||
{link && (
|
||||
<div className={styles.mediaPreview}>
|
||||
<Link to={`p/${subplebbitAddress}/c/${cid}`} onClick={(e) => e.preventDefault()}>
|
||||
{commentMediaInfo?.type === 'image' && (
|
||||
<img
|
||||
src={commentMediaInfo.url}
|
||||
alt='thumbnail'
|
||||
onError={(e) => {
|
||||
e.currentTarget.alt = '';
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{commentMediaInfo?.type === 'video' &&
|
||||
(commentMediaInfo.thumbnail ? (
|
||||
<img
|
||||
src={commentMediaInfo.thumbnail}
|
||||
alt='thumbnail'
|
||||
onError={(e) => {
|
||||
e.currentTarget.alt = '';
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<video src={commentMediaInfo.url} controls />
|
||||
))}
|
||||
{commentMediaInfo?.type === 'webpage' && commentMediaInfo.thumbnail && (
|
||||
<img
|
||||
src={commentMediaInfo.thumbnail}
|
||||
alt='thumbnail'
|
||||
onError={(e) => {
|
||||
e.currentTarget.alt = '';
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{commentMediaInfo?.type === 'audio' && <audio src={commentMediaInfo.url} controls />}
|
||||
{commentMediaInfo?.type === 'iframe' && expandoVisible && <Embed url={commentMediaInfo.url} />}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{content && (
|
||||
<div className={styles.usertext}>
|
||||
<div className={styles.markdown}>{content}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Expando commentCid={cid} expanded={expanded} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ const Thumbnail: FC<ThumbnailProps> = ({ commentCid }) => {
|
||||
const comment = useComment({ commentCid });
|
||||
const subplebbitAddress = comment.subplebbitAddress;
|
||||
const { cid, linkHeight, linkWidth } = comment;
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemo(comment);
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemoized(comment);
|
||||
const iframeThumbnail = commentMediaInfo?.patternThumbnailUrl || commentMediaInfo?.thumbnail;
|
||||
|
||||
let displayWidth, displayHeight, hasLinkDimensions;
|
||||
|
||||
@@ -4,6 +4,13 @@ import extName from 'ext-name';
|
||||
import { Comment } from '@plebbit/plebbit-react-hooks';
|
||||
import { canEmbed } from '../components/embed/embed';
|
||||
|
||||
interface CommentMediaInfo {
|
||||
url: string;
|
||||
type: string;
|
||||
thumbnail?: string;
|
||||
patternThumbnailUrl?: string;
|
||||
}
|
||||
|
||||
const getCommentMediaInfo = (comment: Comment) => {
|
||||
if (!comment?.thumbnailUrl && !comment?.link) {
|
||||
return;
|
||||
@@ -58,7 +65,7 @@ const getCommentMediaInfo = (comment: Comment) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getCommentMediaInfoMemo = memoize(getCommentMediaInfo, { max: 1000 });
|
||||
const getCommentMediaInfoMemoized = memoize(getCommentMediaInfo, { max: 1000 });
|
||||
|
||||
const getFormattedTime = (unixTimestamp: number): string => {
|
||||
const currentTime = Date.now() / 1000;
|
||||
@@ -104,10 +111,23 @@ const getHostname = (url: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
const hasThumbnail = (commentMediaInfo: CommentMediaInfo | undefined, link: string | undefined): boolean => {
|
||||
const iframeThumbnail = commentMediaInfo?.patternThumbnailUrl || commentMediaInfo?.thumbnail;
|
||||
return link &&
|
||||
commentMediaInfo &&
|
||||
(commentMediaInfo.type === 'image' ||
|
||||
commentMediaInfo.type === 'video' ||
|
||||
(commentMediaInfo.type === 'webpage' && commentMediaInfo.thumbnail) ||
|
||||
(commentMediaInfo.type === 'iframe' && iframeThumbnail))
|
||||
? true
|
||||
: false;
|
||||
};
|
||||
|
||||
const utils = {
|
||||
getCommentMediaInfoMemo,
|
||||
getCommentMediaInfoMemoized,
|
||||
getFormattedTime,
|
||||
getHostname,
|
||||
hasThumbnail,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
|
||||
Reference in New Issue
Block a user