mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-17 21:31:43 +01:00
Support nostr links in markdown
This commit is contained in:
parent
01d7db3232
commit
979a8601fe
5
.changeset/late-steaks-worry.md
Normal file
5
.changeset/late-steaks-worry.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"nostrudel": minor
|
||||
---
|
||||
|
||||
Support nostr links in markdown
|
@ -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, {
|
||||
|
@ -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>
|
@ -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,
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
Loading…
x
Reference in New Issue
Block a user