updated preview component

This commit is contained in:
Ren Amamiya 2023-02-21 15:31:38 +07:00
parent 672298daf9
commit fe2fef0f85
7 changed files with 59 additions and 71 deletions

View File

@ -42,11 +42,11 @@ export const User = memo(function User({ pubkey, time }: { pubkey: string; time:
</div>
<div className="flex w-full flex-1 items-start justify-between">
<div className="flex w-full justify-between">
<div className="flex items-center gap-2 text-sm">
<div className="flex items-baseline gap-2 text-sm">
<span className="font-bold leading-tight">
{userData?.name ? userData.name : truncate(pubkey, 16, ' .... ')}
</span>
<span className="text-zinc-500">·</span>
<span className="leading-tight text-zinc-500">·</span>
<Moment fromNow unix className="text-zinc-500">
{time}
</Moment>

View File

@ -1,20 +0,0 @@
import Image from 'next/image';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export default function ImagePreview({ data }: { data: object }) {
return (
<div
className={`relative mt-2 flex flex-col overflow-hidden rounded-xl border border-zinc-800`}>
<div className="relative h-full w-full">
<Image
src={data['image']}
alt="image preview"
width="0"
height="0"
sizes="100vw"
className="h-auto w-full object-cover"
/>
</div>
</div>
);
}

View File

@ -1,16 +1,20 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import ImageCard from '@components/note/content/preview/imageCard';
import Video from '@components/note/content/preview/video';
import { MarkdownPreviewProps } from '@uiw/react-markdown-preview';
import dynamic from 'next/dynamic';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import ReactPlayer from 'react-player';
const MarkdownPreview = dynamic<MarkdownPreviewProps>(() => import('@uiw/react-markdown-preview'), {
ssr: false,
});
export default function Content({ data }: { data: string }) {
const imagesRef = useRef([]);
const videosRef = useRef([]);
const [preview, setPreview] = useState({});
const content = useRef(data);
const urls = useMemo(
() =>
data.match(
@ -19,52 +23,56 @@ export default function Content({ data }: { data: string }) {
[data]
);
const extractURL = useCallback((urls: any[]) => {
if (urls !== null && urls.length > 0) {
urls.forEach((url: string | URL) => {
const parseURL = new URL(url);
const path = parseURL.pathname.toLowerCase();
switch (path) {
case path.match(/\.(jpg|jpeg|gif|png|webp)$/)?.input:
imagesRef.current.push(parseURL.href);
break;
case path.match(
/(http:|https:)?\/\/(www\.)?(youtube.com|youtu.be)\/(watch)?(\?v=)?(\S+)?/
)?.input:
videosRef.current.push(parseURL.href);
break;
case path.match(/\.(mp4|webm|m4v|mov|avi|mkv|flv)$/)?.input:
videosRef.current.push(parseURL.href);
break;
default:
break;
}
});
}
}, []);
useEffect(() => {
extractURL(urls);
}, [extractURL, urls]);
if (urls !== null && urls.length > 0) {
const parseURL = new URL(urls[0]);
if (parseURL.pathname.toLowerCase().match(/\.(jpg|jpeg|gif|png|webp)$/)) {
// add image to preview
setPreview({ image: parseURL.href, type: 'image' });
content.current = content.current.replace(parseURL.href, '');
} else if (ReactPlayer.canPlay(parseURL.href)) {
// add video to preview
setPreview({ url: parseURL.href, type: 'video' });
content.current = content.current.replace(parseURL.href, '');
} // #TODO: support multiple preview
}
}, [urls]);
const previewAttachment = useCallback(() => {
if (Object.keys(preview).length > 0) {
switch (preview['type']) {
case 'image':
return <ImageCard data={preview} />;
case 'video':
return <Video data={preview} />;
default:
return null;
}
}
}, [preview]);
return (
<div className="flex flex-col">
<MarkdownPreview
source={data}
className={
'prose prose-zinc max-w-none break-words dark:prose-invert prose-headings:mt-3 prose-headings:mb-2 prose-p:m-0 prose-p:leading-normal prose-ul:mt-2 prose-li:my-1'
}
linkTarget="_blank"
disallowedElements={[
'Table',
'Heading ID',
'Highlight',
'Fenced Code Block',
'Footnote',
'Definition List',
'Task List',
]}
/>
<div>
<MarkdownPreview
source={content.current}
className={
'prose prose-zinc max-w-none break-words dark:prose-invert prose-headings:mt-3 prose-headings:mb-2 prose-p:m-0 prose-p:leading-normal prose-ul:mt-2 prose-li:my-1'
}
linkTarget="_blank"
disallowedElements={[
'Table',
'Heading ID',
'Highlight',
'Fenced Code Block',
'Footnote',
'Definition List',
'Task List',
]}
/>
</div>
<div>{previewAttachment()}</div>
</div>
);
}

View File

@ -8,7 +8,7 @@ export default function ImageCard({ data }: { data: object }) {
<div className="relative h-full w-full">
<Image
src={data['image']}
alt="image preview"
alt={data['image']}
width="0"
height="0"
sizes="100vw"

View File

@ -1,7 +1,7 @@
import Reaction from '@components/note/atoms/reaction';
import Reply from '@components/note/atoms/reply';
import RootUser from '@components/note/atoms/rootUser';
import User from '@components/note/atoms/user';
import { User } from '@components/note/atoms/user';
import { Placeholder } from '@components/note/placeholder';
import LikeSolidIcon from '@assets/icons/LikeSolid';

View File

@ -1,6 +1,6 @@
import Reaction from '@components/note/atoms/reaction';
import Reply from '@components/note/atoms/reply';
import User from '@components/note/atoms/user';
import { User } from '@components/note/atoms/user';
import { Placeholder } from '@components/note/placeholder';
import dynamic from 'next/dynamic';

View File

@ -1,7 +1,7 @@
import Reaction from '@components/note/atoms/reaction';
import Reply from '@components/note/atoms/reply';
import RootUser from '@components/note/atoms/rootUser';
import User from '@components/note/atoms/user';
import { User } from '@components/note/atoms/user';
import { Placeholder } from '@components/note/placeholder';
import RepostIcon from '@assets/icons/Repost';