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

@ -15,7 +15,7 @@
"dependencies": {
"@floating-ui/react": "^0.23.1",
"@headlessui/react": "^1.7.15",
"@nostr-dev-kit/ndk": "^0.5.3",
"@nostr-dev-kit/ndk": "^0.5.4",
"@tanstack/react-virtual": "3.0.0-beta.54",
"@tauri-apps/api": "^1.4.0",
"@vidstack/react": "^0.4.5",
@ -27,7 +27,7 @@
"nostr-tools": "^1.12.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.44.3",
"react-hook-form": "^7.45.0",
"react-resizable-panels": "^0.0.48",
"react-string-replace": "^1.1.1",
"react-virtuoso": "^4.3.10",

View File

@ -8,8 +8,8 @@ dependencies:
specifier: ^1.7.15
version: 1.7.15(react-dom@18.2.0)(react@18.2.0)
'@nostr-dev-kit/ndk':
specifier: ^0.5.3
version: 0.5.3(typescript@4.9.5)
specifier: ^0.5.4
version: 0.5.4(typescript@4.9.5)
'@tanstack/react-virtual':
specifier: 3.0.0-beta.54
version: 3.0.0-beta.54(react@18.2.0)
@ -44,8 +44,8 @@ dependencies:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-hook-form:
specifier: ^7.44.3
version: 7.44.3(react@18.2.0)
specifier: ^7.45.0
version: 7.45.0(react@18.2.0)
react-resizable-panels:
specifier: ^0.0.48
version: 0.0.48(react-dom@18.2.0)(react@18.2.0)
@ -571,8 +571,8 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
/@nostr-dev-kit/ndk@0.5.3(typescript@4.9.5):
resolution: {integrity: sha512-GLmuAoor4oMxxKjFeZ4viHR9XEI61m0wBm78vTUzY1Ev+bBdDzorv6heBz7TWmQirtoJ32r/zIgWdzHsHC6h3A==}
/@nostr-dev-kit/ndk@0.5.4(typescript@4.9.5):
resolution: {integrity: sha512-A1JXJVJjyO8q53KXHnmFG6lf/b+7LSveLpHOJvUtcnbM/mkMtYlPJknMQ3i08oDdBO1j+nG3/8xYC3Y/8+arVw==}
dependencies:
'@noble/hashes': 1.3.1
'@noble/secp256k1': 2.0.0
@ -699,8 +699,8 @@ packages:
resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==}
dev: false
/@swc/core-darwin-arm64@1.3.64:
resolution: {integrity: sha512-gSPld6wxZBZoEvZXWmNfd+eJGlGvrEXmhMBCUwSccpuMa0KqK7F6AAZVu7kFkmlXPq2kS8owjk6/VXnVBmm5Vw==}
/@swc/core-darwin-arm64@1.3.65:
resolution: {integrity: sha512-fQIXZgr7CD/+1ADqrVbz/gHvSoIMmggHvPzguQjV8FggBuS9Efm1D1ZrdUSqptggKvuLLHMZf+49tENq8NWWcg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [darwin]
@ -708,8 +708,8 @@ packages:
dev: true
optional: true
/@swc/core-darwin-x64@1.3.64:
resolution: {integrity: sha512-SJd1pr+U2pz5ZVv5BL36CN879Pn1V0014uVNlB+6yNh3e8T0fjUbtRJcbFiBB+OeYuJ1UNUeslaRJtKJNtMH7A==}
/@swc/core-darwin-x64@1.3.65:
resolution: {integrity: sha512-kGuWP7OP9mwOiIcJpEVa+ydC3Wxf0fPQ1MK0hUIPFcR6tAUEdOvdAuCzP6U20RX/JbbgwfI/Qq6ugT7VL6omgg==}
engines: {node: '>=10'}
cpu: [x64]
os: [darwin]
@ -717,8 +717,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-arm-gnueabihf@1.3.64:
resolution: {integrity: sha512-XE60bZS+qO+d8IQYAayhn3TRqyzVmQeOsX2B1yUHuKZU3Zb/mt/cmD/HLzZZW7J3z19kYf2na7Hvmnt3amUGoA==}
/@swc/core-linux-arm-gnueabihf@1.3.65:
resolution: {integrity: sha512-Bjbzldp8n4mWSdAvBt4VuLiHlfFM5pyftjJvJnmSY4H1IzbxkByyT60OHOedcIPRiZveD8NJzUJqutqrgTmtLg==}
engines: {node: '>=10'}
cpu: [arm]
os: [linux]
@ -726,8 +726,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-arm64-gnu@1.3.64:
resolution: {integrity: sha512-+jcUua4cYLRMqDicv+4AaTZUGgYWXkXVI9AzaAgfkMNLU2TMXwuYXopxk1giAMop88+ovzYIqrxErRdu70CgtQ==}
/@swc/core-linux-arm64-gnu@1.3.65:
resolution: {integrity: sha512-GmxtcCymeQqEqT9n5mo857koRsUbEwmuijrBA4OeD5KOPW9gqAmUxr+ZgwgYHwyJ3CiN+UbK8uEqPsL6UVQmLg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
@ -735,8 +735,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-arm64-musl@1.3.64:
resolution: {integrity: sha512-50MI8NFYUKhLncqY2piM/XOnNqZT6zY2ZoNOFsy63/T2gAYy1ts4mF4YUEkg4XOA2zhue1JSLZBUrHQXbgMYUQ==}
/@swc/core-linux-arm64-musl@1.3.65:
resolution: {integrity: sha512-yv9jP3gbfMsYrqswT2MwK5Q1+avSwRXAKo+LYUknTeoLQNNlukDfqSLHajNq23XrVDRP4B3Pjn7kaqjxRcihbg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
@ -744,8 +744,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-x64-gnu@1.3.64:
resolution: {integrity: sha512-bT8seQ41Q4J2JDgn2JpFCGNehGAIilAkZ476gEaKKroEWepBhkD0K1MspSSVYSJhLSGbBVSaadUEiBPxWgu1Rw==}
/@swc/core-linux-x64-gnu@1.3.65:
resolution: {integrity: sha512-GQkwysEPTlAOQ3jiTiedObzh6pBaf9RLaQqpGdCp+iKze9+BR+STBP0IIKhZDMPG/nWWNhrYFD/VMQxRoYPjfw==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
@ -753,8 +753,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-x64-musl@1.3.64:
resolution: {integrity: sha512-sJgh3TXCDOEq/Au4XLAgNqy4rVcLeywQBoftnV3rcvX1/u9OCSRzgKLgYc5d1pEN5AMJV1l4u26kbGlQuZ+yRw==}
/@swc/core-linux-x64-musl@1.3.65:
resolution: {integrity: sha512-ETzhOhtDluYFK4x73OTM9gVTMyzGd2WeWGlCu3WoT1EPPUwCqQpcAqI3TfEcP1ljFDG0pPkpYzVpwNf8yjQElg==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
@ -762,8 +762,8 @@ packages:
dev: true
optional: true
/@swc/core-win32-arm64-msvc@1.3.64:
resolution: {integrity: sha512-zWIy+mAWDjtJjl4e4mmhQL7g9KbkOwcWbeoIk4C6NT4VpjnjdX1pMml/Ez2sF5J5cGBwu7B1ePfTe/kAE6G36Q==}
/@swc/core-win32-arm64-msvc@1.3.65:
resolution: {integrity: sha512-3weD0I6F8bggN0KOnbZkvYC1PBrT5wrvohpvtgijRsODxjoWwztozjawJxF3rqgVqlSI/+nA+JkrN48e2cxJjQ==}
engines: {node: '>=10'}
cpu: [arm64]
os: [win32]
@ -771,8 +771,8 @@ packages:
dev: true
optional: true
/@swc/core-win32-ia32-msvc@1.3.64:
resolution: {integrity: sha512-6HMiuUeSMpTUAimb1E+gUNjy8m211oAzw+wjU8oOdA6iihWaLBz4TOhU9IaKZPPjqEcYGwqaT3tj5b5+mxde6Q==}
/@swc/core-win32-ia32-msvc@1.3.65:
resolution: {integrity: sha512-i6c3D7E9Ca41HteW3+hn1OKQfjIabc2P0p1mJRXBkn+igwb+Ba6gXJc7NqhrlF8uZsDhhcGZTsAqBBtfcfTuHQ==}
engines: {node: '>=10'}
cpu: [ia32]
os: [win32]
@ -780,8 +780,8 @@ packages:
dev: true
optional: true
/@swc/core-win32-x64-msvc@1.3.64:
resolution: {integrity: sha512-c8Al0JJfmgnO9sg6w34PICibqI4p7iXywo+wOxjY88oFwMcfV5rGaif1Fe3RqxJP/1WtUV7lYuKKZrneMXtyLA==}
/@swc/core-win32-x64-msvc@1.3.65:
resolution: {integrity: sha512-tQ9hEDtwPZxQ2sYb2n8ypfmdMjobKAf6VSnChteLMktofU7o562op5pLS6D6QCP2AtL3lcwe1piTCgIhk4vmjA==}
engines: {node: '>=10'}
cpu: [x64]
os: [win32]
@ -789,8 +789,8 @@ packages:
dev: true
optional: true
/@swc/core@1.3.64:
resolution: {integrity: sha512-be1dk2pfjzBjFp/+p47/wvOAm7KpEtsi7hqI3ofox6pK3hBJChHgVTLVV9xqZm7CnYdyYYw3Z78hH6lrwutxXQ==}
/@swc/core@1.3.65:
resolution: {integrity: sha512-d5iDiKWf12FBo6h9Fro2pcnLK6HSPbyZ7A1U5iFNpRRx8XEd4uGdKtf5NoXJ3GDLQDLXnNSLA82Cl6SfrJ1lyw==}
engines: {node: '>=10'}
requiresBuild: true
peerDependencies:
@ -799,16 +799,16 @@ packages:
'@swc/helpers':
optional: true
optionalDependencies:
'@swc/core-darwin-arm64': 1.3.64
'@swc/core-darwin-x64': 1.3.64
'@swc/core-linux-arm-gnueabihf': 1.3.64
'@swc/core-linux-arm64-gnu': 1.3.64
'@swc/core-linux-arm64-musl': 1.3.64
'@swc/core-linux-x64-gnu': 1.3.64
'@swc/core-linux-x64-musl': 1.3.64
'@swc/core-win32-arm64-msvc': 1.3.64
'@swc/core-win32-ia32-msvc': 1.3.64
'@swc/core-win32-x64-msvc': 1.3.64
'@swc/core-darwin-arm64': 1.3.65
'@swc/core-darwin-x64': 1.3.65
'@swc/core-linux-arm-gnueabihf': 1.3.65
'@swc/core-linux-arm64-gnu': 1.3.65
'@swc/core-linux-arm64-musl': 1.3.65
'@swc/core-linux-x64-gnu': 1.3.65
'@swc/core-linux-x64-musl': 1.3.65
'@swc/core-win32-arm64-msvc': 1.3.65
'@swc/core-win32-ia32-msvc': 1.3.65
'@swc/core-win32-x64-msvc': 1.3.65
dev: true
/@tailwindcss/typography@0.5.9(tailwindcss@3.3.2):
@ -1175,7 +1175,7 @@ packages:
peerDependencies:
vite: ^4
dependencies:
'@swc/core': 1.3.64
'@swc/core': 1.3.65
vite: 4.3.9(@types/node@18.16.18)
transitivePeerDependencies:
- '@swc/helpers'
@ -3777,8 +3777,8 @@ packages:
scheduler: 0.23.0
dev: false
/react-hook-form@7.44.3(react@18.2.0):
resolution: {integrity: sha512-/tHId6p2ViAka1wECMw8FEPn/oz/w226zehHrJyQ1oIzCBNMIJCaj6ZkQcv+MjDxYh9MWR7RQic7Qqwe4a5nkw==}
/react-hook-form@7.45.0(react@18.2.0):
resolution: {integrity: sha512-AbHeZ4ad+0dEIknSW9dBgIwcvRDfZ1O97sgj75WaMdOX0eg8TBiUf9wxzVkIjZbk76BBIE9lmFOzyD4PN80ZQg==}
engines: {node: '>=12.22.0'}
peerDependencies:
react: ^16.8.0 || ^17 || ^18
@ -4701,7 +4701,7 @@ packages:
vite: '>=2.8'
dependencies:
'@rollup/plugin-virtual': 3.0.1
'@swc/core': 1.3.64
'@swc/core': 1.3.65
uuid: 9.0.0
vite: 4.3.9(@types/node@18.16.18)
transitivePeerDependencies:

View File

@ -1,7 +1,6 @@
import { getNotesByAuthor } from "@libs/storage";
import { CancelIcon } from "@shared/icons";
import { NoteBase } from "@shared/notes/base";
import { NoteQuoteRepost } from "@shared/notes/quoteRepost";
import { Note } from "@shared/notes/note";
import { NoteSkeleton } from "@shared/notes/skeleton";
import { useActiveAccount } from "@stores/accounts";
import { useVirtualizer } from "@tanstack/react-virtual";
@ -101,35 +100,15 @@ export function FeedBlock({ params }: { params: any }) {
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
const note = notes[virtualRow.index];
if (note) {
if (note.kind === 1) {
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<NoteBase
key={note.event_id}
block={params.id}
event={note}
/>
</div>
);
} else {
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<NoteQuoteRepost
key={note.event_id}
block={params.id}
event={note}
/>
</div>
);
}
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<Note event={note} block={params.id} />
</div>
);
}
})}
</div>

