update threads (kind 30023) page

This commit is contained in:
Ren Amamiya
2023-05-16 09:56:24 +07:00
parent 180e31d1bd
commit 7e8e5a931b
4 changed files with 77 additions and 13 deletions

View File

@@ -1,8 +1,15 @@
import { useProfile } from "@utils/hooks/useProfile"; import { useProfile } from "@utils/hooks/useProfile";
import { shortenKey } from "@utils/shortenKey"; import { shortenKey } from "@utils/shortenKey";
const hexRegex = /[0-9A-Fa-f]{6}/g;
export function MentionUser(props: { children: any[] }) { export function MentionUser(props: { children: any[] }) {
const pubkey = props.children[0]; const pubkey = props.children[0].match(hexRegex) ? props.children[0] : null;
if (!pubkey) {
return null;
}
const { user } = useProfile(pubkey); const { user } = useProfile(pubkey);
return ( return (

View File

@@ -1,11 +1,40 @@
import { Image } from "@shared/image";
import { DEFAULT_AVATAR, IMGPROXY_URL } from "@stores/constants";
import { useProfile } from "@utils/hooks/useProfile";
import { shortenKey } from "@utils/shortenKey";
import dayjs from "dayjs";
export function ThreadAuthor({ export function ThreadAuthor({
pubkey, pubkey,
time, time,
}: { pubkey: string; time: number }) { }: { pubkey: string; time: number }) {
const { user } = useProfile(pubkey);
return ( return (
<div> <div className="relative flex items-center gap-2.5">
<p>{pubkey}</p> <div className="h-9 w-9 shrink-0 overflow-hidden rounded-md bg-zinc-900">
<span>{time}</span> <Image
src={`${IMGPROXY_URL}/rs:fit:100:100/plain/${
user?.picture ? user.picture : DEFAULT_AVATAR
}`}
alt={pubkey}
className="h-9 w-9 object-cover"
/>
</div>
<div className="flex w-full flex-1 items-start justify-between">
<div className="flex flex-col gap-0.5">
<h5 className="text-sm font-semibold leading-none">
{user?.display_name || user?.name || (
<div className="h-3 w-20 animate-pulse rounded-sm bg-zinc-700" />
)}
</h5>
<div className="flex items-baseline gap-1.5 text-sm leading-none text-zinc-500">
<span>{user?.nip05 || shortenKey(pubkey)}</span>
<span></span>
<span>{dayjs().to(dayjs.unix(time), true)}</span>
</div>
</div>
</div>
</div> </div>
); );
} }

View File

@@ -1,18 +1,37 @@
import { ThreadAuthor } from "@app/threads/components/author"; import { ThreadAuthor } from "@app/threads/components/author";
import { Image } from "@shared/image";
export function ThreadBase({ event }: { event: any }) { export function ThreadBase({ event }: { event: any }) {
const metadata = JSON.parse(event.metadata); const metadata = JSON.parse(event.tags);
const title = metadata.find((i: any) => i[0] === "title")[1]; const title = metadata.find((i: any) => i[0] === "title")?.[1];
const summary = metadata.find((i: any) => i[0] === "summary")[1] || ""; const summary = metadata.find((i: any) => i[0] === "summary")?.[1];
const image = metadata.find((i: any) => i[0] === "image")?.[1];
if (!title) {
return null;
}
return ( return (
<div className="h-min w-full px-3 py-1.5"> <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="rounded-md border border-zinc-800 bg-zinc-900 shadow-input shadow-black/20">
<div className="px-3 py-3"> <div className="px-3 py-3">
<h3>{title}</h3> <div className="flex flex-row gap-2">
<div className="flex-1">
<h3 className="text-zinc-100 text-xl font-semibold">{title}</h3>
<div className="mt-2 prose prose-zinc max-w-none select-text break-words dark:prose-invert prose-p:text-[15px] prose-p:leading-tight prose-a:text-[15px] prose-a:font-normal prose-a:leading-tight prose-a:text-fuchsia-500 prose-a:no-underline hover:prose-a:text-fuchsia-600 hover:prose-a:underline prose-ol:mb-1 prose-ul:mb-1 prose-li:text-[15px] prose-li:leading-tight">
<p>{summary}</p> <p>{summary}</p>
</div> </div>
<div className="inline-flex w-full justify-between items-center px-3 h-10"> </div>
<div className="shrink-0 w-32 h-32">
<Image
src={image}
alt={title}
className="w-32 h-32 rounded-md object-cover"
/>
</div>
</div>
</div>
<div className="inline-flex border-t border-zinc-800 w-full justify-between items-center px-3 h-16">
<ThreadAuthor pubkey={event.pubkey} time={event.created_at} /> <ThreadAuthor pubkey={event.pubkey} time={event.created_at} />
</div> </div>
</div> </div>

View File

@@ -8,6 +8,15 @@ import { useEffect, useRef } from "react";
const ITEM_PER_PAGE = 10; const ITEM_PER_PAGE = 10;
const TIME = Math.floor(Date.now() / 1000); const TIME = Math.floor(Date.now() / 1000);
function isJSON(str: string) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
export function Page() { export function Page() {
const { const {
status, status,
@@ -56,7 +65,7 @@ export function Page() {
return ( return (
<div <div
ref={parentRef} ref={parentRef}
className="scrollbar-hide flex h-full flex-col justify-between gap-1.5 overflow-y-auto" className="scrollbar-hide h-full overflow-y-auto"
style={{ contain: "strict" }} style={{ contain: "strict" }}
> >
{status === "loading" ? ( {status === "loading" ? (
@@ -69,7 +78,7 @@ export function Page() {
<div>{error.message}</div> <div>{error.message}</div>
) : ( ) : (
<div <div
className="relative w-full" className="relative w-full mt-2"
style={{ style={{
height: `${rowVirtualizer.getTotalSize()}px`, height: `${rowVirtualizer.getTotalSize()}px`,
}} }}
@@ -84,7 +93,7 @@ export function Page() {
> >
{rowVirtualizer.getVirtualItems().map((virtualRow) => { {rowVirtualizer.getVirtualItems().map((virtualRow) => {
const note = allRows[virtualRow.index]; const note = allRows[virtualRow.index];
if (note) { if (note && isJSON(note.tags)) {
return ( return (
<div <div
key={virtualRow.index} key={virtualRow.index}