mirror of
https://github.com/plebbit/seedit.git
synced 2026-02-06 12:01:04 -05:00
feat: add blur for nsfw media or spoilers
This commit is contained in:
@@ -178,6 +178,7 @@
|
||||
.joinButton {
|
||||
order: 3;
|
||||
margin-bottom: 3px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
.expando {
|
||||
display: block;
|
||||
padding: 5px;
|
||||
padding-right: 0;
|
||||
padding-top: 5px;
|
||||
clear: left;
|
||||
position: relative;
|
||||
}
|
||||
@@ -17,19 +16,6 @@
|
||||
.usertext {
|
||||
unicode-bidi: isolate;
|
||||
font-size: small;
|
||||
width: 862px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.usertext {
|
||||
width: calc(100vw - 335px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.usertext {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown {
|
||||
@@ -59,13 +45,16 @@
|
||||
|
||||
.mediaPreview {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.mediaPreview img,
|
||||
.mediaPreview video,
|
||||
.mediaPreview iframe {
|
||||
max-width: calc(100vw - 335px) !important;
|
||||
max-width: calc(100vw - 435px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,3 +125,102 @@
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.blurContent {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(40px);
|
||||
}
|
||||
|
||||
.unblurButton {
|
||||
color: white;
|
||||
position: absolute;
|
||||
font-size: 13px;
|
||||
z-index: 1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
cursor: pointer;
|
||||
border: 1px solid #ffffff;
|
||||
padding: 10px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.alwaysShowNsfwButton {
|
||||
color: white;
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
z-index: 1;
|
||||
top: calc(50% + 45px);
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.alwaysShowNsfwButton:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.alwaysShowNsfwNotice {
|
||||
background: #fafaf8;
|
||||
border: 1px solid #e5e3da;
|
||||
clear: left;
|
||||
margin-top: 5px;
|
||||
padding: 5px 10px;
|
||||
position: relative;
|
||||
unicode-bidi: isolate;
|
||||
font-size: small;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.alwaysShowNsfwNotice p {
|
||||
color: #222222;
|
||||
font-weight: 400;
|
||||
word-wrap: break-word;
|
||||
line-height: 15px;
|
||||
margin: 5px 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.alwaysShowNsfwNotice button {
|
||||
background-color: #4f86b5;
|
||||
color: #ffffff;
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
background-image: none;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
padding: 4px 12px 3px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
border-radius: 3px;
|
||||
margin-left: auto;
|
||||
display: block;
|
||||
border-bottom: 2px solid #4270a2;
|
||||
}
|
||||
|
||||
.alwaysShowNsfwNotice button:hover {
|
||||
background-color: #4980ae;
|
||||
}
|
||||
|
||||
@media (max-width: 770px) {
|
||||
.mediaPreview {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.expando {
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './expando.module.css';
|
||||
import Embed from '../embed';
|
||||
@@ -14,6 +14,7 @@ interface ExpandoProps {
|
||||
expanded: boolean;
|
||||
link?: string;
|
||||
modEditReason?: string;
|
||||
nsfw?: boolean;
|
||||
removed?: boolean;
|
||||
showContent: boolean;
|
||||
spoiler?: boolean;
|
||||
@@ -28,6 +29,7 @@ const Expando = ({
|
||||
expanded,
|
||||
link,
|
||||
modEditReason,
|
||||
nsfw,
|
||||
removed,
|
||||
showContent,
|
||||
spoiler = false,
|
||||
@@ -35,7 +37,14 @@ const Expando = ({
|
||||
}: ExpandoProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [showSpoiler, setShowSpoiler] = useState(false);
|
||||
const [hideContent, setHideContent] = useState(true);
|
||||
const [alwaysShowNsfw, setAlwaysShowNsfw] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!expanded) {
|
||||
setHideContent(true);
|
||||
}
|
||||
}, [expanded]);
|
||||
|
||||
let mediaComponent = null;
|
||||
|
||||
@@ -53,51 +62,55 @@ const Expando = ({
|
||||
|
||||
return (
|
||||
<div className={expanded ? styles.expando : styles.expandoHidden}>
|
||||
<div
|
||||
className={styles.expandoContent}
|
||||
onClick={() => {
|
||||
spoiler && !showSpoiler && setShowSpoiler(true);
|
||||
}}
|
||||
>
|
||||
{spoiler && !showSpoiler && !(deleted || removed) && (
|
||||
<>
|
||||
<div className={styles.hideSpoiler} />
|
||||
<span className={styles.showSpoilerButton}>{t('view_spoiler')}</span>
|
||||
</>
|
||||
)}
|
||||
{link && !removed && commentMediaInfo?.type !== 'webpage' && (
|
||||
<div className={styles.mediaPreview}>
|
||||
<Link
|
||||
to={link}
|
||||
onClick={(e) => {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
toggleExpanded && toggleExpanded();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{mediaComponent}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{content && showContent && (
|
||||
<div className={styles.usertext}>
|
||||
<div className={styles.markdown}>
|
||||
<Markdown content={content} />
|
||||
{modEditReason && (
|
||||
<p>
|
||||
{t('mod_reason')}: {modEditReason}
|
||||
</p>
|
||||
{link && !removed && commentMediaInfo?.type !== 'webpage' && (
|
||||
<div className={styles.mediaPreview} onClick={() => setHideContent(false)}>
|
||||
{(nsfw || spoiler) && hideContent && link && commentMediaInfo?.type !== 'webpage' && !(deleted || removed) && (
|
||||
<>
|
||||
<div className={styles.blurContent} />
|
||||
<span className={styles.unblurButton}>{nsfw && spoiler ? 'CLICK TO SEE NSFW SPOILER' : spoiler ? t('view_spoiler') : nsfw ? 'CLICK TO SEE NSFW' : ''}</span>
|
||||
{nsfw && (
|
||||
<span className={styles.alwaysShowNsfwButton} onClick={() => setAlwaysShowNsfw(!alwaysShowNsfw)}>
|
||||
Always show NSFW media?
|
||||
</span>
|
||||
)}
|
||||
{authorEditReason && !(removed || deleted) && (
|
||||
<p>
|
||||
{t('edit')}: {authorEditReason}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<Link
|
||||
to={link}
|
||||
onClick={(e) => {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
toggleExpanded && toggleExpanded();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{mediaComponent}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{alwaysShowNsfw && (
|
||||
<div className={styles.alwaysShowNsfwNotice}>
|
||||
<p>Ok, we changed your preferences to always show NSFW media.</p>
|
||||
<button onClick={() => setAlwaysShowNsfw(false)}>Undo</button>
|
||||
</div>
|
||||
)}
|
||||
{content && showContent && (
|
||||
<div className={styles.usertext}>
|
||||
<div className={styles.markdown}>
|
||||
<Markdown content={content} />
|
||||
{modEditReason && (
|
||||
<p>
|
||||
{t('mod_reason')}: {modEditReason}
|
||||
</p>
|
||||
)}
|
||||
{authorEditReason && !(removed || deleted) && (
|
||||
<p>
|
||||
{t('edit')}: {authorEditReason}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import styles from './post.module.css';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { Comment, useAuthorAddress, useBlock, useComment, useEditedComment, useSubplebbit, useSubscribe } from '@plebbit/plebbit-react-hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { isAllView, isHomeView, isPostPageView, isProfileHiddenView, isSubplebbitView } from '../../lib/utils/view-utils';
|
||||
import { isAllView, isPostPageView, isProfileHiddenView, isSubplebbitView } from '../../lib/utils/view-utils';
|
||||
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getPostScore, formatScore } from '../../lib/utils/post-utils';
|
||||
import { getHostname } from '../../lib/utils/url-utils';
|
||||
@@ -20,6 +20,7 @@ import useUpvote from '../../hooks/use-upvote';
|
||||
import _ from 'lodash';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import { usePinnedPostsStore } from '../../stores/use-pinned-posts-store';
|
||||
import useWindowWidth from '../../hooks/use-window-width';
|
||||
|
||||
interface PostAuthorProps {
|
||||
authorAddress: string;
|
||||
@@ -122,7 +123,6 @@ const Post = ({ index, post = {} }: PostProps) => {
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInPostPageView = isPostPageView(location.pathname, params);
|
||||
const isInProfileHiddenView = isProfileHiddenView(location.pathname);
|
||||
const isInHomeView = isHomeView(location.pathname);
|
||||
const isInSubplebbitView = isSubplebbitView(location.pathname, params);
|
||||
|
||||
const commentMediaInfo = useCommentMediaInfo(post);
|
||||
@@ -161,9 +161,10 @@ const Post = ({ index, post = {} }: PostProps) => {
|
||||
};
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const windowWidth = useWindowWidth();
|
||||
const pinnedPostsCount = usePinnedPostsStore((state) => state.pinnedPostsCount);
|
||||
let rank = (index ?? 0) + 1;
|
||||
if (!isInHomeView) {
|
||||
if (isInSubplebbitView) {
|
||||
rank = rank - pinnedPostsCount;
|
||||
}
|
||||
|
||||
@@ -233,16 +234,17 @@ const Post = ({ index, post = {} }: PostProps) => {
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
{(!(commentMediaInfo?.type === 'webpage') || (commentMediaInfo?.type === 'webpage' && content?.trim().length > 0)) && (
|
||||
<ExpandButton
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
content={content}
|
||||
expanded={isExpanded}
|
||||
hasThumbnail={hasThumbnail}
|
||||
link={link}
|
||||
toggleExpanded={toggleExpanded}
|
||||
/>
|
||||
)}
|
||||
{(!(commentMediaInfo?.type === 'webpage') || (commentMediaInfo?.type === 'webpage' && content?.trim().length > 0)) &&
|
||||
!(isInPostPageView && !link && content?.trim().length > 0) && (
|
||||
<ExpandButton
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
content={content}
|
||||
expanded={isExpanded}
|
||||
hasThumbnail={hasThumbnail}
|
||||
link={link}
|
||||
toggleExpanded={toggleExpanded}
|
||||
/>
|
||||
)}
|
||||
<div className={styles.tagline}>
|
||||
{t('submitted')} <span title={postDate}>{getFormattedTimeAgo(timestamp)}</span>{' '}
|
||||
{edit && isInPostPageView && <span className={styles.timeEdit}>{t('last_edited', { timestamp: getFormattedTimeAgo(edit.timestamp) })}</span>}{' '}
|
||||
@@ -295,23 +297,49 @@ const Post = ({ index, post = {} }: PostProps) => {
|
||||
subplebbitAddress={subplebbitAddress}
|
||||
/>
|
||||
</div>
|
||||
{!(windowWidth < 770) && (
|
||||
<>
|
||||
{isEditing ? (
|
||||
<CommentEditForm commentCid={cid} hideCommentEditForm={hideCommentEditForm} />
|
||||
) : (
|
||||
<Expando
|
||||
authorEditReason={edit?.reason}
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
content={removed ? `[${_.lowerCase(t('removed'))}]` : deleted ? `[${_.lowerCase(t('deleted'))}]` : content}
|
||||
expanded={isExpanded}
|
||||
link={link}
|
||||
modEditReason={reason}
|
||||
nsfw={nsfw}
|
||||
deleted={deleted}
|
||||
removed={removed}
|
||||
showContent={true}
|
||||
spoiler={spoiler && (content || link)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isEditing ? (
|
||||
<CommentEditForm commentCid={cid} hideCommentEditForm={hideCommentEditForm} />
|
||||
) : (
|
||||
<Expando
|
||||
authorEditReason={edit?.reason}
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
content={removed ? `[${_.lowerCase(t('removed'))}]` : deleted ? `[${_.lowerCase(t('deleted'))}]` : content}
|
||||
expanded={isExpanded}
|
||||
link={link}
|
||||
modEditReason={reason}
|
||||
deleted={deleted}
|
||||
removed={removed}
|
||||
showContent={true}
|
||||
spoiler={spoiler && (content || link)}
|
||||
/>
|
||||
{windowWidth < 770 && (
|
||||
<>
|
||||
{isEditing ? (
|
||||
<CommentEditForm commentCid={cid} hideCommentEditForm={hideCommentEditForm} />
|
||||
) : (
|
||||
<Expando
|
||||
authorEditReason={edit?.reason}
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
content={removed ? `[${_.lowerCase(t('removed'))}]` : deleted ? `[${_.lowerCase(t('deleted'))}]` : content}
|
||||
expanded={isExpanded}
|
||||
link={link}
|
||||
modEditReason={reason}
|
||||
nsfw={nsfw}
|
||||
deleted={deleted}
|
||||
removed={removed}
|
||||
showContent={true}
|
||||
spoiler={spoiler && (content || link)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.morePostsSuggestion {
|
||||
font-size: 11px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.morePostsSuggestion a, .link {
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
|
||||
Reference in New Issue
Block a user