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:
25
packages/app/src/Element/NostrFileHeader.tsx
Normal file
25
packages/app/src/Element/NostrFileHeader.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
}
|
@ -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 }}>
|
||||
|
@ -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));
|
||||
|
Reference in New Issue
Block a user