mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-28 18:53:47 +01:00
add support for nevent and nprofile in note and user view
This commit is contained in:
parent
2f06d27819
commit
80eda9145a
5
.changeset/cold-emus-hope.md
Normal file
5
.changeset/cold-emus-hope.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"nostrudel": minor
|
||||
---
|
||||
|
||||
Add support for nprofile and nevent types in paths
|
14
src/app.tsx
14
src/app.tsx
@ -1,7 +1,7 @@
|
||||
import React, { Suspense, useEffect } from "react";
|
||||
import { createBrowserRouter, Navigate, Outlet, RouterProvider, useLocation } from "react-router-dom";
|
||||
import { Button, Flex, Spinner, Text, useColorMode } from "@chakra-ui/react";
|
||||
import { ErrorBoundary } from "./components/error-boundary";
|
||||
import { ErrorBoundary, ErrorFallback } from "./components/error-boundary";
|
||||
import { Page } from "./components/page";
|
||||
import { normalizeToHex } from "./helpers/nip19";
|
||||
import { deleteDatabase } from "./services/db";
|
||||
@ -87,12 +87,6 @@ const router = createBrowserRouter([
|
||||
children: [
|
||||
{
|
||||
path: "/u/:pubkey",
|
||||
loader: ({ params }) => {
|
||||
if (!params.pubkey) throw new Error("Missing pubkey");
|
||||
const hexKey = normalizeToHex(params.pubkey);
|
||||
if (!hexKey) throw new Error(params.pubkey + " is not a valid pubkey");
|
||||
return { pubkey: hexKey };
|
||||
},
|
||||
element: <UserView />,
|
||||
children: [
|
||||
{ path: "", element: <UserNotesTab /> },
|
||||
@ -106,12 +100,6 @@ const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: "/n/:id",
|
||||
loader: ({ params }) => {
|
||||
if (!params.id) throw new Error("Missing pubkey");
|
||||
const hex = normalizeToHex(params.id);
|
||||
if (!hex) throw new Error(params.id + " is not a valid event id");
|
||||
return { id: hex };
|
||||
},
|
||||
element: <NoteView />,
|
||||
},
|
||||
{ path: "settings", element: <SettingsView /> },
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Toast,
|
||||
useDisclosure,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
|
@ -9,8 +9,8 @@ type Options = {
|
||||
enabled?: boolean;
|
||||
};
|
||||
|
||||
export function useThreadLoader(eventId: string, opts?: Options) {
|
||||
const relays = useReadRelayUrls();
|
||||
export function useThreadLoader(eventId: string, additionalRelays: string[] = [], opts?: Options) {
|
||||
const relays = useReadRelayUrls(additionalRelays);
|
||||
|
||||
const ref = useRef<ThreadLoader | null>(null);
|
||||
const loader = (ref.current = ref.current || new ThreadLoader(relays, eventId));
|
||||
|
@ -1,41 +1,6 @@
|
||||
import { Alert, AlertIcon, AlertTitle, Spinner } from "@chakra-ui/react";
|
||||
import { Alert, AlertIcon, AlertTitle } from "@chakra-ui/react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { Kind, nip19 } from "nostr-tools";
|
||||
import { useUserMetadata } from "../../hooks/use-user-metadata";
|
||||
import useSingleEvent from "../../hooks/use-single-event";
|
||||
import { useReadRelayUrls } from "../../hooks/use-client-relays";
|
||||
import { EventPointer, ProfilePointer } from "nostr-tools/lib/nip19";
|
||||
|
||||
export function NpubLinkHandler({ pubkey, relays }: { pubkey: string; relays?: string[] }) {
|
||||
const readRelays = useReadRelayUrls(relays);
|
||||
const metadata = useUserMetadata(pubkey, readRelays);
|
||||
if (!metadata) return <Spinner />;
|
||||
return <Navigate to={`/u/${pubkey}`} replace />;
|
||||
}
|
||||
|
||||
export function NoteLinkHandler({ eventId, relays }: { eventId: string; relays?: string[] }) {
|
||||
const readRelays = useReadRelayUrls(relays);
|
||||
const { event, loading } = useSingleEvent(eventId, readRelays);
|
||||
if (loading) return <Spinner />;
|
||||
|
||||
if (!event)
|
||||
return (
|
||||
<Alert status="error">
|
||||
<AlertIcon />
|
||||
<AlertTitle>Failed to find event</AlertTitle>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
if (event.kind !== Kind.Text && event.kind !== 6)
|
||||
return (
|
||||
<Alert status="error">
|
||||
<AlertIcon />
|
||||
<AlertTitle>Cant handle event kind {event.kind}</AlertTitle>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
return <Navigate to={`/n/${eventId}`} replace />;
|
||||
}
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
export default function NostrLinkView() {
|
||||
const { link } = useParams() as { link?: string };
|
||||
@ -51,15 +16,13 @@ export default function NostrLinkView() {
|
||||
const cleanLink = link.replace(/(web\+)?nostr:/, "");
|
||||
const decoded = nip19.decode(cleanLink);
|
||||
|
||||
if (decoded.type === "npub") return <NpubLinkHandler pubkey={decoded.data as string} />;
|
||||
if (decoded.type === "nprofile") {
|
||||
const data = decoded.data as ProfilePointer;
|
||||
return <NpubLinkHandler pubkey={data.pubkey} relays={data.relays} />;
|
||||
}
|
||||
if (decoded.type === "note") return <NoteLinkHandler eventId={decoded.data as string} />;
|
||||
if (decoded.type === "nevent") {
|
||||
const data = decoded.data as EventPointer;
|
||||
return <NoteLinkHandler eventId={data.id} relays={data.relays} />;
|
||||
switch (decoded.type) {
|
||||
case "npub":
|
||||
case "nprofile":
|
||||
return <Navigate to={`/u/${cleanLink}`} replace />;
|
||||
case "note":
|
||||
case "nevent":
|
||||
return <Navigate to={`/n/${cleanLink}`} replace />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,13 +1,33 @@
|
||||
import { Flex, Spinner } from "@chakra-ui/react";
|
||||
import { useLoaderData } from "react-router-dom";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Note } from "../../components/note";
|
||||
import { isHex } from "../../helpers/nip19";
|
||||
import { useThreadLoader } from "../../hooks/use-thread-loader";
|
||||
import { ThreadPost } from "./thread-post";
|
||||
|
||||
const NoteView = () => {
|
||||
const { id } = useLoaderData() as { id: string };
|
||||
function useNotePointer() {
|
||||
const { id } = useParams() as { id: string };
|
||||
if (isHex(id)) return { id, relays: [] };
|
||||
const pointer = nip19.decode(id);
|
||||
|
||||
const { thread, events, rootId, focusId, loading } = useThreadLoader(id, { enabled: !!id });
|
||||
switch (pointer.type) {
|
||||
case "note":
|
||||
return { id: pointer.data as string, relays: [] };
|
||||
case "nevent":
|
||||
const p = pointer.data as nip19.EventPointer;
|
||||
return { id: p.id, relays: p.relays ?? [] };
|
||||
default:
|
||||
throw new Error(`Unknown type ${pointer.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
const NoteView = () => {
|
||||
const pointer = useNotePointer();
|
||||
|
||||
const { thread, events, rootId, focusId, loading } = useThreadLoader(pointer.id, pointer.relays, {
|
||||
enabled: !!pointer.id,
|
||||
});
|
||||
if (loading) return <Spinner />;
|
||||
|
||||
let pageContent = <span>Missing Event</span>;
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Flex, Image, Spinner, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
|
||||
import { Outlet, useLoaderData, useMatches, useNavigate } from "react-router-dom";
|
||||
import { Flex, Spinner, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
|
||||
import { Outlet, useMatches, useNavigate, useParams } from "react-router-dom";
|
||||
import { useUserMetadata } from "../../hooks/use-user-metadata";
|
||||
import { getUserDisplayName } from "../../helpers/user-metadata";
|
||||
import { useIsMobile } from "../../hooks/use-is-mobile";
|
||||
import { Bech32Prefix, normalizeToBech32 } from "../../helpers/nip19";
|
||||
import { Bech32Prefix, isHex, normalizeToBech32 } from "../../helpers/nip19";
|
||||
import { useAppTitle } from "../../hooks/use-app-title";
|
||||
import Header from "./components/header";
|
||||
import { Suspense } from "react";
|
||||
@ -12,6 +12,8 @@ import { useReadRelayUrls } from "../../hooks/use-client-relays";
|
||||
import relayScoreboardService from "../../services/relay-scoreboard";
|
||||
import { RelayMode } from "../../classes/relay";
|
||||
import { AdditionalRelayProvider } from "../../providers/additional-relay-context";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { unique } from "../../helpers/array";
|
||||
|
||||
const tabs = [
|
||||
{ label: "Notes", path: "notes" },
|
||||
@ -22,6 +24,22 @@ const tabs = [
|
||||
{ label: "Reports", path: "reports" },
|
||||
];
|
||||
|
||||
function useUserPointer() {
|
||||
const { pubkey } = useParams() as { pubkey: string };
|
||||
if (isHex(pubkey)) return { pubkey, relays: [] };
|
||||
const pointer = nip19.decode(pubkey);
|
||||
|
||||
switch (pointer.type) {
|
||||
case "npub":
|
||||
return { pubkey: pointer.data as string, relays: [] };
|
||||
case "nprofile":
|
||||
const d = pointer.data as nip19.ProfilePointer;
|
||||
return { pubkey: d.pubkey, relays: d.relays ?? [] };
|
||||
default:
|
||||
throw new Error(`Unknown type ${pointer.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
function useUserTop4Relays(pubkey: string) {
|
||||
// get user relays
|
||||
const userRelays = useFallbackUserRelays(pubkey)
|
||||
@ -34,9 +52,9 @@ function useUserTop4Relays(pubkey: string) {
|
||||
}
|
||||
|
||||
const UserView = () => {
|
||||
const { pubkey, relays: pointerRelays } = useUserPointer();
|
||||
const isMobile = useIsMobile();
|
||||
const navigate = useNavigate();
|
||||
const { pubkey } = useLoaderData() as { pubkey: string };
|
||||
const userTopRelays = useUserTop4Relays(pubkey);
|
||||
|
||||
const matches = useMatches();
|
||||
@ -50,7 +68,7 @@ const UserView = () => {
|
||||
useAppTitle(getUserDisplayName(metadata, npub ?? pubkey));
|
||||
|
||||
return (
|
||||
<AdditionalRelayProvider relays={userTopRelays}>
|
||||
<AdditionalRelayProvider relays={unique([...userTopRelays, ...pointerRelays])}>
|
||||
<Flex direction="column" alignItems="stretch" gap="2" overflow={isMobile ? "auto" : "hidden"} height="100%">
|
||||
{/* {metadata?.banner && <Image src={metadata.banner} mb={-120} />} */}
|
||||
<Header pubkey={pubkey} />
|
||||
|
Loading…
x
Reference in New Issue
Block a user