polish
This commit is contained in:
@@ -35,11 +35,11 @@ export function ArticleNote({ event }: { event: NDKEvent }) {
|
||||
<div className="mb-3 h-min w-full px-3">
|
||||
<div className="relative flex flex-col gap-2 overflow-hidden rounded-xl bg-neutral-50 pt-3 dark:bg-neutral-950">
|
||||
<User pubkey={event.pubkey} time={event.created_at} eventId={event.id} />
|
||||
<div>
|
||||
<div className="px-3">
|
||||
<Link
|
||||
to={`/notes/article/${event.id}`}
|
||||
preventScrollReset={true}
|
||||
className="flex w-full flex-col rounded-lg border border-neutral-200 bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900"
|
||||
className="flex w-full flex-col rounded-lg bg-neutral-100 dark:bg-neutral-900"
|
||||
>
|
||||
{metadata.image && (
|
||||
<img
|
||||
@@ -48,7 +48,7 @@ export function ArticleNote({ event }: { event: NDKEvent }) {
|
||||
className="h-56 w-full rounded-t-lg object-cover"
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col gap-1 rounded-b-lg bg-neutral-200 px-3 py-3 dark:bg-neutral-800">
|
||||
<div className="flex flex-col gap-1 rounded-b-lg rounded-t-lg bg-neutral-100 px-3 py-3 dark:bg-neutral-900">
|
||||
<h5 className="break-all font-semibold text-neutral-900 dark:text-neutral-100">
|
||||
{metadata.title}
|
||||
</h5>
|
||||
|
||||
@@ -6,7 +6,6 @@ export * from './child';
|
||||
export * from './notify';
|
||||
export * from './unknown';
|
||||
export * from './skeleton';
|
||||
export * from './stats';
|
||||
export * from './actions';
|
||||
export * from './actions/reaction';
|
||||
export * from './actions/reply';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { download } from '@tauri-apps/plugin-upload';
|
||||
import { SyntheticEvent } from 'react';
|
||||
import Zoom from 'react-medium-image-zoom';
|
||||
|
||||
import { DownloadIcon } from '@shared/icons';
|
||||
import { CancelIcon, DownloadIcon } from '@shared/icons';
|
||||
|
||||
export function ImagePreview({ url }: { url: string }) {
|
||||
const downloadImage = async (url: string) => {
|
||||
@@ -17,7 +17,7 @@ export function ImagePreview({ url }: { url: string }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<Zoom key={url} zoomMargin={50}>
|
||||
<Zoom key={url} zoomMargin={50} IconUnzoom={() => <CancelIcon className="h-4 w-4" />}>
|
||||
<div className="group relative mt-2">
|
||||
<img
|
||||
src={url}
|
||||
|
||||
@@ -49,7 +49,7 @@ export function LinkPreview({ url }: { url: string }) {
|
||||
<img
|
||||
src={data.image}
|
||||
alt={url}
|
||||
className="h-44 w-full rounded-t-lg bg-white object-cover"
|
||||
className="h-48 w-full rounded-t-lg bg-white object-cover"
|
||||
/>
|
||||
) : null}
|
||||
<div className="flex flex-col items-start px-3 py-3">
|
||||
|
||||
@@ -12,25 +12,15 @@ export function Reply({ event, root }: { event: NDKEventWithReplies; root?: stri
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<User pubkey={event.pubkey} time={event.created_at} eventId={event.id} />
|
||||
<MemoizedTextKind content={event.content} />
|
||||
<div className="-ml-1">
|
||||
<NoteActions
|
||||
id={event.id}
|
||||
pubkey={event.pubkey}
|
||||
root={root}
|
||||
extraButtons={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pl-4">
|
||||
<Collapsible.Root open={open} onOpenChange={setOpen}>
|
||||
{event.replies?.length > 0 ? (
|
||||
<div>
|
||||
<Collapsible.Root open={open} onOpenChange={setOpen}>
|
||||
<div className="rounded-xl bg-neutral-50 dark:bg-neutral-950">
|
||||
<div className="flex flex-col gap-2 pt-3">
|
||||
<User pubkey={event.pubkey} time={event.created_at} eventId={event.id} />
|
||||
<MemoizedTextKind content={event.content} />
|
||||
<div className="-ml-1 flex items-center justify-between">
|
||||
{event.replies?.length > 0 ? (
|
||||
<Collapsible.Trigger asChild>
|
||||
<div className="inline-flex h-10 items-center gap-1 font-semibold text-blue-500">
|
||||
<div className="ml-4 inline-flex h-14 items-center gap-1 font-semibold text-blue-500">
|
||||
<NavArrowDownIcon
|
||||
className={twMerge('h-3 w-3', open ? 'rotate-180 transform' : '')}
|
||||
/>
|
||||
@@ -39,13 +29,23 @@ export function Reply({ event, root }: { event: NDKEventWithReplies; root?: stri
|
||||
(event.replies?.length === 1 ? 'reply' : 'replies')}
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
{event.replies?.map((sub) => <SubReply key={sub.id} event={sub} />)}
|
||||
</Collapsible.Content>
|
||||
</div>
|
||||
) : null}
|
||||
<NoteActions
|
||||
id={event.id}
|
||||
pubkey={event.pubkey}
|
||||
root={root}
|
||||
extraButtons={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={twMerge('px-3', open ? 'pb-3' : '')}>
|
||||
{event.replies?.length > 0 ? (
|
||||
<Collapsible.Content>
|
||||
{event.replies?.map((sub) => <SubReply key={sub.id} event={sub} />)}
|
||||
</Collapsible.Content>
|
||||
) : null}
|
||||
</Collapsible.Root>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Collapsible.Root>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ export function ReplyList({ eventId }: { eventId: string }) {
|
||||
|
||||
return (
|
||||
<div className="mt-3 flex flex-col gap-5">
|
||||
<h3 className="font-semibold">Replies</h3>
|
||||
{data?.length === 0 ? (
|
||||
<div className="mt-2 flex w-full items-center justify-center">
|
||||
<div className="flex flex-col items-center justify-center gap-2 py-6">
|
||||
|
||||
@@ -5,7 +5,7 @@ import { User } from '@shared/user';
|
||||
|
||||
export function SubReply({ event }: { event: NDKEvent }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-col gap-2 rounded-lg bg-neutral-100 pt-3 dark:bg-neutral-900">
|
||||
<User pubkey={event.pubkey} time={event.created_at} eventId={event.id} />
|
||||
<MemoizedTextKind content={event.content} />
|
||||
<div className="-ml-1">
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { decode } from 'light-bolt11-decoder';
|
||||
|
||||
import { useNDK } from '@libs/ndk/provider';
|
||||
|
||||
import { LoaderIcon } from '@shared/icons';
|
||||
|
||||
import { compactNumber } from '@utils/number';
|
||||
|
||||
export function NoteStats({ id }: { id: string }) {
|
||||
const { ndk } = useNDK();
|
||||
const { status, data } = useQuery({
|
||||
queryKey: ['note-stats', id],
|
||||
queryFn: async () => {
|
||||
let reactions = 0;
|
||||
let reposts = 0;
|
||||
let zaps = 0;
|
||||
|
||||
const filter: NDKFilter = {
|
||||
'#e': [id],
|
||||
kinds: [6, 7, 9735],
|
||||
};
|
||||
|
||||
const events = await ndk.fetchEvents(filter);
|
||||
events.forEach((event: NDKEvent) => {
|
||||
switch (event.kind) {
|
||||
case 6:
|
||||
reposts += 1;
|
||||
break;
|
||||
case 7:
|
||||
reactions += 1;
|
||||
break;
|
||||
case 9735: {
|
||||
const bolt11 = event.tags.find((tag) => tag[0] === 'bolt11')[1];
|
||||
if (bolt11) {
|
||||
const decoded = decode(bolt11);
|
||||
const amount = decoded.sections.find((item) => item.name === 'amount');
|
||||
const sats = amount.value / 1000;
|
||||
zaps += sats;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return { reposts, reactions, zaps };
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
});
|
||||
|
||||
if (status === 'pending') {
|
||||
return (
|
||||
<div className="flex h-11 items-center">
|
||||
<LoaderIcon className="h-4 w-4 animate-spin text-white" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-3 flex w-full flex-wrap gap-2">
|
||||
<div className="flex flex-1 flex-col rounded-lg bg-neutral-100 px-3 py-2 dark:bg-neutral-900">
|
||||
<div className="text-lg font-semibold text-neutral-900 dark:text-neutral-100">
|
||||
{compactNumber.format(data.reactions)}
|
||||
</div>
|
||||
<div className="text-sm text-neutral-500 dark:text-neutral-300">Reactions</div>
|
||||
</div>
|
||||
<div className="flex flex-1 flex-col rounded-lg bg-neutral-100 px-3 py-2 dark:bg-neutral-900">
|
||||
<div className="text-lg font-semibold text-neutral-900 dark:text-neutral-100">
|
||||
{compactNumber.format(data.reposts)}
|
||||
</div>
|
||||
<div className="text-sm text-neutral-500 dark:text-neutral-300">Reposts</div>
|
||||
</div>
|
||||
<div className="flex flex-1 flex-col rounded-lg bg-neutral-100 px-3 py-2 dark:bg-neutral-900">
|
||||
<div className="text-lg font-semibold text-neutral-900 dark:text-neutral-100">
|
||||
{compactNumber.format(data.zaps)}
|
||||
</div>
|
||||
<div className="text-sm text-neutral-500 dark:text-neutral-300">Zaps</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user