restructure note component
This commit is contained in:
@@ -2,7 +2,7 @@ import MessageHideButton from '@lume/app/channel/components/messages/hideButton'
|
|||||||
import MessageMuteButton from '@lume/app/channel/components/messages/muteButton';
|
import MessageMuteButton from '@lume/app/channel/components/messages/muteButton';
|
||||||
import MessageReplyButton from '@lume/app/channel/components/messages/replyButton';
|
import MessageReplyButton from '@lume/app/channel/components/messages/replyButton';
|
||||||
import ChannelMessageUser from '@lume/app/channel/components/messages/user';
|
import ChannelMessageUser from '@lume/app/channel/components/messages/user';
|
||||||
import { noteParser } from '@lume/app/note/components/parser';
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import ChatMessageUser from '@lume/app/chat/components/messages/user';
|
import ChatMessageUser from '@lume/app/chat/components/messages/user';
|
||||||
import { noteParser } from '@lume/app/note/components/parser';
|
|
||||||
import ImagePreview from '@lume/app/note/components/preview/image';
|
import ImagePreview from '@lume/app/note/components/preview/image';
|
||||||
import VideoPreview from '@lume/app/note/components/preview/video';
|
import VideoPreview from '@lume/app/note/components/preview/video';
|
||||||
import { useDecryptMessage } from '@lume/utils/hooks/useDecryptMessage';
|
import { useDecryptMessage } from '@lume/utils/hooks/useDecryptMessage';
|
||||||
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import LumeIcon from '@lume/shared/icons/lume';
|
|
||||||
import { getActiveAccount } from '@lume/utils/storage';
|
import { getActiveAccount } from '@lume/utils/storage';
|
||||||
|
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
@@ -21,41 +20,5 @@ export function Page() {
|
|||||||
navigate('/app/inital-data', { overwriteLastHistoryEntry: true });
|
navigate('/app/inital-data', { overwriteLastHistoryEntry: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-black dark:text-white"></div>;
|
||||||
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-black dark:text-white">
|
|
||||||
<div className="relative h-full overflow-hidden">
|
|
||||||
{/* dragging area */}
|
|
||||||
<div data-tauri-drag-region className="absolute left-0 top-0 z-20 h-16 w-full bg-transparent" />
|
|
||||||
{/* end dragging area */}
|
|
||||||
<div className="relative flex h-full flex-col items-center justify-center">
|
|
||||||
<div className="flex flex-col items-center gap-2">
|
|
||||||
<LumeIcon className="h-16 w-16 text-black dark:text-white" />
|
|
||||||
<div className="text-center">
|
|
||||||
<h3 className="text-lg font-semibold leading-tight text-zinc-900 dark:text-zinc-100">
|
|
||||||
Here's an interesting fact:
|
|
||||||
</h3>
|
|
||||||
<p className="font-medium text-zinc-300 dark:text-zinc-600">
|
|
||||||
Bitcoin and Nostr can be used by anyone, and no one can stop you!
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="absolute bottom-16 left-1/2 -translate-x-1/2 transform">
|
|
||||||
<svg
|
|
||||||
className="h-5 w-5 animate-spin text-black dark:text-white"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
|
||||||
<path
|
|
||||||
className="opacity-75"
|
|
||||||
fill="currentColor"
|
|
||||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { ContentMarkdown } from '@lume/app/note/components/markdown';
|
import { NoteContent } from '@lume/app/note/components/content';
|
||||||
import NoteMetadata from '@lume/app/note/components/metadata';
|
import NoteMetadata from '@lume/app/note/components/metadata';
|
||||||
import { NoteParent } from '@lume/app/note/components/parent';
|
import { NoteParent } from '@lume/app/note/components/parent';
|
||||||
import { noteParser } from '@lume/app/note/components/parser';
|
|
||||||
import ImagePreview from '@lume/app/note/components/preview/image';
|
|
||||||
import VideoPreview from '@lume/app/note/components/preview/video';
|
|
||||||
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
||||||
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
import { navigate } from 'vite-plugin-ssr/client/router';
|
import { navigate } from 'vite-plugin-ssr/client/router';
|
||||||
|
|
||||||
@@ -25,19 +23,13 @@ export default function NoteBase({ event }: { event: any }) {
|
|||||||
onClick={(e) => openNote(e)}
|
onClick={(e) => openNote(e)}
|
||||||
className="relative z-10 flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 px-3 py-5 hover:bg-black/20"
|
className="relative z-10 flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 px-3 py-5 hover:bg-black/20"
|
||||||
>
|
>
|
||||||
{event.parent_id && event.parent_id !== event.event_id ? (
|
{event.parent_id && event.parent_id !== event.event_id && (
|
||||||
<NoteParent key={event.parent_id} id={event.parent_id} />
|
<NoteParent key={event.parent_id} id={event.parent_id} />
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
)}
|
||||||
<div className="relative z-10 flex flex-col">
|
<div className="relative z-10 flex flex-col">
|
||||||
<NoteDefaultUser pubkey={event.pubkey} time={event.created_at} />
|
<NoteDefaultUser pubkey={event.pubkey} time={event.created_at} />
|
||||||
<div className="mt-1 pl-[52px]">
|
<div className="mt-1 pl-[52px]">
|
||||||
<ContentMarkdown content={content.parsed} />
|
<NoteContent content={content} />
|
||||||
{Array.isArray(content.images) && content.images.length ? <ImagePreview urls={content.images} /> : <></>}
|
|
||||||
{Array.isArray(content.videos) && content.videos.length ? <VideoPreview urls={content.videos} /> : <></>}
|
|
||||||
</div>
|
|
||||||
<div onClick={(e) => e.stopPropagation()} className="mt-5 pl-[52px]">
|
|
||||||
<NoteMetadata id={event.event_id} eventPubkey={event.pubkey} />
|
<NoteMetadata id={event.event_id} eventPubkey={event.pubkey} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
|
||||||
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
export const NoteComment = memo(function NoteComment({ event }: { event: any }) {
|
|
||||||
return (
|
|
||||||
<div className="relative z-10 flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 px-3 py-5 hover:bg-black/20">
|
|
||||||
<div className="relative z-10 flex flex-col">
|
|
||||||
<NoteDefaultUser pubkey={event.pubkey} time={event.created_at} />
|
|
||||||
<div className="-mt-5 pl-[52px]">
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<div className="prose prose-zinc max-w-none break-words text-[15px] leading-tight dark:prose-invert prose-p:m-0 prose-p:text-[15px] prose-p:leading-tight prose-a:font-normal prose-a:text-fuchsia-500 prose-a:no-underline prose-img:m-0 prose-video:m-0">
|
|
||||||
{event.content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div onClick={(e) => e.stopPropagation()} className="mt-5 pl-[52px]"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
28
src/app/note/components/content.tsx
Normal file
28
src/app/note/components/content.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import ImagePreview from '@lume/app/note/components/preview/image';
|
||||||
|
import VideoPreview from '@lume/app/note/components/preview/video';
|
||||||
|
import { NoteQuote } from '@lume/app/note/components/quote';
|
||||||
|
import { NoteMentionUser } from '@lume/app/note/components/user/mention';
|
||||||
|
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
|
|
||||||
|
export const NoteContent = ({ content }: { content: any }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ReactMarkdown
|
||||||
|
remarkPlugins={[[remarkGfm]]}
|
||||||
|
linkTarget="_blank"
|
||||||
|
className="prose prose-zinc max-w-none break-words dark:prose-invert prose-p:text-[15px] prose-p:leading-tight prose-a:text-[15px] prose-a:leading-tight prose-a:text-fuchsia-500 prose-a:no-underline prose-a:hover:text-fuchsia-600 prose-a:hover:underline prose-ol:mb-1 prose-ul:mb-1 prose-li:text-[15px] prose-li:leading-tight"
|
||||||
|
components={{
|
||||||
|
h5: ({ ...props }) => <NoteMentionUser pubkey={props.content} />,
|
||||||
|
h6: ({ ...props }) => <NoteQuote id={props.content} />,
|
||||||
|
em: ({ ...props }) => <span className="text-fuchsia-500 hover:text-fuchsia-600" {...props} />,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{content.parsed}
|
||||||
|
</ReactMarkdown>
|
||||||
|
{Array.isArray(content.images) && content.images.length ? <ImagePreview urls={content.images} /> : <></>}
|
||||||
|
{Array.isArray(content.videos) && content.videos.length ? <VideoPreview urls={content.videos} /> : <></>}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { NoteQuote } from '@lume/app/note/components/quote';
|
|
||||||
import { NoteMentionUser } from '@lume/app/note/components/user/mention';
|
|
||||||
|
|
||||||
import ReactMarkdown from 'react-markdown';
|
|
||||||
import remarkGfm from 'remark-gfm';
|
|
||||||
|
|
||||||
export const ContentMarkdown = ({ content }: { content: any }) => {
|
|
||||||
return (
|
|
||||||
<ReactMarkdown
|
|
||||||
remarkPlugins={[[remarkGfm]]}
|
|
||||||
linkTarget="_blank"
|
|
||||||
className="prose prose-zinc max-w-none break-words dark:prose-invert prose-p:text-[15px] prose-p:leading-tight prose-a:text-[15px] prose-a:leading-tight prose-a:text-fuchsia-500 prose-a:no-underline prose-a:hover:text-fuchsia-600 prose-a:hover:underline prose-ol:mb-1 prose-ul:mb-1 prose-li:text-[15px] prose-li:leading-tight"
|
|
||||||
components={{
|
|
||||||
h5: ({ ...props }) => <NoteMentionUser pubkey={props.content} />,
|
|
||||||
h6: ({ ...props }) => <NoteQuote id={props.content} />,
|
|
||||||
em: ({ ...props }) => <span className="text-fuchsia-500 hover:text-fuchsia-600" {...props} />,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{content}
|
|
||||||
</ReactMarkdown>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -51,7 +51,7 @@ export default function NoteMetadata({ id, eventPubkey }: { id: string; eventPub
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-16">
|
<div className="mt-5 flex items-center gap-16">
|
||||||
<NoteReply id={id} replies={replies} />
|
<NoteReply id={id} replies={replies} />
|
||||||
<NoteLike id={id} pubkey={eventPubkey} likes={likes} />
|
<NoteLike id={id} pubkey={eventPubkey} likes={likes} />
|
||||||
<NoteRepost id={id} pubkey={eventPubkey} reposts={reposts} />
|
<NoteRepost id={id} pubkey={eventPubkey} reposts={reposts} />
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { ContentMarkdown } from '@lume/app/note/components/markdown';
|
import { NoteContent } from '@lume/app/note/components/content';
|
||||||
import NoteMetadata from '@lume/app/note/components/metadata';
|
import NoteMetadata from '@lume/app/note/components/metadata';
|
||||||
import { noteParser } from '@lume/app/note/components/parser';
|
|
||||||
import ImagePreview from '@lume/app/note/components/preview/image';
|
|
||||||
import VideoPreview from '@lume/app/note/components/preview/video';
|
|
||||||
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
||||||
import { RelayContext } from '@lume/shared/relayProvider';
|
import { RelayContext } from '@lume/shared/relayProvider';
|
||||||
import { READONLY_RELAYS } from '@lume/stores/constants';
|
import { READONLY_RELAYS } from '@lume/stores/constants';
|
||||||
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
import { memo, useContext } from 'react';
|
import { memo, useContext } from 'react';
|
||||||
import useSWRSubscription from 'swr/subscription';
|
import useSWRSubscription from 'swr/subscription';
|
||||||
@@ -72,12 +70,7 @@ export const NoteParent = memo(function NoteParent({ id }: { id: string }) {
|
|||||||
<div className="relative z-10 flex flex-col">
|
<div className="relative z-10 flex flex-col">
|
||||||
<NoteDefaultUser pubkey={data.pubkey} time={data.created_at} />
|
<NoteDefaultUser pubkey={data.pubkey} time={data.created_at} />
|
||||||
<div className="mt-1 pl-[52px]">
|
<div className="mt-1 pl-[52px]">
|
||||||
<div className="whitespace-pre-line break-words text-[15px] leading-tight text-zinc-100"></div>
|
<NoteContent content={content} />
|
||||||
<ContentMarkdown content={content.parsed} />
|
|
||||||
{Array.isArray(content.images) && content.images.length ? <ImagePreview urls={content.images} /> : <></>}
|
|
||||||
{Array.isArray(content.videos) && content.videos.length ? <VideoPreview urls={content.videos} /> : <></>}
|
|
||||||
</div>
|
|
||||||
<div onClick={(e) => e.stopPropagation()} className="mt-5 pl-[52px]">
|
|
||||||
<NoteMetadata id={data.id} eventPubkey={data.pubkey} />
|
<NoteMetadata id={data.id} eventPubkey={data.pubkey} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,28 +2,15 @@ import { Image } from '@lume/shared/image';
|
|||||||
|
|
||||||
export default function ImagePreview({ urls }: { urls: string[] }) {
|
export default function ImagePreview({ urls }: { urls: string[] }) {
|
||||||
return (
|
return (
|
||||||
<div className="mt-2 grid h-full w-full grid-cols-2">
|
<div className="mt-3 grid h-full w-full grid-cols-3">
|
||||||
{urls.length === 1 ? (
|
<div className="col-span-2">
|
||||||
<div className="col-span-2">
|
<Image
|
||||||
<Image
|
src={urls[0]}
|
||||||
src={urls[0]}
|
alt="image"
|
||||||
alt="image"
|
className="h-auto w-full rounded-lg object-cover"
|
||||||
className="h-auto w-full rounded-lg object-cover"
|
style={{ contentVisibility: 'auto' }}
|
||||||
style={{ contentVisibility: 'auto' }}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
urls.map((url: string) => (
|
|
||||||
<div key={url} className="col-span-1">
|
|
||||||
<Image
|
|
||||||
src={url}
|
|
||||||
alt="image"
|
|
||||||
className="h-auto w-full rounded-lg object-cover"
|
|
||||||
style={{ contentVisibility: 'auto' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export default function VideoPreview({ urls }: { urls: string[] }) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
className="relative mt-2 flex w-full flex-col overflow-hidden rounded-lg bg-zinc-950"
|
className="relative mt-3 flex w-full flex-col overflow-hidden rounded-lg bg-zinc-950"
|
||||||
>
|
>
|
||||||
<MediaPlayer src={urls[0]} poster="" controls>
|
<MediaPlayer src={urls[0]} poster="" controls>
|
||||||
<MediaOutlet />
|
<MediaOutlet />
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { ContentMarkdown } from '@lume/app/note/components/markdown';
|
import { NoteContent } from '@lume/app/note/components/content';
|
||||||
import { noteParser } from '@lume/app/note/components/parser';
|
|
||||||
import ImagePreview from '@lume/app/note/components/preview/image';
|
|
||||||
import VideoPreview from '@lume/app/note/components/preview/video';
|
|
||||||
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
||||||
import { RelayContext } from '@lume/shared/relayProvider';
|
import { RelayContext } from '@lume/shared/relayProvider';
|
||||||
import { READONLY_RELAYS } from '@lume/stores/constants';
|
import { READONLY_RELAYS } from '@lume/stores/constants';
|
||||||
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
import { memo, useContext } from 'react';
|
import { memo, useContext } from 'react';
|
||||||
import useSWRSubscription from 'swr/subscription';
|
import useSWRSubscription from 'swr/subscription';
|
||||||
@@ -36,6 +34,8 @@ export const NoteQuote = memo(function NoteQuote({ id }: { id: string }) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const content = !error && data ? noteParser(data) : null;
|
||||||
|
|
||||||
const openNote = (e) => {
|
const openNote = (e) => {
|
||||||
const selection = window.getSelection();
|
const selection = window.getSelection();
|
||||||
if (selection.toString().length === 0) {
|
if (selection.toString().length === 0) {
|
||||||
@@ -45,8 +45,6 @@ export const NoteQuote = memo(function NoteQuote({ id }: { id: string }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const content = !error && data ? noteParser(data) : null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={(e) => openNote(e)}
|
onClick={(e) => openNote(e)}
|
||||||
@@ -59,9 +57,7 @@ export const NoteQuote = memo(function NoteQuote({ id }: { id: string }) {
|
|||||||
<div className="relative z-10 flex flex-col">
|
<div className="relative z-10 flex flex-col">
|
||||||
<NoteDefaultUser pubkey={data.pubkey} time={data.created_at} />
|
<NoteDefaultUser pubkey={data.pubkey} time={data.created_at} />
|
||||||
<div className="mt-1 pl-[52px]">
|
<div className="mt-1 pl-[52px]">
|
||||||
<ContentMarkdown content={content.parsed} />
|
<NoteContent content={content} />
|
||||||
{Array.isArray(content.images) && content.images.length ? <ImagePreview urls={content.images} /> : <></>}
|
|
||||||
{Array.isArray(content.videos) && content.videos.length ? <VideoPreview urls={content.videos} /> : <></>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
18
src/app/note/components/replies/item.tsx
Normal file
18
src/app/note/components/replies/item.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { NoteContent } from '@lume/app/note/components/content';
|
||||||
|
import NoteReplyUser from '@lume/app/note/components/user/reply';
|
||||||
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
|
export default function Reply({ data }: { data: any }) {
|
||||||
|
const content = noteParser(data);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-min min-h-min w-full select-text flex-col px-5 py-3.5 hover:bg-black/20">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<NoteReplyUser pubkey={data.pubkey} time={data.created_at} />
|
||||||
|
<div className="-mt-[17px] pl-[48px]">
|
||||||
|
<NoteContent content={content} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import NoteReplyForm from '@lume/app/note/components/formReply';
|
import NoteReplyForm from '@lume/app/note/components/replies/form';
|
||||||
import NoteReply from '@lume/app/note/components/reply';
|
import Reply from '@lume/app/note/components/replies/item';
|
||||||
import { RelayContext } from '@lume/shared/relayProvider';
|
import { RelayContext } from '@lume/shared/relayProvider';
|
||||||
import { READONLY_RELAYS } from '@lume/stores/constants';
|
import { READONLY_RELAYS } from '@lume/stores/constants';
|
||||||
import { sortEvents } from '@lume/utils/transform';
|
import { sortEvents } from '@lume/utils/transform';
|
||||||
@@ -7,7 +7,7 @@ import { sortEvents } from '@lume/utils/transform';
|
|||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import useSWRSubscription from 'swr/subscription';
|
import useSWRSubscription from 'swr/subscription';
|
||||||
|
|
||||||
export default function NoteReplies({ id }: { id: string }) {
|
export default function RepliesList({ id }: { id: string }) {
|
||||||
const pool: any = useContext(RelayContext);
|
const pool: any = useContext(RelayContext);
|
||||||
|
|
||||||
const { data, error } = useSWRSubscription(id ? ['note-replies', id] : null, ([, key], { next }) => {
|
const { data, error } = useSWRSubscription(id ? ['note-replies', id] : null, ([, key], { next }) => {
|
||||||
@@ -53,7 +53,7 @@ export default function NoteReplies({ id }: { id: string }) {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
sortEvents(data).map((event: any) => {
|
sortEvents(data).map((event: any) => {
|
||||||
return <NoteReply key={event.id} data={event} />;
|
return <Reply key={event.id} data={event} />;
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { noteParser } from '@lume/app/note/components//parser';
|
|
||||||
import { ContentMarkdown } from '@lume/app/note/components/markdown';
|
|
||||||
import ImagePreview from '@lume/app/note/components/preview/image';
|
|
||||||
import VideoPreview from '@lume/app/note/components/preview/video';
|
|
||||||
import NoteReplyUser from '@lume/app/note/components/user/reply';
|
|
||||||
|
|
||||||
export default function NoteReply({ data }: { data: any }) {
|
|
||||||
const content = noteParser(data);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex h-min min-h-min w-full select-text flex-col px-5 py-3.5 hover:bg-black/20">
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<NoteReplyUser pubkey={data.pubkey} time={data.created_at} />
|
|
||||||
<div className="-mt-[17px] pl-[48px]">
|
|
||||||
<ContentMarkdown content={content.parsed} />
|
|
||||||
{Array.isArray(content.images) && content.images.length ? <ImagePreview urls={content.images} /> : <></>}
|
|
||||||
{Array.isArray(content.videos) && content.videos.length ? <VideoPreview urls={content.videos} /> : <></>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
import { ContentMarkdown } from '@lume/app/note/components/markdown';
|
import { NoteContent } from '@lume/app/note/components/content';
|
||||||
import NoteMetadata from '@lume/app/note/components/metadata';
|
import NoteMetadata from '@lume/app/note/components/metadata';
|
||||||
import { noteParser } from '@lume/app/note/components/parser';
|
|
||||||
import ImagePreview from '@lume/app/note/components/preview/image';
|
|
||||||
import VideoPreview from '@lume/app/note/components/preview/video';
|
|
||||||
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
||||||
import { RelayContext } from '@lume/shared/relayProvider';
|
import { RelayContext } from '@lume/shared/relayProvider';
|
||||||
import { READONLY_RELAYS } from '@lume/stores/constants';
|
import { READONLY_RELAYS } from '@lume/stores/constants';
|
||||||
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
import { memo, useContext } from 'react';
|
import { memo, useContext } from 'react';
|
||||||
import useSWRSubscription from 'swr/subscription';
|
import useSWRSubscription from 'swr/subscription';
|
||||||
@@ -65,19 +63,7 @@ export const RootNote = memo(function RootNote({ id, fallback }: { id: string; f
|
|||||||
<div onClick={(e) => openNote(e)} className="relative z-10 flex flex-col">
|
<div onClick={(e) => openNote(e)} className="relative z-10 flex flex-col">
|
||||||
<NoteDefaultUser pubkey={parseFallback.pubkey} time={parseFallback.created_at} />
|
<NoteDefaultUser pubkey={parseFallback.pubkey} time={parseFallback.created_at} />
|
||||||
<div className="mt-1 pl-[52px]">
|
<div className="mt-1 pl-[52px]">
|
||||||
<ContentMarkdown content={contentFallback.parsed} />
|
<NoteContent content={contentFallback} />
|
||||||
{Array.isArray(contentFallback.images) && contentFallback.images.length ? (
|
|
||||||
<ImagePreview urls={contentFallback.images} />
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
{Array.isArray(contentFallback.videos) && contentFallback.videos.length ? (
|
|
||||||
<VideoPreview urls={contentFallback.videos} />
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div onClick={(e) => e.stopPropagation()} className="mt-5 pl-[52px]">
|
|
||||||
<NoteMetadata id={parseFallback.id} eventPubkey={parseFallback.pubkey} />
|
<NoteMetadata id={parseFallback.id} eventPubkey={parseFallback.pubkey} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -113,11 +99,7 @@ export const RootNote = memo(function RootNote({ id, fallback }: { id: string; f
|
|||||||
<div onClick={(e) => openNote(e)} className="relative z-10 flex flex-col">
|
<div onClick={(e) => openNote(e)} className="relative z-10 flex flex-col">
|
||||||
<NoteDefaultUser pubkey={data.pubkey} time={data.created_at} />
|
<NoteDefaultUser pubkey={data.pubkey} time={data.created_at} />
|
||||||
<div className="mt-1 pl-[52px]">
|
<div className="mt-1 pl-[52px]">
|
||||||
<ContentMarkdown content={content.parsed} />
|
<NoteContent content={content} />
|
||||||
{Array.isArray(content.images) && content.images.length ? <ImagePreview urls={content.images} /> : <></>}
|
|
||||||
{Array.isArray(content.videos) && content.videos.length ? <VideoPreview urls={content.videos} /> : <></>}
|
|
||||||
</div>
|
|
||||||
<div onClick={(e) => e.stopPropagation()} className="mt-5 pl-[52px]">
|
|
||||||
<NoteMetadata id={data.id} eventPubkey={data.pubkey} />
|
<NoteMetadata id={data.id} eventPubkey={data.pubkey} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import NoteMetadata from '@lume/app/note/components/metadata';
|
import NoteMetadata from '@lume/app/note/components/metadata';
|
||||||
import { noteParser } from '@lume/app/note/components/parser';
|
|
||||||
import ImagePreview from '@lume/app/note/components/preview/image';
|
import ImagePreview from '@lume/app/note/components/preview/image';
|
||||||
import VideoPreview from '@lume/app/note/components/preview/video';
|
import VideoPreview from '@lume/app/note/components/preview/video';
|
||||||
import NoteReplies from '@lume/app/note/components/replies';
|
import RepliesList from '@lume/app/note/components/replies/list';
|
||||||
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
import { NoteDefaultUser } from '@lume/app/note/components/user/default';
|
||||||
import { RelayContext } from '@lume/shared/relayProvider';
|
import { RelayContext } from '@lume/shared/relayProvider';
|
||||||
import { READONLY_RELAYS } from '@lume/stores/constants';
|
import { READONLY_RELAYS } from '@lume/stores/constants';
|
||||||
import { usePageContext } from '@lume/utils/hooks/usePageContext';
|
import { usePageContext } from '@lume/utils/hooks/usePageContext';
|
||||||
|
import { noteParser } from '@lume/utils/parser';
|
||||||
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import useSWRSubscription from 'swr/subscription';
|
import useSWRSubscription from 'swr/subscription';
|
||||||
@@ -94,7 +94,7 @@ export function Page() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<NoteReplies id={noteID} />
|
<RepliesList id={noteID} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ const getURLs = new RegExp(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const noteParser = (event: Event) => {
|
export const noteParser = (event: Event) => {
|
||||||
const content: { original: string; parsed: any; images: string[]; videos: string[] } = {
|
const content: { original: string; parsed: any; notes: string[]; images: string[]; videos: string[] } = {
|
||||||
original: event.content,
|
original: event.content,
|
||||||
parsed: event.content,
|
parsed: event.content,
|
||||||
|
notes: [],
|
||||||
images: [],
|
images: [],
|
||||||
videos: [],
|
videos: [],
|
||||||
};
|
};
|
||||||
@@ -31,19 +32,21 @@ export const noteParser = (event: Event) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// extract note mention
|
||||||
|
content.original.match(/^(nostr:)?(note1|nevent1).*$/gm)?.forEach((item) => {
|
||||||
|
content.notes.push(item);
|
||||||
|
// remove url from original content
|
||||||
|
content.parsed = content.parsed.toString().replace(item, '');
|
||||||
|
});
|
||||||
|
|
||||||
// map hashtag to em
|
// map hashtag to em
|
||||||
content.original.match(/#(\w+)(?!:\/\/)/gi)?.forEach((item) => {
|
content.original.match(/#(\w+)(?!:\/\/)/gi)?.forEach((item) => {
|
||||||
content.parsed = content.parsed.replace(item, `*${item}*`);
|
content.parsed = content.parsed.replace(item, `*${item}*`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// map note mention to h6
|
// map profile mention to h6 (markdown)
|
||||||
content.original.match(/^(nostr:)?(note1|nevent1).*$/gm)?.forEach((item) => {
|
|
||||||
content.parsed = content.parsed.replace(item, `###### ${item}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// map profile mention to h5
|
|
||||||
content.original.match(/^(nostr:)?(nprofile1|npub1).*$/gm)?.forEach((item) => {
|
content.original.match(/^(nostr:)?(nprofile1|npub1).*$/gm)?.forEach((item) => {
|
||||||
content.parsed = content.parsed.replace(item, `##### ${item}`);
|
content.parsed = content.parsed.replace(item, `###### ${item}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
Reference in New Issue
Block a user