View File

@ -1,7 +1,6 @@
import { createNote, getNotes } from "@libs/storage";
import { NDKEvent } from "@nostr-dev-kit/ndk";
import { NoteBase } from "@shared/notes/base";
import { NoteQuoteRepost } from "@shared/notes/quoteRepost";
import { Note } from "@shared/notes/note";
import { NoteSkeleton } from "@shared/notes/skeleton";
import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts";
@ -86,20 +85,11 @@ export function FollowingBlock({ block }: { block: number }) {
const note = notes[index];
if (!note) return;
if (note.kind === 1) {
return (
<div key={index} data-index={index} ref={rowVirtualizer.measureElement}>
<NoteBase block={block} event={note} />
</div>
);
} else {
return (
<div key={index} data-index={index} ref={rowVirtualizer.measureElement}>
<NoteQuoteRepost block={block} event={note} />
</div>
);
}
return (
<div key={index} data-index={index} ref={rowVirtualizer.measureElement}>
<Note event={note} block={block} />
</div>
);
};
return (

View File

@ -1,7 +1,7 @@
import { getNoteByID } from "@libs/storage";
import { ArrowLeftIcon } from "@shared/icons";
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 { NoteReplyForm } from "@shared/notes/replies/form";
import { RepliesList } from "@shared/notes/replies/list";

View File

@ -1,5 +1,4 @@
import { Profile } from "@app/trending/components/profile";
import { NoteBase } from "@shared/notes/base";
import { Note } from "@shared/notes/note";
import { NoteSkeleton } from "@shared/notes/skeleton";
import useSWR from "swr";
@ -30,7 +29,7 @@ export function TrendingNotes() {
) : (
<div className="relative w-full flex flex-col pt-1.5">
{data.notes.map((item) => (
<NoteBase key={item.id} event={item.event} metadata={false} />
<Note key={item.id} event={item.event} />
))}
</div>
)}

View File

@ -206,8 +206,8 @@ export async function createReplyNote(
) {
const db = await connect();
return await db.execute(
"INSERT OR IGNORE INTO replies (parent_id, event_id, pubkey, kind, tags, content, created_at) VALUES (?, ?, ?, ?, ?, ?, ?);",
[parent_id, event_id, pubkey, kind, tags, content, created_at],
"INSERT OR IGNORE INTO replies (event_id, parent_id, pubkey, kind, tags, content, created_at) VALUES (?, ?, ?, ?, ?, ?, ?);",
[event_id, parent_id, pubkey, kind, tags, content, created_at],
);
}

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>
);
});

View File

@ -80,7 +80,7 @@ export function isTagsIncludeID(id: string, arr: NDKTag[]) {
}
// get parent id from event tags
export function getQuoteID(arr: NDKTag[]) {
export function getRepostID(arr: NDKTag[]) {
const tags = destr(arr);
let quoteID = null;