From d4e92fcbe0cd8137a16f08fdf10b8630cd0dde7c Mon Sep 17 00:00:00 2001 From: "plebeius.eth" Date: Tue, 6 Feb 2024 10:54:07 +0100 Subject: [PATCH 01/11] missing spaces in strings --- src/views/settings/general-settings/general-settings.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/views/settings/general-settings/general-settings.tsx b/src/views/settings/general-settings/general-settings.tsx index b7a40e66..5261cbe8 100644 --- a/src/views/settings/general-settings/general-settings.tsx +++ b/src/views/settings/general-settings/general-settings.tsx @@ -34,7 +34,8 @@ const CheckForUpdates = () => { const latestCommitHash = commitData[0].sha; if (latestCommitHash.trim() !== commitRef.trim()) { - const newVersionText = t('new_development_version', { newCommit: latestCommitHash.slice(0, 7), oldCommit: commitRef.slice(0, 7) }) + t('refresh_to_update'); + const newVersionText = + t('new_development_version', { newCommit: latestCommitHash.slice(0, 7), oldCommit: commitRef.slice(0, 7) }) + ' ' + t('refresh_to_update'); alert(newVersionText); updateAvailable = true; } @@ -48,7 +49,7 @@ const CheckForUpdates = () => { ); } } catch (error) { - alert('Failed to fetch latest version info:' + error); + alert('Failed to fetch latest version info: ' + error); } finally { setLoading(false); } From da6e474a6ef0bde4a6c909a6743f20c29932cf76 Mon Sep 17 00:00:00 2001 From: "plebeius.eth" Date: Tue, 6 Feb 2024 13:30:52 +0100 Subject: [PATCH 02/11] feat(post): add small profile nft avatar next to username --- src/components/post/post.module.css | 16 ++++++++++++++++ src/components/post/post.tsx | 12 ++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/components/post/post.module.css b/src/components/post/post.module.css index f7f03e89..8ba373fe 100644 --- a/src/components/post/post.module.css +++ b/src/components/post/post.module.css @@ -108,6 +108,9 @@ color: var(--text-info); font-size: x-small; white-space: nowrap; + vertical-align: middle; + display: inline-block; + padding-bottom: 2px; } .domain a { @@ -209,3 +212,16 @@ font-size: 10px; cursor: pointer; } + +.authorAvatar { + width: 18px; + display: inline-block; + position: relative; +} + +.authorAvatar img { + width: 18px; + max-height: 18px; + position: absolute; + bottom: -5px; +} \ No newline at end of file diff --git a/src/components/post/post.tsx b/src/components/post/post.tsx index 914b71ec..e7b7cbf0 100644 --- a/src/components/post/post.tsx +++ b/src/components/post/post.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import styles from './post.module.css'; import { Link, useLocation, useParams } from 'react-router-dom'; -import { Comment, useAuthorAddress, useBlock, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import { Comment, useAuthorAddress, useAuthorAvatar, useBlock, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { useTranslation } from 'react-i18next'; import { isPendingView, isPostView, isSubplebbitView } from '../../lib/utils/view-utils'; import { getCommentMediaInfoMemoized, getHasThumbnail } from '../../lib/utils/media-utils'; @@ -22,13 +22,14 @@ interface PostAuthorProps { authorRole: string; cid: string; displayName: string; + imageUrl: string | undefined; index?: number; shortAddress: string; shortAuthorAddress: string | undefined; authorAddressChanged: boolean; } -const PostAuthor = ({ authorAddress, authorRole, cid, displayName, index, shortAddress, shortAuthorAddress, authorAddressChanged }: PostAuthorProps) => { +const PostAuthor = ({ authorAddress, authorRole, cid, displayName, imageUrl, index, shortAddress, shortAuthorAddress, authorAddressChanged }: PostAuthorProps) => { const isAuthorOwner = authorRole === 'owner'; const isAuthorAdmin = authorRole === 'admin'; const isAuthorModerator = authorRole === 'moderator'; @@ -38,6 +39,11 @@ const PostAuthor = ({ authorAddress, authorRole, cid, displayName, index, shortA return ( <> + {imageUrl && ( + + + + )} {displayName && {displayName} } u/{shortAddress || shortAuthorAddress} @@ -96,6 +102,7 @@ const Post = ({ post = {}, index }: PostProps) => { } = post || {}; const { displayName, shortAddress } = author || {}; const { shortAuthorAddress, authorAddressChanged } = useAuthorAddress({ comment: post }); + const { imageUrl } = useAuthorAvatar({ author }); const { t } = useTranslation(); const params = useParams(); @@ -203,6 +210,7 @@ const Post = ({ post = {}, index }: PostProps) => { authorRole={authorRole} cid={cid} displayName={displayName} + imageUrl={imageUrl} index={post?.index} shortAddress={shortAddress} shortAuthorAddress={shortAuthorAddress} From 05c1e4bd57f40d7c763a79b7e886221e09e34f88 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" <117766773+plebeius-eth@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:20:39 +0100 Subject: [PATCH 03/11] Update post.tsx --- src/components/post/post.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/post/post.tsx b/src/components/post/post.tsx index e7b7cbf0..ad7154e0 100644 --- a/src/components/post/post.tsx +++ b/src/components/post/post.tsx @@ -41,7 +41,7 @@ const PostAuthor = ({ authorAddress, authorRole, cid, displayName, imageUrl, ind {imageUrl && ( - + avatar )} {displayName && {displayName} } From 2d6e7ddb381e31befcf546cd542fa0db2761cfa1 Mon Sep 17 00:00:00 2001 From: "plebeius.eth" Date: Tue, 6 Feb 2024 15:42:25 +0100 Subject: [PATCH 04/11] feat(submit): add media preview to url field --- src/components/post/embed/embed.module.css | 2 +- src/lib/utils/media-utils.ts | 40 ++++++++++ src/views/submit/submit.module.css | 70 ++++++++++------- src/views/submit/submit.tsx | 88 +++++++++++++++++----- 4 files changed, 154 insertions(+), 46 deletions(-) diff --git a/src/components/post/embed/embed.module.css b/src/components/post/embed/embed.module.css index c590a17c..a7d6fc65 100644 --- a/src/components/post/embed/embed.module.css +++ b/src/components/post/embed/embed.module.css @@ -54,7 +54,7 @@ @media (max-width: 768px) { .videoEmbed { max-height: 250px !important; - width: 100% !important; + width: 100%; } } diff --git a/src/lib/utils/media-utils.ts b/src/lib/utils/media-utils.ts index 7d8e0159..0fe51e94 100644 --- a/src/lib/utils/media-utils.ts +++ b/src/lib/utils/media-utils.ts @@ -77,3 +77,43 @@ const getCommentMediaInfo = (comment: Comment) => { }; export const getCommentMediaInfoMemoized = memoize(getCommentMediaInfo, { max: 1000 }); + +export const getLinkMediaInfo = (link: string) => { + let mime: string | undefined; + try { + mime = extName(new URL(link).pathname.toLowerCase().replace('/', ''))[0]?.mime; + } catch (e) { + return; + } + + const url = new URL(link); + const host = url.hostname; + let patternThumbnailUrl; + + if (['youtube.com', 'www.youtube.com', 'youtu.be', 'www.youtu.be', 'm.youtube.com'].includes(host)) { + const videoId = host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v'); + patternThumbnailUrl = `https://img.youtube.com/vi/${videoId}/0.jpg`; + } else if (host.includes('streamable.com')) { + const videoId = url.pathname.split('/')[1]; + patternThumbnailUrl = `https://cdn-cf-east.streamable.com/image/${videoId}.jpg`; + } + + if (canEmbed(url)) { + return { + url: link, + type: 'iframe', + patternThumbnailUrl, + }; + } + + if (mime?.startsWith('image')) { + return { url: link, type: 'image' }; + } + if (mime?.startsWith('video')) { + return { url: link, type: 'video' }; + } + if (mime?.startsWith('audio')) { + return { url: link, type: 'audio' }; + } + return { url: link, type: 'webpage' }; +}; diff --git a/src/views/submit/submit.module.css b/src/views/submit/submit.module.css index 0b16fa43..02bf1766 100644 --- a/src/views/submit/submit.module.css +++ b/src/views/submit/submit.module.css @@ -98,32 +98,6 @@ h1 { padding: 2px 6px 3px; } -@media (max-width: 768px) { - .formContent { - width: 100%; - } - - .box { - width: 100%; - box-sizing: border-box; - } - - .input, - .description { - width: calc(100% - 6px); - box-sizing: border-box; - } - - .input { - min-width: calc(100% - 6px); - max-width: calc(100% - 6px); - } - - h1 { - font-size: 16px; - } -} - .subsDescription { font-size: 13px; font-weight: normal; @@ -181,4 +155,48 @@ h1 { .dropdownLink:hover { color: var(--background); +} + +.mediaPreview { + display: inline-block; + position: relative; + align-items: center; + margin-top: 10px; + font-size: smaller; + text-transform: capitalize; +} + +.logoError { + padding-left: 10px; +} + +.mediaPreview img, .mediaPreview iframe, .mediaPreview video { + max-width: 100%; + max-height: 300px; + box-sizing: border-box; +} + +@media (max-width: 768px) { + .formContent { + width: 100%; + } + + .box { + width: 100%; + box-sizing: border-box; + } + + .input, + .description { + width: calc(100% - 6px); + box-sizing: border-box; + } + + .input { + min-width: 100%; + } + + h1 { + font-size: 16px; + } } \ No newline at end of file diff --git a/src/views/submit/submit.tsx b/src/views/submit/submit.tsx index 78a56637..16a43b38 100644 --- a/src/views/submit/submit.tsx +++ b/src/views/submit/submit.tsx @@ -1,15 +1,17 @@ -import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react'; +import { ChangeEvent, forwardRef, useCallback, useEffect, useRef, useState } from 'react'; import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'; import { PublishCommentOptions, useAccount, usePublishComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { getShortAddress } from '@plebbit/plebbit-js'; import { Trans, useTranslation } from 'react-i18next'; import { create } from 'zustand'; +import { getRandomSubplebbits, useDefaultSubplebbitAddresses } from '../../lib/utils/addresses-utils'; import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils'; +import { getLinkMediaInfo } from '../../lib/utils/media-utils'; import { isValidURL } from '../../lib/utils/url-utils'; +import { isSubmitView } from '../../lib/utils/view-utils'; import styles from './submit.module.css'; import challengesStore from '../../hooks/use-challenges'; -import { getRandomSubplebbits, useDefaultSubplebbitAddresses } from '../../lib/utils/addresses-utils'; -import { isSubmitView } from '../../lib/utils/view-utils'; +import Embed from '../../components/post/embed/'; type SubmitState = { subplebbitAddress: string | undefined; @@ -52,6 +54,69 @@ const useSubmitStore = create((set) => ({ resetSubmitStore: () => set({ subplebbitAddress: undefined, title: undefined, content: undefined, link: undefined, publishCommentOptions: undefined }), })); +const UrlField = forwardRef((_, ref) => { + const { t } = useTranslation(); + const { setSubmitStore } = useSubmitStore(); + const [mediaError, setMediaError] = useState(false); + const [url, setUrl] = useState(''); + const [mediaType, setMediaType] = useState(''); + + useEffect(() => { + const mediaInfo = getLinkMediaInfo(url); + if (mediaInfo?.type) { + setMediaType(mediaInfo.type); + } + }, [url]); + + let mediaComponent; + + if (mediaType === 'image') { + mediaComponent = setMediaError(true)} />; + } else if (mediaType === 'video') { + mediaComponent =