restructure note component

This commit is contained in:
Ren Amamiya
2023-06-20 09:01:48 +07:00
parent aa8531b32b
commit 9b84068e6d
22 changed files with 257 additions and 286 deletions

View File

@@ -16,7 +16,7 @@ export function Button({
switch (preset) {
case "small":
preClass =
"w-min h-9 px-4 bg-zinc-900 rounded-md text-sm font-medium text-zinc-100 hover:bg-fuchsia-600";
"w-min h-9 px-4 bg-fuchsia-500 rounded-md text-sm font-medium text-zinc-100 hover:bg-fuchsia-600";
break;
case "publish":
preClass =

View File

@@ -11,7 +11,7 @@ import {
import { useActiveAccount } from "@stores/accounts";
import { useComposer } from "@stores/composer";
import { COMPOSE_SHORTCUT } from "@stores/shortcuts";
import { register } from "@tauri-apps/api/globalShortcut";
import { isRegistered, register } from "@tauri-apps/api/globalShortcut";
import { Fragment, useEffect } from "react";
export function Composer() {
@@ -26,14 +26,17 @@ export function Composer() {
};
const registerShortcut = async () => {
await register(COMPOSE_SHORTCUT, () => {
toggle(true);
});
const isShortcutRegistered = await isRegistered(COMPOSE_SHORTCUT);
if (!isShortcutRegistered) {
await register(COMPOSE_SHORTCUT, () => {
toggle(true);
});
}
};
useEffect(() => {
registerShortcut();
}, [registerShortcut]);
}, []);
return (
<>

23
src/shared/icons/cmd.tsx Normal file
View File

@@ -0,0 +1,23 @@
import { SVGProps } from "react";
export function CommandIcon(
props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="square"
strokeWidth="1.5"
d="M9.25 9.25V6.5A2.75 2.75 0 106.5 9.25h2.75zm0 0h5.5m-5.5 0v5.5m5.5-5.5V6.5a2.75 2.75 0 112.75 2.75h-2.75zm0 0v5.5m0 0h-5.5m5.5 0v2.75a2.75 2.75 0 102.75-2.75h-2.75zm-5.5 0v2.75a2.75 2.75 0 11-2.75-2.75h2.75z"
/>
</svg>
);
}

View File

@@ -35,4 +35,5 @@ export * from "./zap";
export * from "./loader";
export * from "./trending";
export * from "./empty";
export * from "./cmd";
// @endindex

View File

@@ -1,47 +0,0 @@
import { Kind1 } from "@shared/notes/kind1";
import { Kind1063 } from "@shared/notes/kind1063";
import { NoteMetadata } from "@shared/notes/metadata";
import { NoteParent } from "@shared/notes/parent";
import { User } from "@shared/user";
import { parser } from "@utils/parser";
import { isTagsIncludeID } from "@utils/transform";
import { LumeEvent } from "@utils/types";
import { useMemo } from "react";
export function NoteBase({
event,
block,
metadata = true,
}: { event: LumeEvent; block?: number; metadata?: boolean }) {
const content = useMemo(() => parser(event), [event]);
const checkParentID = isTagsIncludeID(event.parent_id, event.tags);
return (
<div className="h-min w-full px-3 py-1.5">
<div className="rounded-md bg-zinc-900 px-5 pt-5">
{event.parent_id &&
(event.parent_id !== event.event_id || checkParentID) ? (
<NoteParent id={event.parent_id} />
) : (
<></>
)}
<div className="flex flex-col">
<User pubkey={event.pubkey} time={event.created_at} />
<div className="-mt-5 pl-[49px]">
{event.kind === 1 && <Kind1 content={content} />}
{event.kind === 1063 && <Kind1063 metadata={event.tags} />}
{metadata ? (
<NoteMetadata
id={event.event_id}
eventPubkey={event.pubkey}
currentBlock={block || 1}
/>
) : (
<div className="h-5" />
)}
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,5 +1,5 @@
import { Kind1 } from "@shared/notes/kind1";
import { Kind1063 } from "@shared/notes/kind1063";
import { Kind1 } from "@shared/notes/contents/kind1";
import { Kind1063 } from "@shared/notes/contents/kind1063";
import { NoteSkeleton } from "@shared/notes/skeleton";
import { User } from "@shared/user";
import { useEvent } from "@utils/hooks/useEvent";

89
src/shared/notes/note.tsx Normal file
View File

@@ -0,0 +1,89 @@
import { Kind1 } from "@shared/notes/contents/kind1";
import { Kind1063 } from "@shared/notes/contents/kind1063";
import { NoteMetadata } from "@shared/notes/metadata";
import { NoteParent } from "@shared/notes/parent";
import { Repost } from "@shared/notes/repost";
import { User } from "@shared/user";
import { parser } from "@utils/parser";
import { LumeEvent } from "@utils/types";
import { useMemo } from "react";
interface Note {
event: LumeEvent;
block?: number;
}
export function Note({ event, block }: Note) {
const isRepost = event.kind === 6;
const renderParent = useMemo(() => {
if (!isRepost && event.parent_id && event.parent_id !== event.event_id) {
return <NoteParent id={event.parent_id} currentBlock={block} />;
} else {
return null;
}
}, [event.parent_id]);
const renderRepost = useMemo(() => {
if (isRepost) {
return <Repost event={event} currentBlock={block} />;
} else {
return null;
}
}, [event.kind]);
const renderContent = useMemo(() => {
switch (event.kind) {
case 1: {
const content = parser(event);
return <Kind1 content={content} />;
}
case 6:
return null;
case 1063:
return <Kind1063 metadata={event.tags} />;
default:
return (
<div className="flex flex-col gap-2">
<div className="px-2 py-2 inline-flex flex-col gap-1 bg-zinc-800 rounded-md">
<span className="text-zinc-500 text-sm font-medium leading-none">
Kind: {event.kind}
</span>
<p className="text-fuchsia-500 text-sm leading-none">
Lume isn't fully support this kind in newsfeed
</p>
</div>
<div className="markdown">
<p>{event.content}</p>
</div>
</div>
);
}
}, [event.kind]);
return (
<div className="h-min w-full px-3 py-1.5">
<div className="rounded-md bg-zinc-900 px-5 pt-5">
{renderParent}
<div className="flex flex-col">
<User
pubkey={event.pubkey}
time={event.created_at}
repost={isRepost}
/>
<div className="-mt-5 pl-[49px]">
{renderContent}
{!isRepost && (
<NoteMetadata
id={event.event_id}
eventPubkey={event.pubkey}
currentBlock={block || 1}
/>
)}
</div>
</div>
{renderRepost}
</div>
</div>
);
}

View File

@@ -1,13 +1,15 @@
import { Kind1 } from "@shared/notes/kind1";
import { Kind1063 } from "@shared/notes/kind1063";
import { Kind1 } from "@shared/notes/contents/kind1";
import { Kind1063 } from "@shared/notes/contents/kind1063";
import { NoteMetadata } from "@shared/notes/metadata";
import { NoteSkeleton } from "@shared/notes/skeleton";
import { User } from "@shared/user";
import { useEvent } from "@utils/hooks/useEvent";
import { parser } from "@utils/parser";
import { memo } from "react";
export const NoteParent = memo(function NoteParent({ id }: { id: string }) {
export function NoteParent({
id,
currentBlock,
}: { id: string; currentBlock: number }) {
const data = useEvent(id);
const kind1 = data?.kind === 1 ? parser(data) : null;
@@ -33,13 +35,14 @@ export const NoteParent = memo(function NoteParent({ id }: { id: string }) {
</p>
</div>
<div className="markdown">
<p>{data.content}</p>
<p>{data.content || data.toString()}</p>
</div>
</div>
)}
<NoteMetadata
id={data.event_id || data.id}
eventPubkey={data.pubkey}
currentBlock={currentBlock}
/>
</div>
</>
@@ -48,4 +51,4 @@ export const NoteParent = memo(function NoteParent({ id }: { id: string }) {
)}
</div>
);
});
}

View File

@@ -1,23 +0,0 @@
import { RootNote } from "@shared/notes/rootNote";
import { User } from "@shared/user";
import { getQuoteID } from "@utils/transform";
import { LumeEvent } from "@utils/types";
export function NoteQuoteRepost({
block,
event,
}: { block: number; event: LumeEvent }) {
const rootID = getQuoteID(event.tags);
return (
<div className="h-min w-full px-3 py-1.5">
<div className="rounded-md bg-zinc-900">
<div className="relative px-5 pb-5 pt-5">
<div className="absolute left-[35px] top-[20px] h-[70px] w-0.5 bg-gradient-to-t from-zinc-800 to-zinc-600" />
<User pubkey={event.pubkey} time={event.created_at} repost={true} />
</div>
<RootNote id={rootID} fallback={event.content} currentBlock={block} />
</div>
</div>
);
}

View File

@@ -1,4 +1,4 @@
import { Kind1 } from "@shared/notes/kind1";
import { Kind1 } from "@shared/notes/contents/kind1";
import { NoteMetadata } from "@shared/notes/metadata";
import { User } from "@shared/user";
import { parser } from "@utils/parser";

View File

@@ -0,0 +1,56 @@
import { Kind1 } from "@shared/notes/contents/kind1";
import { Kind1063 } from "@shared/notes/contents/kind1063";
import { NoteMetadata } from "@shared/notes/metadata";
import { NoteSkeleton } from "@shared/notes/skeleton";
import { User } from "@shared/user";
import { useEvent } from "@utils/hooks/useEvent";
import { parser } from "@utils/parser";
import { getRepostID } from "@utils/transform";
import { LumeEvent } from "@utils/types";
export function Repost({
event,
currentBlock,
}: { event: LumeEvent; currentBlock?: number }) {
const repostID = getRepostID(event.tags);
const data = useEvent(repostID);
const kind1 = data?.kind === 1 ? parser(data) : null;
const kind1063 = data?.kind === 1063 ? data.tags : null;
return (
<div className="relative overflow-hidden flex flex-col mt-12 pb-6">
{data ? (
<>
<User pubkey={data.pubkey} time={data.created_at} />
<div className="-mt-5 pl-[49px]">
{kind1 && <Kind1 content={kind1} />}
{kind1063 && <Kind1063 metadata={kind1063} />}
{!kind1 && !kind1063 && (
<div className="flex flex-col gap-2">
<div className="px-2 py-2 inline-flex flex-col gap-1 bg-zinc-800 rounded-md">
<span className="text-zinc-500 text-sm font-medium leading-none">
Kind: {data.kind}
</span>
<p className="text-fuchsia-500 text-sm leading-none">
Lume isn't fully support this kind in newsfeed
</p>
</div>
<div className="markdown">
<p>{data.content || data.toString()}</p>
</div>
</div>
)}
<NoteMetadata
id={data.event_id || data.id}
eventPubkey={data.pubkey}
currentBlock={currentBlock}
/>
</div>
</>
) : (
<NoteSkeleton />
)}
</div>
);
}

View File

@@ -1,102 +0,0 @@
import { NDKEvent } from "@nostr-dev-kit/ndk";
import { Kind1 } from "@shared/notes/kind1";
import { Kind1063 } from "@shared/notes/kind1063";
import { NoteMetadata } from "@shared/notes/metadata";
import { NoteSkeleton } from "@shared/notes/skeleton";
import { RelayContext } from "@shared/relayProvider";
import { User } from "@shared/user";
import { parser } from "@utils/parser";
import { memo, useContext } from "react";
import useSWRSubscription from "swr/subscription";
function isJSON(str: string) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
export const RootNote = memo(function RootNote({
id,
fallback,
currentBlock,
}: { id: string; fallback?: any; currentBlock?: number }) {
const ndk = useContext(RelayContext);
const parseFallback = isJSON(fallback) ? JSON.parse(fallback) : null;
const { data, error } = useSWRSubscription(
parseFallback ? null : id,
(key, { next }) => {
const sub = ndk.subscribe({
ids: [key],
});
sub.addListener("event", (event: NDKEvent) => {
next(null, event);
});
return () => {
sub.stop();
};
},
);
const kind1 = !error && data?.kind === 1 ? parser(data) : null;
const kind1063 = !error && data?.kind === 1063 ? data.tags : null;
if (parseFallback) {
const contentFallback = parser(parseFallback);
return (
<div className="flex flex-col px-5">
<User pubkey={parseFallback.pubkey} time={parseFallback.created_at} />
<div className="-mt-5 pl-[49px]">
<Kind1 content={contentFallback} />
<NoteMetadata
id={parseFallback.id}
eventPubkey={parseFallback.pubkey}
currentBlock={currentBlock}
/>
</div>
</div>
);
}
return (
<div className="flex flex-col px-5">
{data ? (
<>
<User pubkey={data.pubkey} time={data.created_at} />
<div className="-mt-5 pl-[49px]">
{kind1 && <Kind1 content={kind1} />}
{kind1063 && <Kind1063 metadata={kind1063} />}
{!kind1 && !kind1063 && (
<div className="flex flex-col gap-2">
<div className="px-2 py-2 inline-flex flex-col gap-1 bg-zinc-800 rounded-md">
<span className="text-zinc-500 text-sm font-medium leading-none">
Kind: {data.kind}
</span>
<p className="text-fuchsia-500 text-sm leading-none">
Lume isn't fully support this kind in newsfeed
</p>
</div>
<div className="markdown">
<p>{data.content}</p>
</div>
</div>
)}
<NoteMetadata
id={data.id}
eventPubkey={data.pubkey}
currentBlock={currentBlock}
/>
</div>
</>
) : (
<NoteSkeleton />
)}
</div>
);
});