mirror of
https://github.com/lumehq/lume.git
synced 2025-03-29 03:02:14 +01:00
finish relay manegament screen
This commit is contained in:
parent
11ed618a7f
commit
674e5f0339
@ -1,29 +1,84 @@
|
|||||||
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
|
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { VList } from 'virtua';
|
||||||
|
|
||||||
import { useNDK } from '@libs/ndk/provider';
|
import { useNDK } from '@libs/ndk/provider';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ArticleNote,
|
||||||
|
FileNote,
|
||||||
|
NoteWrapper,
|
||||||
|
Repost,
|
||||||
|
TextNote,
|
||||||
|
UnknownNote,
|
||||||
|
} from '@shared/notes';
|
||||||
|
|
||||||
export function RelayEventList({ relayUrl }: { relayUrl: string }) {
|
export function RelayEventList({ relayUrl }: { relayUrl: string }) {
|
||||||
const { fetcher } = useNDK();
|
const { fetcher } = useNDK();
|
||||||
const { status, data } = useQuery(
|
const { status, data } = useQuery(
|
||||||
['relay-event'],
|
['relay-event'],
|
||||||
async () => {
|
async () => {
|
||||||
|
const url = 'wss://' + relayUrl;
|
||||||
const events = await fetcher.fetchLatestEvents(
|
const events = await fetcher.fetchLatestEvents(
|
||||||
[relayUrl],
|
[url],
|
||||||
{
|
{
|
||||||
kinds: [NDKKind.Text, NDKKind.Repost, 1063, NDKKind.Article],
|
kinds: [NDKKind.Text, NDKKind.Repost, 1063, NDKKind.Article],
|
||||||
},
|
},
|
||||||
100
|
100
|
||||||
);
|
);
|
||||||
|
|
||||||
return events as unknown as NDKEvent[];
|
return events as unknown as NDKEvent[];
|
||||||
},
|
},
|
||||||
{ refetchOnWindowFocus: false }
|
{ refetchOnWindowFocus: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
(event: NDKEvent) => {
|
||||||
|
switch (event.kind) {
|
||||||
|
case NDKKind.Text:
|
||||||
|
return (
|
||||||
|
<NoteWrapper key={event.id} event={event}>
|
||||||
|
<TextNote />
|
||||||
|
</NoteWrapper>
|
||||||
|
);
|
||||||
|
case NDKKind.Repost:
|
||||||
|
return <Repost key={event.id} event={event} />;
|
||||||
|
case 1063:
|
||||||
|
return (
|
||||||
|
<NoteWrapper key={event.id} event={event}>
|
||||||
|
<FileNote />
|
||||||
|
</NoteWrapper>
|
||||||
|
);
|
||||||
|
case NDKKind.Article:
|
||||||
|
return (
|
||||||
|
<NoteWrapper key={event.id} event={event}>
|
||||||
|
<ArticleNote />
|
||||||
|
</NoteWrapper>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<NoteWrapper key={event.id} event={event}>
|
||||||
|
<UnknownNote />
|
||||||
|
</NoteWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[data]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="h-full">
|
||||||
<p>TODO</p>
|
<div className="mx-auto w-full max-w-[500px]">
|
||||||
|
{status === 'loading' ? (
|
||||||
|
<div>Loading...</div>
|
||||||
|
) : (
|
||||||
|
<VList className="scrollbar-hide h-full">
|
||||||
|
<div className="h-10" />
|
||||||
|
{data.map((item) => renderItem(item))}
|
||||||
|
<div className="h-16" />
|
||||||
|
</VList>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,12 @@ export function RelayList() {
|
|||||||
async () => {
|
async () => {
|
||||||
return await getAllRelaysByUsers();
|
return await getAllRelaysByUsers();
|
||||||
},
|
},
|
||||||
{ refetchOnWindowFocus: false }
|
{
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
refetchOnMount: false,
|
||||||
|
refetchOnReconnect: false,
|
||||||
|
staleTime: Infinity,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const inspectRelay = (relayUrl: string) => {
|
const inspectRelay = (relayUrl: string) => {
|
||||||
|
@ -1,14 +1,39 @@
|
|||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
import { Await, useLoaderData } from 'react-router-dom';
|
import { Await, useLoaderData, useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { LoaderIcon } from '@shared/icons';
|
import { ArrowLeftIcon, LoaderIcon } from '@shared/icons';
|
||||||
|
import { User } from '@shared/user';
|
||||||
|
|
||||||
|
import { RelayEventList } from './components/relayEventList';
|
||||||
|
|
||||||
export function RelayScreen() {
|
export function RelayScreen() {
|
||||||
|
const { url } = useParams();
|
||||||
|
|
||||||
const data: { relay?: { [key: string]: string } } = useLoaderData();
|
const data: { relay?: { [key: string]: string } } = useLoaderData();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const getSoftwareName = (url: string) => {
|
||||||
|
const filename = url.substring(url.lastIndexOf('/') + 1);
|
||||||
|
return filename.replace('.git', '');
|
||||||
|
};
|
||||||
|
|
||||||
|
const titleCase = (s: string) => {
|
||||||
|
return s
|
||||||
|
.replace(/^[-_]*(.)/, (_, c) => c.toUpperCase())
|
||||||
|
.replace(/[-_]+(.)/g, (_, c) => ' ' + c.toUpperCase());
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid h-full w-full grid-cols-3">
|
<div className="grid h-full w-full grid-cols-3">
|
||||||
<div className="col-span-2 border-r border-white/5"></div>
|
<div className="col-span-2 border-r border-white/5">
|
||||||
|
<div className="inline-flex h-16 w-full items-center gap-2.5 border-b border-white/5 px-3">
|
||||||
|
<button type="button" onClick={() => navigate(-1)}>
|
||||||
|
<ArrowLeftIcon className="h-5 w-5 text-white/70 hover:text-white" />
|
||||||
|
</button>
|
||||||
|
<h3 className="font-semibold text-white">Global events</h3>
|
||||||
|
</div>
|
||||||
|
<RelayEventList relayUrl={url} />
|
||||||
|
</div>
|
||||||
<div className="col-span-1">
|
<div className="col-span-1">
|
||||||
<div className="inline-flex h-16 w-full items-center border-b border-white/5 px-3">
|
<div className="inline-flex h-16 w-full items-center border-b border-white/5 px-3">
|
||||||
<h3 className="font-semibold text-white">Information</h3>
|
<h3 className="font-semibold text-white">Information</h3>
|
||||||
@ -31,25 +56,104 @@ export function RelayScreen() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{(resolvedRelay) => (
|
{(resolvedRelay) => (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-5">
|
||||||
<p>
|
<div>
|
||||||
<span className="font-semibold">Name</span> : {resolvedRelay.name}
|
<h3 className="font-semibold leading-tight text-white">
|
||||||
</p>
|
{resolvedRelay.name}
|
||||||
<p>
|
</h3>
|
||||||
<span className="font-semibold">Description</span> :{' '}
|
<p className="text-sm font-medium text-white/70">
|
||||||
{resolvedRelay.description}
|
{resolvedRelay.description}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
</div>
|
||||||
<span className="font-semibold">Contact</span> :{' '}
|
{resolvedRelay.pubkey ? (
|
||||||
{resolvedRelay.contact}
|
<div className="flex flex-col gap-1">
|
||||||
</p>
|
<h5 className="text-sm font-semibold text-white/70">Owner:</h5>
|
||||||
<p>
|
<div className="w-full rounded-lg bg-white/10 px-2 py-2">
|
||||||
<span className="font-semibold">Software</span> : [open website]
|
<User pubkey={resolvedRelay.pubkey} variant="simple" />
|
||||||
</p>
|
</div>
|
||||||
<p>
|
</div>
|
||||||
<span className="font-semibold">Version</span> :{' '}
|
) : null}
|
||||||
{resolvedRelay.version}
|
{resolvedRelay.contact ? (
|
||||||
</p>
|
<div>
|
||||||
|
<h5 className="text-sm font-semibold text-white/70">Contact:</h5>
|
||||||
|
<a
|
||||||
|
href={`mailto:${resolvedRelay.contact}`}
|
||||||
|
target="_blank"
|
||||||
|
className="underline after:content-['_↗'] hover:text-fuchsia-500"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
mailto:{resolvedRelay.contact}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div>
|
||||||
|
<h5 className="text-sm font-semibold text-white/70">Software:</h5>
|
||||||
|
<a
|
||||||
|
href={resolvedRelay.software}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="underline after:content-['_↗'] hover:text-fuchsia-500"
|
||||||
|
>
|
||||||
|
{getSoftwareName(resolvedRelay.software) +
|
||||||
|
' - ' +
|
||||||
|
resolvedRelay.version}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h5 className="text-sm font-semibold text-white/70">
|
||||||
|
Supported NIPs:
|
||||||
|
</h5>
|
||||||
|
<div className="mt-2 grid grid-cols-7 gap-2">
|
||||||
|
{resolvedRelay.supported_nips.map((item: string) => (
|
||||||
|
<a
|
||||||
|
key={item}
|
||||||
|
href={`https://nips.be/${item}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex aspect-square h-full w-full items-center justify-center rounded-lg bg-white/10 text-sm font-medium hover:bg-fuchsia-500"
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{resolvedRelay.limitation ? (
|
||||||
|
<div>
|
||||||
|
<h5 className="text-sm font-semibold text-white/70">Limitation</h5>
|
||||||
|
<div className="flex flex-col gap-2 divide-y divide-white/5">
|
||||||
|
{Object.keys(resolvedRelay.limitation).map((key, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex items-baseline justify-between pt-2"
|
||||||
|
>
|
||||||
|
<p className="text-sm font-medium text-white">
|
||||||
|
{titleCase(key)}:
|
||||||
|
</p>
|
||||||
|
<p className="text-sm font-medium text-white/70">
|
||||||
|
{resolvedRelay.limitation[key].toString()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{resolvedRelay.payments_url ? (
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<a
|
||||||
|
href={resolvedRelay.payments_url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex h-10 w-full items-center justify-center rounded-lg bg-fuchsia-500 text-sm font-medium hover:bg-fuchsia-600"
|
||||||
|
>
|
||||||
|
Open payment website
|
||||||
|
</a>
|
||||||
|
<span className="text-center text-xs text-white/70">
|
||||||
|
You need to make a payment to connect this relay
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Await>
|
</Await>
|
||||||
|
@ -277,7 +277,7 @@ export const User = memo(function User({
|
|||||||
<HoverCard.Root>
|
<HoverCard.Root>
|
||||||
<div className="relative z-10 flex items-start gap-3">
|
<div className="relative z-10 flex items-start gap-3">
|
||||||
<HoverCard.Trigger asChild>
|
<HoverCard.Trigger asChild>
|
||||||
<Avatar.Root className="shrink-0">
|
<Avatar.Root className="h-10 w-10 shrink-0">
|
||||||
<Avatar.Image
|
<Avatar.Image
|
||||||
src={user?.picture || user?.image}
|
src={user?.picture || user?.image}
|
||||||
alt={pubkey}
|
alt={pubkey}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user