Support nostr links in markdown

This commit is contained in:
hzrd149 2024-11-22 12:09:23 -06:00
parent 01d7db3232
commit 979a8601fe
10 changed files with 57 additions and 16 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Support nostr links in markdown

View File

@ -1,5 +1,5 @@
import { EmbedableContent, embedJSX } from "../../../helpers/embeds";
import WikiLink from "../../../views/wiki/components/wiki-link";
import WikiLink from "../../markdown/wiki-link";
export function embedNostrWikiLinks(content: EmbedableContent) {
return embedJSX(content, {

View File

@ -22,12 +22,16 @@ import {
Tr,
UnorderedList,
} from "@chakra-ui/react";
import Markdown, { Components, ExtraProps } from "react-markdown";
import Markdown, { Components, defaultUrlTransform, ExtraProps } from "react-markdown";
import styled from "@emotion/styled";
import { NostrEvent } from "nostr-tools";
import { nip19, NostrEvent } from "nostr-tools";
import remarkGfm from "remark-gfm";
import wikiLinkPlugin from "remark-wiki-link";
import { remarkNostrMentions, NostrMention } from "applesauce-content/markdown";
import WikiLink from "./wiki-link";
import UserLink from "../user/user-link";
import { EmbedEventPointer } from "../embed-event";
const StyledMarkdown = styled(Markdown)`
pre > code {
@ -91,6 +95,27 @@ function A({ children, node, href, ...props }: LinkProps & ExtraProps) {
);
}
// render nostr: mentions
if (href?.startsWith("nostr:")) {
try {
const parsed = nip19.decode(href.replace(/^nostr:/, ""));
switch (parsed.type) {
case "npub":
return <UserLink pubkey={parsed.data} showAt color="blue.500" />;
case "nprofile":
return <UserLink pubkey={parsed.data.pubkey} showAt relays={parsed.data.relays} color="blue.500" />;
case "naddr":
case "nevent":
case "note":
return <EmbedEventPointer pointer={parsed} />;
}
} catch (error) {
if (error instanceof Error) return <Text color="red.500">{error.message}</Text>;
}
}
return (
<Link color="blue.500" isExternal href={href} {...props}>
{children}
@ -145,10 +170,20 @@ const components: Partial<Components> = {
code: CustomCode,
};
function urlTransform(url: string) {
if (url.startsWith("nostr:")) return url;
return defaultUrlTransform(url);
}
export const CharkaMarkdown = forwardRef<HTMLDivElement, { children: string }>(({ children }, ref) => {
return (
<div ref={ref}>
<StyledMarkdown remarkPlugins={[remarkGfm, wikiLinkPlugin]} components={components}>
<StyledMarkdown
remarkPlugins={[remarkGfm, wikiLinkPlugin, remarkNostrMentions]}
components={components}
skipHtml
urlTransform={urlTransform}
>
{children}
</StyledMarkdown>
</div>

View File

@ -20,11 +20,11 @@ import { getEventUID } from "nostr-idb";
import { Link as RouterLink } from "react-router-dom";
import { useObservable } from "applesauce-react/hooks";
import { useReadRelays } from "../../../hooks/use-client-relays";
import { getPageDefer, getPageSummary } from "../../../helpers/nostr/wiki";
import UserName from "../../../components/user/user-name";
import dictionaryService from "../../../services/dictionary";
import { useWebOfTrust } from "../../../providers/global/web-of-trust-provider";
import { useReadRelays } from "../../hooks/use-client-relays";
import { getPageDefer, getPageSummary } from "../../helpers/nostr/wiki";
import UserName from "../user/user-name";
import dictionaryService from "../../services/dictionary";
import { useWebOfTrust } from "../../providers/global/web-of-trust-provider";
export default function WikiLink({
children,

View File

@ -11,10 +11,11 @@ export type UserLinkProps = LinkProps & {
pubkey: string;
showAt?: boolean;
tab?: string;
relays?: string[];
};
export default function UserLink({ pubkey, showAt, tab, ...props }: UserLinkProps) {
const metadata = useUserProfile(pubkey);
export default function UserLink({ pubkey, showAt, tab, relays, ...props }: UserLinkProps) {
const metadata = useUserProfile(pubkey, relays);
const account = useCurrentAccount();
const { hideUsernames, removeEmojisInUsernames, showPubkeyColor } = useAppSettings();
const color = "#" + pubkey.slice(0, 6);

View File

@ -14,7 +14,7 @@ import {
import UserLink from "../../components/user/user-link";
import UserAvatarLink from "../../components/user/user-avatar-link";
import UserDnsIdentityIcon from "../../components/user/user-dns-identity-icon";
import MarkdownContent from "../wiki/components/markdown";
import MarkdownContent from "../../components/markdown/markdown";
import ArticleMenu from "./components/article-menu";
import ArticleTags from "./components/article-tags";
import NoteReactions from "../../components/note/timeline-note/components/note-reactions";

View File

@ -20,7 +20,7 @@ import Timestamp from "../../components/timestamp";
import WikiPageHeader from "./components/wiki-page-header";
import DiffViewer from "../../components/diff/diff-viewer";
import { useBreakpointValue } from "../../providers/global/breakpoint-provider";
import MarkdownContent from "./components/markdown";
import MarkdownContent from "../../components/markdown/markdown";
import { WIKI_RELAYS } from "../../const";
import UserName from "../../components/user/user-name";
import WikiPageMenu from "./components/wiki-page-menu";

View File

@ -12,7 +12,7 @@ import useUsersMediaServers from "../../../hooks/use-user-media-servers";
import useAppSettings from "../../../hooks/use-app-settings";
import useCurrentAccount from "../../../hooks/use-current-account";
import { CharkaMarkdown } from "./markdown";
import { CharkaMarkdown } from "../../../components/markdown/markdown";
import { useSigningContext } from "../../../providers/global/signing-provider";
import { simpleMultiServerUpload } from "../../../helpers/media-upload/blossom";
import { stripSensitiveMetadataOnFile } from "../../../helpers/image";

View File

@ -10,7 +10,7 @@ import { useReadRelays } from "../../hooks/use-client-relays";
import TimelineActionAndStatus from "../../components/timeline/timeline-action-and-status";
import { WIKI_RELAYS } from "../../const";
import { ExternalLinkIcon } from "../../components/icons";
import WikiLink from "./components/wiki-link";
import WikiLink from "../../components/markdown/wiki-link";
import { useEffect } from "react";
import dictionaryService from "../../services/dictionary";
import UserAvatar from "../../components/user/user-avatar";

View File

@ -20,7 +20,7 @@ import useParamsAddressPointer from "../../hooks/use-params-address-pointer";
import useReplaceableEvent from "../../hooks/use-replaceable-event";
import VerticalPageLayout from "../../components/vertical-page-layout";
import { getPageDefer, getPageForks, getPageSummary, getPageTitle, getPageTopic } from "../../helpers/nostr/wiki";
import MarkdownContent from "./components/markdown";
import MarkdownContent from "../../components/markdown/markdown";
import UserLink from "../../components/user/user-link";
import WikiPageResult from "./components/wiki-page-result";
import Timestamp from "../../components/timestamp";