NIP-94 file headers (#488)

* feat: NIP-94 file headers

* Merge NIP-81 tags

* disable embedding nip94 for now

* merge error

* disable broken test

* bugfixes

* bug: validation failure
This commit is contained in:
2023-04-17 11:57:13 +01:00
committed by GitHub
parent c294f5f0bd
commit c59dda1e49
12 changed files with 134 additions and 25 deletions

View File

@ -0,0 +1,25 @@
import useEventFeed from "Feed/EventFeed";
import { NostrLink } from "Util";
import HyperText from "Element/HyperText";
import { FormattedMessage } from "react-intl";
import Spinner from "Icons/Spinner";
export default function NostrFileHeader({ link }: { link: NostrLink }) {
const ev = useEventFeed(link);
if (!ev.data?.length) return <Spinner />;
// 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] ?? "";
if (u) {
return <HyperText link={u} creator={ev.data?.[0]?.pubkey ?? ""} />;
} else {
return (
<b className="error">
<FormattedMessage defaultMessage="Unknown file header: {name}" values={{ name: ev.data?.[0]?.content }} />
</b>
);
}
}

View File

@ -1,7 +1,8 @@
import { NostrPrefix } from "@snort/nostr";
import { EventKind, NostrPrefix } from "@snort/nostr";
import { Link } from "react-router-dom";
import Mention from "Element/Mention";
import NostrFileHeader from "Element/NostrFileHeader";
import { parseNostrLink } from "Util";
export default function NostrLink({ link }: { link: string }) {
@ -10,6 +11,9 @@ export default function NostrLink({ link }: { link: string }) {
if (nav?.type === NostrPrefix.PublicKey || nav?.type === NostrPrefix.Profile) {
return <Mention pubkey={nav.id} relays={nav.relays} />;
} else if (nav?.type === NostrPrefix.Note || nav?.type === NostrPrefix.Event || nav?.type === NostrPrefix.Address) {
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 }}>

View File

@ -1,7 +1,7 @@
import "./NoteCreator.css";
import { FormattedMessage, useIntl } from "react-intl";
import { useDispatch, useSelector } from "react-redux";
import { EventKind, TaggedRawEvent } from "@snort/nostr";
import { encodeTLV, EventKind, NostrPrefix, TaggedRawEvent } from "@snort/nostr";
import Icon from "Icons/Icon";
import useEventPublisher from "Feed/EventPublisher";
@ -22,6 +22,7 @@ import {
setSensitive,
reset,
setPollOptions,
setOtherEvents,
} from "State/NoteCreator";
import type { RootState } from "State/Store";
import { LNURL } from "LNURL";
@ -51,16 +52,19 @@ export function NoteCreator() {
const { formatMessage } = useIntl();
const publisher = useEventPublisher();
const uploader = useFileUpload();
const note = useSelector((s: RootState) => s.noteCreator.note);
const show = useSelector((s: RootState) => s.noteCreator.show);
const error = useSelector((s: RootState) => s.noteCreator.error);
const active = useSelector((s: RootState) => s.noteCreator.active);
const preview = useSelector((s: RootState) => s.noteCreator.preview);
const replyTo = useSelector((s: RootState) => s.noteCreator.replyTo);
const showAdvanced = useSelector((s: RootState) => s.noteCreator.showAdvanced);
const zapForward = useSelector((s: RootState) => s.noteCreator.zapForward);
const sensitive = useSelector((s: RootState) => s.noteCreator.sensitive);
const pollOptions = useSelector((s: RootState) => s.noteCreator.pollOptions);
const {
note,
zapForward,
sensitive,
pollOptions,
replyTo,
otherEvents,
preview,
active,
show,
showAdvanced,
error,
} = useSelector((s: RootState) => s.noteCreator);
const [uploadInProgress, setUploadInProgress] = useState(false);
const dispatch = useDispatch();
@ -83,6 +87,7 @@ export function NoteCreator() {
return;
}
}
if (sensitive) {
extraTags ??= [];
extraTags.push(["content-warning", sensitive]);
@ -100,6 +105,10 @@ export function NoteCreator() {
const ev = replyTo ? await publisher.reply(replyTo, note, hk) : await publisher.note(note, hk);
publisher.broadcast(ev);
dispatch(reset());
for (const oe of otherEvents) {
publisher.broadcast(oe);
}
dispatch(reset());
}
}
@ -121,7 +130,11 @@ export function NoteCreator() {
try {
if (file) {
const rx = await uploader.upload(file, file.name);
if (rx.url) {
if (rx.header) {
const link = `nostr:${encodeTLV(rx.header.id, NostrPrefix.Event, undefined, rx.header.kind)}`;
dispatch(setNote(`${note ? `${note}\n` : ""}${link}`));
dispatch(setOtherEvents([...otherEvents, rx.header]));
} else if (rx.url) {
dispatch(setNote(`${note ? `${note}\n` : ""}${rx.url}`));
} else if (rx?.error) {
dispatch(setError(rx.error));