mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-09-18 11:32:30 +02:00
Merge branch 'next' into things
This commit is contained in:
5
.changeset/small-comics-try.md
Normal file
5
.changeset/small-comics-try.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"nostrudel": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add NIP definitions when hovering over "NIP-xx"
|
@@ -1,4 +1,4 @@
|
|||||||
import { Link } from "@chakra-ui/react";
|
import { Link, Text, Tooltip } from "@chakra-ui/react";
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
|
|
||||||
import { EmbedableContent, embedJSX } from "../../helpers/embeds";
|
import { EmbedableContent, embedJSX } from "../../helpers/embeds";
|
||||||
@@ -7,6 +7,7 @@ import UserLink from "../user-link";
|
|||||||
import { getMatchHashtag, getMatchNostrLink, stripInvisibleChar } from "../../helpers/regexp";
|
import { getMatchHashtag, getMatchNostrLink, stripInvisibleChar } from "../../helpers/regexp";
|
||||||
import { safeDecode } from "../../helpers/nip19";
|
import { safeDecode } from "../../helpers/nip19";
|
||||||
import { EmbedEventPointer } from "../embed-event";
|
import { EmbedEventPointer } from "../embed-event";
|
||||||
|
import { NIP_NAMES } from "../../views/relays/components/supported-nips";
|
||||||
|
|
||||||
// nostr:nevent1qqsthg2qlxp9l7egtwa92t8lusm7pjknmjwa75ctrrpcjyulr9754fqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq36amnwvaz7tmwdaehgu3dwp6kytnhv4kxcmmjv3jhytnwv46q2qg5q9
|
// nostr:nevent1qqsthg2qlxp9l7egtwa92t8lusm7pjknmjwa75ctrrpcjyulr9754fqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq36amnwvaz7tmwdaehgu3dwp6kytnhv4kxcmmjv3jhytnwv46q2qg5q9
|
||||||
// nostr:nevent1qqsq3wc73lqxd70lg43m5rul57d4mhcanttjat56e30yx5zla48qzlspz9mhxue69uhkummnw3e82efwvdhk6qgdwaehxw309ahx7uewd3hkcq5hsum
|
// nostr:nevent1qqsq3wc73lqxd70lg43m5rul57d4mhcanttjat56e30yx5zla48qzlspz9mhxue69uhkummnw3e82efwvdhk6qgdwaehxw309ahx7uewd3hkcq5hsum
|
||||||
@@ -93,3 +94,22 @@ export function embedNostrHashtags(content: EmbedableContent, event: NostrEvent
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function embedNipDefinitions(content: EmbedableContent) {
|
||||||
|
return embedJSX(content, {
|
||||||
|
name: "nip-definition",
|
||||||
|
regexp: /nip-?(\d\d)/gi,
|
||||||
|
render: (match) => {
|
||||||
|
if (NIP_NAMES[match[1]]) {
|
||||||
|
return (
|
||||||
|
<Tooltip label={NIP_NAMES[match[1]]} aria-label="NIP Definition">
|
||||||
|
<Text as="abbr" title={NIP_NAMES[match[1]]}>
|
||||||
|
{match[0]}
|
||||||
|
</Text>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@@ -26,6 +26,7 @@ import {
|
|||||||
renderSoundCloudUrl,
|
renderSoundCloudUrl,
|
||||||
renderSimpleXLink,
|
renderSimpleXLink,
|
||||||
renderRedditUrl,
|
renderRedditUrl,
|
||||||
|
embedNipDefinitions,
|
||||||
} from "../embed-types";
|
} from "../embed-types";
|
||||||
import { LightboxProvider } from "../lightbox-provider";
|
import { LightboxProvider } from "../lightbox-provider";
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ function buildContents(event: NostrEvent | DraftNostrEvent, simpleLinks = false)
|
|||||||
content = embedNostrLinks(content);
|
content = embedNostrLinks(content);
|
||||||
content = embedNostrMentions(content, event);
|
content = embedNostrMentions(content, event);
|
||||||
content = embedNostrHashtags(content, event);
|
content = embedNostrHashtags(content, event);
|
||||||
|
content = embedNipDefinitions(content);
|
||||||
content = embedEmoji(content, event);
|
content = embedEmoji(content, event);
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
|
@@ -47,6 +47,7 @@ import useCurrentAccount from "../../hooks/use-current-account";
|
|||||||
import useCacheForm from "../../hooks/use-cache-form";
|
import useCacheForm from "../../hooks/use-cache-form";
|
||||||
import { useAdditionalRelayContext } from "../../providers/additional-relay-context";
|
import { useAdditionalRelayContext } from "../../providers/additional-relay-context";
|
||||||
import { useTextAreaUploadFileWithForm } from "../../hooks/use-textarea-upload-file";
|
import { useTextAreaUploadFileWithForm } from "../../hooks/use-textarea-upload-file";
|
||||||
|
import { useThrottle } from "react-use";
|
||||||
|
|
||||||
type FormValues = {
|
type FormValues = {
|
||||||
subject: string;
|
subject: string;
|
||||||
@@ -147,6 +148,8 @@ export default function PostModal({
|
|||||||
const canSubmit = getValues().content.length > 0;
|
const canSubmit = getValues().content.length > 0;
|
||||||
const mentions = getContentMentions(correctContentMentions(getValues().content));
|
const mentions = getContentMentions(correctContentMentions(getValues().content));
|
||||||
|
|
||||||
|
const previewDraft = useThrottle(getDraft(), 500);
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (publishAction) {
|
if (publishAction) {
|
||||||
return (
|
return (
|
||||||
@@ -176,12 +179,12 @@ export default function PostModal({
|
|||||||
if (e.ctrlKey && e.key === "Enter") submit();
|
if (e.ctrlKey && e.key === "Enter") submit();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{getValues().content.length > 0 && (
|
{previewDraft.content.length > 0 && (
|
||||||
<Box>
|
<Box>
|
||||||
<Heading size="sm">Preview:</Heading>
|
<Heading size="sm">Preview:</Heading>
|
||||||
<Box borderWidth={1} borderRadius="md" p="2">
|
<Box borderWidth={1} borderRadius="md" p="2">
|
||||||
<TrustProvider trust>
|
<TrustProvider trust>
|
||||||
<NoteContents event={getDraft()} />
|
<NoteContents event={previewDraft} />
|
||||||
</TrustProvider>
|
</TrustProvider>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
@@ -9,6 +9,7 @@ import {
|
|||||||
embedEmoji,
|
embedEmoji,
|
||||||
embedImageGallery,
|
embedImageGallery,
|
||||||
embedLightningInvoice,
|
embedLightningInvoice,
|
||||||
|
embedNipDefinitions,
|
||||||
embedNostrHashtags,
|
embedNostrHashtags,
|
||||||
embedNostrLinks,
|
embedNostrLinks,
|
||||||
embedNostrMentions,
|
embedNostrMentions,
|
||||||
@@ -64,6 +65,7 @@ const ChannelMessageContent = memo(({ message, children, ...props }: BoxProps &
|
|||||||
c = embedNostrLinks(c);
|
c = embedNostrLinks(c);
|
||||||
c = embedNostrMentions(c, message);
|
c = embedNostrMentions(c, message);
|
||||||
c = embedNostrHashtags(c, message);
|
c = embedNostrHashtags(c, message);
|
||||||
|
c = embedNipDefinitions(c);
|
||||||
c = embedEmoji(c, message);
|
c = embedEmoji(c, message);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Flex, Tag, Tooltip } from "@chakra-ui/react";
|
import { Flex, Tag, Tooltip } from "@chakra-ui/react";
|
||||||
|
|
||||||
// copied from github
|
// copied from github
|
||||||
const NIP_NAMES: Record<string, string> = {
|
export const NIP_NAMES: Record<string, string> = {
|
||||||
"01": "Basic protocol",
|
"01": "Basic protocol",
|
||||||
"02": "Contact List and Petnames",
|
"02": "Contact List and Petnames",
|
||||||
"03": "OpenTimestamps Attestations for Events",
|
"03": "OpenTimestamps Attestations for Events",
|
||||||
@@ -17,13 +17,13 @@ const NIP_NAMES: Record<string, string> = {
|
|||||||
"13": "Proof of Work",
|
"13": "Proof of Work",
|
||||||
"14": "Subject tag in text events",
|
"14": "Subject tag in text events",
|
||||||
"15": "Nostr Marketplace",
|
"15": "Nostr Marketplace",
|
||||||
"16": "Event Treatment",
|
|
||||||
"18": "Reposts",
|
"18": "Reposts",
|
||||||
"19": "bech32-encoded entities",
|
"19": "bech32-encoded entities",
|
||||||
"20": "Command Results",
|
"20": "Command Results",
|
||||||
"21": "nostr: URI scheme",
|
"21": "nostr: URI scheme",
|
||||||
"22": "Event created_at Limits",
|
"22": "Event created_at Limits", // removed
|
||||||
"23": "Long-form Content",
|
"23": "Long-form Content",
|
||||||
|
"24": "Extra metadata fields and tags",
|
||||||
"25": "Reactions",
|
"25": "Reactions",
|
||||||
"26": "Delegated Event Signing",
|
"26": "Delegated Event Signing",
|
||||||
"27": "Text Note References",
|
"27": "Text Note References",
|
||||||
@@ -31,14 +31,17 @@ const NIP_NAMES: Record<string, string> = {
|
|||||||
"30": "Custom Emoji",
|
"30": "Custom Emoji",
|
||||||
"31": "Dealing with Unknown Events",
|
"31": "Dealing with Unknown Events",
|
||||||
"32": "Labeling",
|
"32": "Labeling",
|
||||||
"33": "Parameterized Replaceable Events",
|
"33": "Parameterized Replaceable Events", //removed
|
||||||
"36": "Sensitive Content",
|
"36": "Sensitive Content",
|
||||||
|
"38": "User Statuses",
|
||||||
"39": "External Identities in Profiles",
|
"39": "External Identities in Profiles",
|
||||||
"40": "Expiration Timestamp",
|
"40": "Expiration Timestamp",
|
||||||
"42": "Authentication of clients to relays",
|
"42": "Authentication of clients to relays",
|
||||||
|
"44": "Versioned Encryption",
|
||||||
"45": "Counting results",
|
"45": "Counting results",
|
||||||
"46": "Nostr Connect",
|
"46": "Nostr Connect",
|
||||||
"47": "Wallet Connect",
|
"47": "Wallet Connect",
|
||||||
|
"48": "Proxy Tags",
|
||||||
"50": "Keywords filter",
|
"50": "Keywords filter",
|
||||||
"51": "Lists",
|
"51": "Lists",
|
||||||
"52": "Calendar Events",
|
"52": "Calendar Events",
|
||||||
@@ -47,8 +50,12 @@ const NIP_NAMES: Record<string, string> = {
|
|||||||
"57": "Lightning Zaps",
|
"57": "Lightning Zaps",
|
||||||
"58": "Badges",
|
"58": "Badges",
|
||||||
"65": "Relay List Metadata",
|
"65": "Relay List Metadata",
|
||||||
|
"72": "Moderated Communities",
|
||||||
|
"75": "Zap Goals",
|
||||||
"78": "Application-specific data",
|
"78": "Application-specific data",
|
||||||
|
"84": "Highlights",
|
||||||
"89": "Recommended Application Handlers",
|
"89": "Recommended Application Handlers",
|
||||||
|
"90": "Data Vending Machines",
|
||||||
"94": "File Metadata",
|
"94": "File Metadata",
|
||||||
"98": "HTTP Auth",
|
"98": "HTTP Auth",
|
||||||
"99": "Classified Listings",
|
"99": "Classified Listings",
|
||||||
|
@@ -3,6 +3,7 @@ import { ParsedStream } from "../../../helpers/nostr/stream";
|
|||||||
import { EmbedableContent, embedUrls } from "../../../helpers/embeds";
|
import { EmbedableContent, embedUrls } from "../../../helpers/embeds";
|
||||||
import {
|
import {
|
||||||
embedEmoji,
|
embedEmoji,
|
||||||
|
embedNipDefinitions,
|
||||||
embedNostrHashtags,
|
embedNostrHashtags,
|
||||||
embedNostrLinks,
|
embedNostrLinks,
|
||||||
embedNostrMentions,
|
embedNostrMentions,
|
||||||
@@ -23,6 +24,7 @@ export default function StreamSummaryContent({ stream, ...props }: BoxProps & {
|
|||||||
c = embedNostrLinks(c);
|
c = embedNostrLinks(c);
|
||||||
c = embedNostrMentions(c, stream.event);
|
c = embedNostrMentions(c, stream.event);
|
||||||
c = embedNostrHashtags(c, stream.event);
|
c = embedNostrHashtags(c, stream.event);
|
||||||
|
c = embedNipDefinitions(c);
|
||||||
c = embedEmoji(c, stream.event);
|
c = embedEmoji(c, stream.event);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
|
@@ -3,6 +3,7 @@ import React, { useMemo } from "react";
|
|||||||
import { EmbedableContent, embedUrls } from "../../../../helpers/embeds";
|
import { EmbedableContent, embedUrls } from "../../../../helpers/embeds";
|
||||||
import {
|
import {
|
||||||
embedEmoji,
|
embedEmoji,
|
||||||
|
embedNipDefinitions,
|
||||||
embedNostrHashtags,
|
embedNostrHashtags,
|
||||||
embedNostrLinks,
|
embedNostrLinks,
|
||||||
embedNostrMentions,
|
embedNostrMentions,
|
||||||
@@ -24,6 +25,7 @@ const ChatMessageContent = React.memo(({ event }: { event: NostrEvent }) => {
|
|||||||
c = embedNostrLinks(c);
|
c = embedNostrLinks(c);
|
||||||
c = embedNostrMentions(c, event);
|
c = embedNostrMentions(c, event);
|
||||||
c = embedNostrHashtags(c, event);
|
c = embedNostrHashtags(c, event);
|
||||||
|
c = embedNipDefinitions(c);
|
||||||
c = embedEmoji(c, event);
|
c = embedEmoji(c, event);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
|
@@ -11,6 +11,7 @@ import { parseZapEvent } from "../../../../helpers/nostr/zaps";
|
|||||||
import { readablizeSats } from "../../../../helpers/bolt11";
|
import { readablizeSats } from "../../../../helpers/bolt11";
|
||||||
import { TrustProvider } from "../../../../providers/trust";
|
import { TrustProvider } from "../../../../providers/trust";
|
||||||
import ChatMessageContent from "./chat-message-content";
|
import ChatMessageContent from "./chat-message-content";
|
||||||
|
import useClientSideMuteFilter from "../../../../hooks/use-client-side-mute-filter";
|
||||||
|
|
||||||
function ZapMessage({ zap, stream }: { zap: NostrEvent; stream: ParsedStream }) {
|
function ZapMessage({ zap, stream }: { zap: NostrEvent; stream: ParsedStream }) {
|
||||||
const ref = useRef<HTMLDivElement | null>(null);
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
@@ -21,8 +22,10 @@ function ZapMessage({ zap, stream }: { zap: NostrEvent; stream: ParsedStream })
|
|||||||
return parseZapEvent(zap);
|
return parseZapEvent(zap);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}, [zap]);
|
}, [zap]);
|
||||||
|
const clientMuteFilter = useClientSideMuteFilter();
|
||||||
|
|
||||||
if (!parsed || !parsed.payment.amount) return null;
|
if (!parsed || !parsed.payment.amount) return null;
|
||||||
|
if (clientMuteFilter(parsed.event)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TrustProvider event={parsed.request}>
|
<TrustProvider event={parsed.request}>
|
||||||
|
@@ -25,6 +25,7 @@ import { useContextEmojis } from "../../../providers/emoji-provider";
|
|||||||
import { TrustProvider } from "../../../providers/trust";
|
import { TrustProvider } from "../../../providers/trust";
|
||||||
import { nostrBuildUploadImage } from "../../../helpers/nostr-build";
|
import { nostrBuildUploadImage } from "../../../helpers/nostr-build";
|
||||||
import { UploadImageIcon } from "../../../components/icons";
|
import { UploadImageIcon } from "../../../components/icons";
|
||||||
|
import { useThrottle } from "react-use";
|
||||||
|
|
||||||
export type ReplyFormProps = {
|
export type ReplyFormProps = {
|
||||||
item: ThreadItem;
|
item: ThreadItem;
|
||||||
@@ -96,6 +97,7 @@ export default function ReplyForm({ item, onCancel, onSubmitted, replyKind = Kin
|
|||||||
});
|
});
|
||||||
|
|
||||||
const formRef = useRef<HTMLFormElement | null>(null);
|
const formRef = useRef<HTMLFormElement | null>(null);
|
||||||
|
const previewDraft = useThrottle(draft, 500);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex as="form" direction="column" gap="2" pb="4" onSubmit={submit} ref={formRef}>
|
<Flex as="form" direction="column" gap="2" pb="4" onSubmit={submit} ref={formRef}>
|
||||||
@@ -142,10 +144,10 @@ export default function ReplyForm({ item, onCancel, onSubmitted, replyKind = Kin
|
|||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</Flex>
|
</Flex>
|
||||||
{getValues().content.length > 0 && (
|
{previewDraft.content.length > 0 && (
|
||||||
<Box p="2" borderWidth={1} borderRadius="md" mb="2">
|
<Box p="2" borderWidth={1} borderRadius="md" mb="2">
|
||||||
<TrustProvider trust>
|
<TrustProvider trust>
|
||||||
<NoteContents event={draft} />
|
<NoteContents event={previewDraft} />
|
||||||
</TrustProvider>
|
</TrustProvider>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
Reference in New Issue
Block a user