feat: render note quotes
This commit is contained in:
parent
a6eefb1027
commit
13461cca80
@ -26,7 +26,7 @@ import NostrLink from "Element/NostrLink";
|
||||
import RevealMedia from "Element/RevealMedia";
|
||||
import MagnetLink from "Element/MagnetLink";
|
||||
|
||||
export default function HyperText({ link, creator }: { link: string; creator: string }) {
|
||||
export default function HyperText({ link, creator, depth }: { link: string; creator: string; depth?: number }) {
|
||||
const a = link;
|
||||
try {
|
||||
const url = new URL(a);
|
||||
@ -85,7 +85,7 @@ export default function HyperText({ link, creator }: { link: string; creator: st
|
||||
} else if (isWavlakeLink) {
|
||||
return <WavlakeEmbed link={a} />;
|
||||
} else if (url.protocol === "nostr:" || url.protocol === "web+nostr:") {
|
||||
return <NostrLink link={a} />;
|
||||
return <NostrLink link={a} depth={depth} />;
|
||||
} else if (url.protocol === "magnet:") {
|
||||
const parsed = magnetURIDecode(a);
|
||||
if (parsed) {
|
||||
|
@ -2,23 +2,23 @@ import useEventFeed from "Feed/EventFeed";
|
||||
import { NostrLink } from "Util";
|
||||
import HyperText from "Element/HyperText";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import Spinner from "Icons/Spinner";
|
||||
import PageSpinner from "Element/PageSpinner";
|
||||
|
||||
export default function NostrFileHeader({ link }: { link: NostrLink }) {
|
||||
const ev = useEventFeed(link);
|
||||
|
||||
if (!ev.data?.length) return <Spinner />;
|
||||
if (!ev.data) return <PageSpinner />;
|
||||
|
||||
// assume image or embed which can be rendered by the hypertext kind
|
||||
// todo: make use of hash
|
||||
// todo: use magnet or other links if present
|
||||
const u = ev.data?.[0]?.tags.find(a => a[0] === "u")?.[1] ?? "";
|
||||
const u = ev.data?.tags.find(a => a[0] === "u")?.[1] ?? "";
|
||||
if (u) {
|
||||
return <HyperText link={u} creator={ev.data?.[0]?.pubkey ?? ""} />;
|
||||
return <HyperText link={u} creator={ev.data?.pubkey ?? ""} />;
|
||||
} else {
|
||||
return (
|
||||
<b className="error">
|
||||
<FormattedMessage defaultMessage="Unknown file header: {name}" values={{ name: ev.data?.[0]?.content }} />
|
||||
<FormattedMessage defaultMessage="Unknown file header: {name}" values={{ name: ev.data?.content }} />
|
||||
</b>
|
||||
);
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { EventKind, NostrPrefix } from "@snort/nostr";
|
||||
import { Link } from "react-router-dom";
|
||||
import { EventKind, NostrPrefix } from "@snort/nostr";
|
||||
|
||||
import Mention from "Element/Mention";
|
||||
import NostrFileHeader from "Element/NostrFileHeader";
|
||||
import { parseNostrLink } from "Util";
|
||||
import NoteQuote from "Element/NoteQuote";
|
||||
|
||||
export default function NostrLink({ link }: { link: string }) {
|
||||
export default function NostrLink({ link, depth }: { link: string; depth?: number }) {
|
||||
const nav = parseNostrLink(link);
|
||||
|
||||
if (nav?.type === NostrPrefix.PublicKey || nav?.type === NostrPrefix.Profile) {
|
||||
@ -14,12 +15,16 @@ export default function NostrLink({ link }: { link: string }) {
|
||||
if (nav.kind === EventKind.FileHeader) {
|
||||
return <NostrFileHeader link={nav} />;
|
||||
}
|
||||
const evLink = nav.encode();
|
||||
return (
|
||||
<Link to={`/e/${evLink}`} onClick={e => e.stopPropagation()} state={{ from: location.pathname }}>
|
||||
#{evLink.substring(0, 12)}
|
||||
</Link>
|
||||
);
|
||||
if ((depth ?? 0) > 0) {
|
||||
const evLink = nav.encode();
|
||||
return (
|
||||
<Link to={`/e/${evLink}`} onClick={e => e.stopPropagation()} state={{ from: location.pathname }}>
|
||||
#{evLink.substring(0, 12)}
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
return <NoteQuote link={nav} depth={depth} />;
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<a href={link} onClick={e => e.stopPropagation()} target="_blank" rel="noreferrer" className="ext">
|
||||
|
@ -57,6 +57,14 @@
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.note-quote {
|
||||
border: 1px solid var(--gray);
|
||||
}
|
||||
|
||||
.note-quote.note > .body {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.note > .body {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 24px;
|
||||
@ -98,9 +106,6 @@
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.light .note > .footer .ctx-menu {
|
||||
}
|
||||
|
||||
.note > .footer .ctx-menu li {
|
||||
background: #1e1e1e;
|
||||
padding-top: 8px;
|
||||
|
@ -39,6 +39,7 @@ export interface NoteProps {
|
||||
highlight?: boolean;
|
||||
ignoreModeration?: boolean;
|
||||
onClick?: (e: TaggedRawEvent) => void;
|
||||
depth?: number;
|
||||
options?: {
|
||||
showHeader?: boolean;
|
||||
showTime?: boolean;
|
||||
@ -187,7 +188,7 @@ export default function Note(props: NoteProps) {
|
||||
</Reveal>
|
||||
);
|
||||
}
|
||||
return <Text content={body} tags={ev.tags} creator={ev.pubkey} />;
|
||||
return <Text content={body} tags={ev.tags} creator={ev.pubkey} depth={props.depth} />;
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
20
packages/app/src/Element/NoteQuote.tsx
Normal file
20
packages/app/src/Element/NoteQuote.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import useEventFeed from "Feed/EventFeed";
|
||||
import { NostrLink } from "Util";
|
||||
import Note from "Element/Note";
|
||||
import PageSpinner from "Element/PageSpinner";
|
||||
|
||||
export default function NoteQuote({ link, depth }: { link: NostrLink; depth?: number }) {
|
||||
const ev = useEventFeed(link);
|
||||
if (!ev.data) return <PageSpinner />;
|
||||
return (
|
||||
<Note
|
||||
data={ev.data}
|
||||
related={[]}
|
||||
className="note-quote"
|
||||
depth={(depth ?? 0) + 1}
|
||||
options={{
|
||||
showFooter: false,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.text a {
|
||||
.text > a {
|
||||
color: var(--highlight);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@ -25,9 +25,10 @@ export interface TextProps {
|
||||
creator: HexKey;
|
||||
tags: Array<Array<string>>;
|
||||
disableMedia?: boolean;
|
||||
depth?: number;
|
||||
}
|
||||
|
||||
export default function Text({ content, tags, creator, disableMedia }: TextProps) {
|
||||
export default function Text({ content, tags, creator, disableMedia, depth }: TextProps) {
|
||||
const location = useLocation();
|
||||
|
||||
function extractLinks(fragments: Fragment[]) {
|
||||
@ -43,7 +44,7 @@ export default function Text({ content, tags, creator, disableMedia }: TextProps
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return <HyperText link={a} creator={creator} />;
|
||||
return <HyperText link={a} creator={creator} depth={depth} />;
|
||||
}
|
||||
return a;
|
||||
});
|
||||
|
@ -88,7 +88,9 @@ const Timeline = (props: TimelineProps) => {
|
||||
if (eRef) {
|
||||
return <NoteReaction data={e} key={e.id} root={findRelated(eRef)} />;
|
||||
}
|
||||
return <Note key={e.id} data={e} related={relatedFeed(e.id)} ignoreModeration={props.ignoreModeration} />;
|
||||
return (
|
||||
<Note key={e.id} data={e} related={relatedFeed(e.id)} ignoreModeration={props.ignoreModeration} depth={0} />
|
||||
);
|
||||
}
|
||||
case EventKind.ZapReceipt: {
|
||||
const zap = parseZap(e);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||
import { FlatNoteStore, RequestBuilder } from "System";
|
||||
import { RequestBuilder, ReplaceableNoteStore } from "System";
|
||||
import { NostrLink } from "Util";
|
||||
|
||||
export default function useEventFeed(link: NostrLink) {
|
||||
@ -11,5 +11,5 @@ export default function useEventFeed(link: NostrLink) {
|
||||
return b;
|
||||
}, [link]);
|
||||
|
||||
return useRequestBuilder<FlatNoteStore>(FlatNoteStore, sub);
|
||||
return useRequestBuilder<ReplaceableNoteStore>(ReplaceableNoteStore, sub);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
NoteStore,
|
||||
PubkeyReplaceableNoteStore,
|
||||
ParameterizedReplaceableNoteStore,
|
||||
ReplaceableNoteStore,
|
||||
} from "./NoteCollection";
|
||||
import { diffFilters } from "./RequestSplitter";
|
||||
import { Query } from "./Query";
|
||||
@ -18,6 +19,7 @@ export {
|
||||
FlatNoteStore,
|
||||
PubkeyReplaceableNoteStore,
|
||||
ParameterizedReplaceableNoteStore,
|
||||
ReplaceableNoteStore,
|
||||
Query,
|
||||
EventBuilder,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user