mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-18 11:13:30 +00:00
refactor event handler
This commit is contained in:
parent
31a3a712ec
commit
4b73715927
@ -57,12 +57,12 @@ export default function CreatePost() {
|
||||
return (
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger asChild>
|
||||
<div className="flex flex-col">
|
||||
<div className="relative shrink-0 before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-blue-500/100 dark:focus-within:after:shadow-blue-500/20">
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="relative h-16 shrink-0 before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] before:border before:border-blue-500 before:opacity-0 before:ring-2 before:ring-blue-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-blue-500/100 dark:focus-within:after:shadow-blue-500/20">
|
||||
<textarea
|
||||
readOnly
|
||||
placeholder="What's your thought?"
|
||||
className="relative w-full resize-none rounded-lg border border-black/5 px-3.5 py-3 text-sm shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
|
||||
className="relative h-16 w-full resize-none rounded-lg border border-black/5 px-3.5 py-3 text-sm shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-200 dark:shadow-black/10 dark:placeholder:text-zinc-500"
|
||||
/>
|
||||
</div>
|
||||
<button className="inline-flex h-9 w-full items-center justify-center rounded-lg border border-white/10 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-gray-300 via-fuchsia-600 to-orange-600 text-sm font-semibold shadow-input">
|
||||
|
@ -2,14 +2,14 @@
|
||||
import { truncate } from '@utils/truncate';
|
||||
|
||||
import { useNostrEvents } from 'nostr-react';
|
||||
import { useState } from 'react';
|
||||
import { memo, useState } from 'react';
|
||||
|
||||
export default function RootUser({ userPubkey, action }: { userPubkey: string; action: string }) {
|
||||
export const UserRepost = memo(function UserRepost({ pubkey }: { pubkey: string }) {
|
||||
const [profile, setProfile] = useState({ picture: null, name: null });
|
||||
|
||||
const { onEvent } = useNostrEvents({
|
||||
filter: {
|
||||
authors: [userPubkey],
|
||||
authors: [pubkey],
|
||||
kinds: [0],
|
||||
},
|
||||
});
|
||||
@ -28,9 +28,7 @@ export default function RootUser({ userPubkey, action }: { userPubkey: string; a
|
||||
|
||||
return (
|
||||
<div className="text-zinc-400">
|
||||
<p>
|
||||
{profile.name ? profile.name : truncate(userPubkey, 16, ' .... ')} {action}
|
||||
</p>
|
||||
<p>{profile.name ? profile.name : truncate(pubkey, 16, ' .... ')} repost</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
@ -1,4 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import Reaction from '@components/note/atoms/reaction';
|
||||
import Reply from '@components/note/atoms/reply';
|
||||
import { User } from '@components/note/atoms/user';
|
||||
import { ImageCard } from '@components/note/content/preview/imageCard';
|
||||
import { Video } from '@components/note/content/preview/video';
|
||||
|
||||
@ -14,13 +17,13 @@ const MarkdownPreview = dynamic(() => import('@uiw/react-markdown-preview'), {
|
||||
export default function Content({ data }: { data: any }) {
|
||||
const [preview, setPreview] = useState({});
|
||||
|
||||
const content = useRef(data);
|
||||
const content = useRef(data.content);
|
||||
const urls = useMemo(
|
||||
() =>
|
||||
data.match(
|
||||
content.current.match(
|
||||
/((http|ftp|https):\/\/)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi
|
||||
),
|
||||
[data]
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -61,25 +64,36 @@ export default function Content({ data }: { data: any }) {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<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',
|
||||
]}
|
||||
/>
|
||||
<User pubkey={data.pubkey} time={data.created_at} />
|
||||
<div className="-mt-4 pl-[60px]">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col">
|
||||
<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>
|
||||
<>{previewAttachment()}</>
|
||||
</div>
|
||||
<div className="relative z-10 -ml-1 flex items-center gap-8">
|
||||
<Reply eventID={data.id} />
|
||||
<Reaction eventID={data.id} eventPubkey={data.pubkey} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>{previewAttachment()}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
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 Content from '@components/note/content';
|
||||
import { Placeholder } from '@components/note/placeholder';
|
||||
|
||||
import LikeSolidIcon from '@assets/icons/LikeSolid';
|
||||
|
||||
import { useNostrEvents } from 'nostr-react';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const Liked = memo(function Liked({
|
||||
eventUser,
|
||||
sourceID,
|
||||
}: {
|
||||
eventUser: string;
|
||||
sourceID: string;
|
||||
}) {
|
||||
const { events } = useNostrEvents({
|
||||
filter: {
|
||||
ids: [sourceID],
|
||||
since: 0,
|
||||
kinds: [1],
|
||||
limit: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (events !== undefined && events.length > 0) {
|
||||
return (
|
||||
<div className="flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 py-6 px-6">
|
||||
<div className="flex items-center gap-1 pl-8 text-sm">
|
||||
<LikeSolidIcon className="h-4 w-4 text-zinc-400" />
|
||||
<div className="ml-2">
|
||||
<RootUser userPubkey={eventUser} action={'like'} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<User pubkey={events[0].pubkey} time={events[0].created_at} />
|
||||
<div className="-mt-4 pl-[60px]">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Content data={events[0].content} />
|
||||
<div className="-ml-1 flex items-center gap-8">
|
||||
<Reply eventID={events[0].id} />
|
||||
<Reaction eventID={events[0].id} eventPubkey={events[0].pubkey} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <Placeholder />;
|
||||
}
|
||||
});
|
@ -1,55 +0,0 @@
|
||||
import Reaction from '@components/note/atoms/reaction';
|
||||
import Reply from '@components/note/atoms/reply';
|
||||
import { User } from '@components/note/atoms/user';
|
||||
import Content from '@components/note/content';
|
||||
import { Placeholder } from '@components/note/placeholder';
|
||||
|
||||
import { useNostrEvents } from 'nostr-react';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function Multi({ event }: { event: any }) {
|
||||
const tags = event.tags;
|
||||
|
||||
const { events } = useNostrEvents({
|
||||
filter: {
|
||||
ids: [tags[0][1]],
|
||||
since: 0,
|
||||
kinds: [1],
|
||||
limit: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (events !== undefined && events.length > 0) {
|
||||
return (
|
||||
<div className="relative flex h-min min-h-min w-full select-text flex-col overflow-hidden border-b border-zinc-800">
|
||||
<div className="absolute left-[45px] top-6 h-full w-[2px] bg-zinc-800"></div>
|
||||
<div className="flex flex-col bg-zinc-900 px-6 pt-6 pb-2">
|
||||
<User pubkey={events[0].pubkey} time={events[0].created_at} />
|
||||
<div className="-mt-4 pl-[60px]">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Content data={events[0].content} />
|
||||
<div className="-ml-1 flex items-center gap-8">
|
||||
<Reply eventID={events[0].id} />
|
||||
<Reaction eventID={events[0].id} eventPubkey={events[0].pubkey} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex flex-col bg-zinc-900 px-6 pb-6">
|
||||
<User pubkey={event.pubkey} time={event.created_at} />
|
||||
<div className="relative z-10 -mt-4 pl-[60px]">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Content data={event.content} />
|
||||
<div className="-ml-1 flex items-center gap-8">
|
||||
<Reply eventID={event.id} />
|
||||
<Reaction eventID={event.id} eventPubkey={event.pubkey} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <Placeholder />;
|
||||
}
|
||||
}
|
@ -1,55 +1,56 @@
|
||||
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';
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { UserRepost } from '@components/note/atoms/userRepost';
|
||||
import Content from '@components/note/content';
|
||||
import { Placeholder } from '@components/note/placeholder';
|
||||
|
||||
import RepostIcon from '@assets/icons/Repost';
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useNostrEvents } from 'nostr-react';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const Repost = memo(function Repost({
|
||||
eventUser,
|
||||
sourceID,
|
||||
}: {
|
||||
eventUser: string;
|
||||
sourceID: string;
|
||||
}) {
|
||||
const Modal = dynamic(() => import('@components/note/modal'), {
|
||||
ssr: false,
|
||||
loading: () => <></>,
|
||||
});
|
||||
|
||||
export const Repost = memo(function Repost({ root, user }: { root: any; user: string }) {
|
||||
const { events } = useNostrEvents({
|
||||
filter: {
|
||||
ids: [sourceID],
|
||||
ids: [root[0][1]],
|
||||
since: 0,
|
||||
kinds: [1],
|
||||
limit: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (events !== undefined && events.length > 0) {
|
||||
if (events !== null) {
|
||||
return (
|
||||
<div className="flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 py-6 px-6">
|
||||
<div className="flex items-center gap-1 pl-8 text-sm">
|
||||
<RepostIcon className="h-4 w-4 text-zinc-400" />
|
||||
<div className="ml-2">
|
||||
<RootUser userPubkey={eventUser} action={'repost'} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<User pubkey={events[0].pubkey} time={events[0].created_at} />
|
||||
<div className="-mt-4 pl-[60px]">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Content data={events[0].content} />
|
||||
<div className="-ml-1 flex items-center gap-8">
|
||||
<Reply eventID={events[0].id} />
|
||||
<Reaction eventID={events[0].id} eventPubkey={events[0].pubkey} />
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<div className="flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 py-6 px-6">
|
||||
<div className="flex items-center gap-1 pl-8 text-sm">
|
||||
<RepostIcon className="h-4 w-4 text-zinc-400" />
|
||||
<div className="ml-2">
|
||||
<UserRepost pubkey={user} />
|
||||
</div>
|
||||
</div>
|
||||
<Content data={events[0]} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm data-[state=open]:animate-overlayShow" />
|
||||
<Dialog.Content className="fixed inset-0 overflow-y-auto">
|
||||
<Modal event={events[0]} />
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Trigger>
|
||||
</Dialog.Root>
|
||||
);
|
||||
} else {
|
||||
return <Placeholder />;
|
||||
return (
|
||||
<div className="border-b border-zinc-800">
|
||||
<Placeholder />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import Reaction from '@components/note/atoms/reaction';
|
||||
import Reply from '@components/note/atoms/reply';
|
||||
import { User } from '@components/note/atoms/user';
|
||||
import Content from '@components/note/content';
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
@ -15,22 +12,13 @@ const Modal = dynamic(() => import('@components/note/modal'), {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const Single = memo(function Single({ event }: { event: any }) {
|
||||
console.log(event);
|
||||
|
||||
return (
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger asChild>
|
||||
<div className="flex h-min min-h-min w-full cursor-pointer select-text flex-col border-b border-zinc-800 py-4 px-6 hover:bg-zinc-800">
|
||||
<div className="flex flex-col">
|
||||
<User pubkey={event.pubkey} time={event.created_at} />
|
||||
<div className="-mt-4 pl-[60px]">
|
||||
<div className="flex flex-col gap-6">
|
||||
<Content data={event.content} />
|
||||
<div className="relative z-10 -ml-1 flex items-center gap-8">
|
||||
<Reply eventID={event.id} />
|
||||
<Reaction eventID={event.id} eventPubkey={event.pubkey} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Content data={event} />
|
||||
</div>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { Liked } from '@components/note/liked';
|
||||
// import { Multi } from '@components/note/multi';
|
||||
import { Placeholder } from '@components/note/placeholder';
|
||||
import { Repost } from '@components/note/repost';
|
||||
import { Single } from '@components/note/single';
|
||||
@ -13,15 +11,12 @@ export function Thread({ data }: { data: any }) {
|
||||
(index: string | number) => {
|
||||
const event = data[index];
|
||||
|
||||
if (event.kind === 7) {
|
||||
// type: like
|
||||
return <Liked key={index} eventUser={event.pubkey} sourceID={event.tags[0][1]} />;
|
||||
} else if (event.content === '#[0]') {
|
||||
if (event.content.includes('#[0]') && event.tags[0][0] == 'e') {
|
||||
// type: repost
|
||||
return <Repost key={index} eventUser={event.pubkey} sourceID={event.tags[0][1]} />;
|
||||
return <Repost root={event.tags} user={event.pubkey} />;
|
||||
} else {
|
||||
// type: default
|
||||
return <Single key={index} event={event} />;
|
||||
return <Single event={event} />;
|
||||
}
|
||||
},
|
||||
[data]
|
||||
|
@ -1,40 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import BaseLayout from '@layouts/baseLayout';
|
||||
import UserLayout from '@layouts/userLayout';
|
||||
|
||||
import { GetStaticPaths } from 'next';
|
||||
import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal } from 'react';
|
||||
|
||||
export default function Page({ id }: { id: string }) {
|
||||
return <div>{id}</div>;
|
||||
}
|
||||
|
||||
export const getStaticPaths: GetStaticPaths = async () => {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: 'blocking',
|
||||
};
|
||||
};
|
||||
|
||||
export async function getStaticProps(context) {
|
||||
const id = context.params.id;
|
||||
return {
|
||||
props: { id },
|
||||
};
|
||||
}
|
||||
|
||||
Page.getLayout = function getLayout(
|
||||
page:
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| ReactElement<unknown, string | JSXElementConstructor<unknown>>
|
||||
| ReactFragment
|
||||
| ReactPortal
|
||||
) {
|
||||
return (
|
||||
<BaseLayout>
|
||||
<UserLayout>{page}</UserLayout>
|
||||
</BaseLayout>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user