initial support nip-23

This commit is contained in:
Ren Amamiya 2023-05-15 09:11:31 +07:00
parent 2b4d11182a
commit 180e31d1bd
9 changed files with 222 additions and 27 deletions

View File

@ -20,6 +20,15 @@ import { getParentID, nip02ToArray } from "@utils/transform";
import { useContext, useEffect, useRef } from "react";
import { navigate } from "vite-plugin-ssr/client/router";
function isJSON(str: string) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
export function Page() {
const pool: any = useContext(RelayContext);
const now = useRef(new Date());
@ -157,19 +166,23 @@ export function Page() {
);
break;
// long post
case 30023:
case 30023: {
// insert event to local database
createNote(
event.id,
account.id,
event.pubkey,
event.kind,
event.tags,
event.content,
event.created_at,
"",
);
const verifyMetadata = isJSON(event.tags);
if (verifyMetadata) {
createNote(
event.id,
account.id,
event.pubkey,
event.kind,
event.tags,
event.content,
event.created_at,
"",
);
}
break;
}
default:
break;
}

View File

@ -0,0 +1 @@
export { LayoutNewsfeed as Layout } from "./layout";

View File

@ -0,0 +1,11 @@
export function ThreadAuthor({
pubkey,
time,
}: { pubkey: string; time: number }) {
return (
<div>
<p>{pubkey}</p>
<span>{time}</span>
</div>
);
}

View File

@ -0,0 +1,21 @@
import { ThreadAuthor } from "@app/threads/components/author";
export function ThreadBase({ event }: { event: any }) {
const metadata = JSON.parse(event.metadata);
const title = metadata.find((i: any) => i[0] === "title")[1];
const summary = metadata.find((i: any) => i[0] === "summary")[1] || "";
return (
<div className="h-min w-full px-3 py-1.5">
<div className="rounded-md border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20">
<div className="px-3 py-3">
<h3>{title}</h3>
<p>{summary}</p>
</div>
<div className="inline-flex w-full justify-between items-center px-3 h-10">
<ThreadAuthor pubkey={event.pubkey} time={event.created_at} />
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,31 @@
import AppHeader from "@shared/appHeader";
import MultiAccounts from "@shared/multiAccounts";
import Navigation from "@shared/navigation";
export function LayoutNewsfeed({ children }: { children: React.ReactNode }) {
return (
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-zinc-950 dark:text-white">
<div className="flex h-screen w-full flex-col">
<div
data-tauri-drag-region
className="relative h-9 shrink-0 border-b border-zinc-100 bg-white dark:border-zinc-900 dark:bg-black"
>
<AppHeader />
</div>
<div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900">
<MultiAccounts />
</div>
<div className="grid w-full grid-cols-4 xl:grid-cols-5">
<div className="scrollbar-hide col-span-1 overflow-y-auto overflow-x-hidden border-r border-zinc-900">
<Navigation />
</div>
<div className="col-span-3 overflow-hidden xl:col-span-4">
{children}
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -1,7 +1,113 @@
import { NoteSkeleton } from "@app/note/components/skeleton";
import { ThreadBase } from "@app/threads/components/base";
import { useInfiniteQuery } from "@tanstack/react-query";
import { useVirtualizer } from "@tanstack/react-virtual";
import { getLongNotes } from "@utils/storage";
import { useEffect, useRef } from "react";
const ITEM_PER_PAGE = 10;
const TIME = Math.floor(Date.now() / 1000);
export function Page() {
const {
status,
error,
data,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
}: any = useInfiniteQuery({
queryKey: ["threads"],
queryFn: async ({ pageParam = 0 }) => {
return await getLongNotes(TIME, ITEM_PER_PAGE, pageParam);
},
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
const allRows = data ? data.pages.flatMap((d: { data: any }) => d.data) : [];
const parentRef = useRef();
const rowVirtualizer = useVirtualizer({
count: hasNextPage ? allRows.length + 1 : allRows.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 500,
overscan: 2,
});
const itemsVirtualizer = rowVirtualizer.getVirtualItems();
useEffect(() => {
const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
if (!lastItem) {
return;
}
if (
lastItem.index >= allRows.length - 1 &&
hasNextPage &&
!isFetchingNextPage
) {
fetchNextPage();
}
}, [fetchNextPage, allRows.length, rowVirtualizer.getVirtualItems()]);
return (
<div>
<p>MySpace</p>
<div
ref={parentRef}
className="scrollbar-hide flex h-full flex-col justify-between gap-1.5 overflow-y-auto"
style={{ contain: "strict" }}
>
{status === "loading" ? (
<div className="px-3 py-1.5">
<div className="rounded-md border border-zinc-800 bg-zinc-900 px-3 py-3 shadow-input shadow-black/20">
<NoteSkeleton />
</div>
</div>
) : status === "error" ? (
<div>{error.message}</div>
) : (
<div
className="relative w-full"
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
}}
>
<div
className="absolute left-0 top-0 w-full"
style={{
transform: `translateY(${
itemsVirtualizer[0].start - rowVirtualizer.options.scrollMargin
}px)`,
}}
>
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
const note = allRows[virtualRow.index];
if (note) {
return (
<div
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>
<ThreadBase key={note.event_id} event={note} />
</div>
);
}
})}
</div>
</div>
)}
<div>
{isFetching && !isFetchingNextPage ? (
<div className="px-3 py-1.5">
<div className="rounded-md border border-zinc-800 bg-zinc-900 px-3 py-3 shadow-input shadow-black/20">
<NoteSkeleton />
</div>
</div>
) : null}
</div>
</div>
);
}

View File

@ -55,7 +55,6 @@ export function Page() {
) {
fetchNextPage();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fetchNextPage, allRows.length, rowVirtualizer.getVirtualItems()]);
return (

View File

@ -14,6 +14,15 @@ import { useSetAtom } from "jotai";
import { useContext, useRef } from "react";
import useSWRSubscription from "swr/subscription";
function isJSON(str: string) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
export default function EventCollector() {
const pool: any = useContext(RelayContext);
@ -97,19 +106,23 @@ export default function EventCollector() {
);
break;
// long post
case 30023:
// insert event to local database
createNote(
event.id,
account.id,
event.pubkey,
event.kind,
event.tags,
event.content,
event.created_at,
"",
);
case 30023: {
const verifyMetadata = isJSON(event.tags);
if (verifyMetadata) {
// insert event to local database
createNote(
event.id,
account.id,
event.pubkey,
event.kind,
event.tags,
event.content,
event.created_at,
"",
);
}
break;
}
default:
break;
}

View File

@ -132,7 +132,7 @@ export async function getLongNotes(
const notes: any = { data: null, nextCursor: 0 };
const query: any = await db.select(
`SELECT * FROM notes WHERE created_at <= "${time}" AND kind = 30023 GROUP BY parent_id ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`,
`SELECT * FROM notes WHERE created_at <= "${time}" AND kind = 30023 ORDER BY created_at DESC LIMIT "${limit}" OFFSET "${offset}";`,
);
notes["data"] = query;