import { EventKind, NostrLink, TaggedNostrEvent } from "@snort/system"; import classNames from "classnames"; import React, { useState } from "react"; import { useInView } from "react-intersection-observer"; import { FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; import NoteHeader from "@/Components/Event/Note/NoteHeader"; import { NoteText } from "@/Components/Event/Note/NoteText"; import useModeration from "@/Hooks/useModeration"; import { chainKey } from "@/Hooks/useThreadContext"; import { findTag } from "@/Utils"; import messages from "../../messages"; import Text from "../../Text/Text"; import { NoteProps } from "../EventComponent"; import HiddenNote from "../HiddenNote"; import Poll from "../Poll"; import { NoteTranslation } from "./NoteContextMenu"; import NoteFooter from "./NoteFooter"; export function Note(props: NoteProps) { const { data: ev, highlight, options: opt, ignoreModeration = false, className, waitUntilInView } = props; const baseClassName = classNames("note min-h-[110px] flex flex-col gap-4 card", className); const navigate = useNavigate(); const { isEventMuted } = useModeration(); const { ref, inView } = useInView({ triggerOnce: true, rootMargin: "2000px" }); const [showTranslation, setShowTranslation] = useState(true); const [translated, setTranslated] = useState(); const options = { showHeader: true, showTime: true, showFooter: true, canUnpin: false, canUnbookmark: false, showContextMenu: true, ...opt, }; function goToEvent(e: React.MouseEvent, eTarget: TaggedNostrEvent) { if (opt?.canClick === false) { return; } let target = e.target as HTMLElement | null; while (target) { if ( target.tagName === "A" || target.tagName === "BUTTON" || target.classList.contains("reaction-pill") || target.classList.contains("szh-menu-container") ) { return; // is there a better way to do this? } target = target.parentElement; } e.stopPropagation(); if (props.onClick) { props.onClick(eTarget); return; } const link = NostrLink.fromEvent(eTarget); // detect cmd key and open in new tab if (e.metaKey) { window.open(`/${link.encode(CONFIG.eventLinkPrefix)}`, "_blank"); } else { navigate(`/${link.encode(CONFIG.eventLinkPrefix)}`, { state: eTarget, }); } } const canRenderAsTextNote = [EventKind.TextNote, EventKind.Polls]; if (!canRenderAsTextNote.includes(ev.kind)) { const alt = findTag(ev, "alt"); if (alt) { return (
); } else { return ( <>

{JSON.stringify(ev, undefined, "  ")}
); } } function translation() { if (translated && translated.confidence > 0.5) { return ( <> { e.stopPropagation(); setShowTranslation(s => !s); }}> ); } else if (translated) { return (

); } } function pollOptions() { if (ev.kind !== EventKind.Polls) return; return ; } function content() { if (waitUntilInView && !inView) return undefined; return ( <> {options.showHeader && }
goToEvent(e, ev, true)}> {translation()} {pollOptions()}
{options.showFooter && } ); } const note = (
goToEvent(e, ev)} ref={ref}> {content()}
); return !ignoreModeration && isEventMuted(ev) ? {note} : note; }