Note -> EventComponent, split NoteInner
This commit is contained in:
@ -12,7 +12,7 @@ import { AsyncIcon } from "@/Components/Button/AsyncIcon";
|
||||
import CloseButton from "@/Components/Button/CloseButton";
|
||||
import { TrendingHashTagsLine } from "@/Components/Event/Create/TrendingHashTagsLine";
|
||||
import { sendEventToRelays } from "@/Components/Event/Create/util";
|
||||
import Note from "@/Components/Event/Note";
|
||||
import Note from "@/Components/Event/EventComponent";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
import { ToggleSwitch } from "@/Components/Icons/Toggle";
|
||||
import Modal from "@/Components/Modal/Modal";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import "./Note.css";
|
||||
import "./EventComponent.css";
|
||||
|
||||
import { EventKind, NostrEvent, TaggedNostrEvent } from "@snort/system";
|
||||
import { memo, ReactNode } from "react";
|
||||
@ -13,7 +13,7 @@ import { LiveEvent } from "@/Components/LiveStream/LiveEvent";
|
||||
import ProfilePreview from "@/Components/User/ProfilePreview";
|
||||
|
||||
import { LongFormText } from "./LongFormText";
|
||||
import { NoteInner } from "./NoteInner";
|
||||
import { NoteInner } from "./Note/NoteInner";
|
||||
|
||||
export interface NoteProps {
|
||||
data: TaggedNostrEvent;
|
@ -12,8 +12,8 @@ import useImgProxy from "@/Hooks/useImgProxy";
|
||||
import { findTag } from "@/Utils";
|
||||
|
||||
import { Markdown } from "./Markdown";
|
||||
import NoteFooter from "./NoteFooter";
|
||||
import NoteTime from "./NoteTime";
|
||||
import NoteFooter from "./Note/NoteFooter";
|
||||
import NoteTime from "./Note/NoteTime";
|
||||
|
||||
interface LongFormTextProps {
|
||||
ev: TaggedNostrEvent;
|
||||
|
@ -12,7 +12,7 @@ import useModeration from "@/Hooks/useModeration";
|
||||
import { setBookmarked, setPinned } from "@/Utils/Login";
|
||||
import { getCurrentSubscription, SubscriptionType } from "@/Utils/Subscription";
|
||||
|
||||
import { ReBroadcaster } from "../ReBroadcaster";
|
||||
import { ReBroadcaster } from "../../ReBroadcaster";
|
||||
|
||||
export interface NoteTranslation {
|
||||
text: string;
|
@ -21,7 +21,7 @@ import { Zapper, ZapTarget } from "@/Utils/Zapper";
|
||||
import { ZapPoolController } from "@/Utils/ZapPoolController";
|
||||
import { useWallet } from "@/Wallet";
|
||||
|
||||
import messages from "../messages";
|
||||
import messages from "../../messages";
|
||||
|
||||
let isZapperBusy = false;
|
||||
const barrierZapper = async <T,>(then: () => Promise<T>): Promise<T> => {
|
@ -1,4 +1,4 @@
|
||||
import "./Note.css";
|
||||
import "../EventComponent.css";
|
||||
|
||||
import ProfileImage from "@/Components/User/ProfileImage";
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { EventExt, EventKind, HexKey, NostrLink, NostrPrefix, TaggedNostrEvent } from "@snort/system";
|
||||
import classNames from "classnames";
|
||||
import React, { ReactNode, useMemo, useState } from "react";
|
||||
import React, { ReactNode, useState } from "react";
|
||||
import { useInView } from "react-intersection-observer";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
|
||||
import { UserCache } from "@/Cache";
|
||||
import { NoteText } from "@/Components/Event/Note/NoteText";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
import DisplayName from "@/Components/User/DisplayName";
|
||||
import { ProfileLink } from "@/Components/User/ProfileLink";
|
||||
@ -16,19 +17,16 @@ import { chainKey } from "@/Hooks/useThreadContext";
|
||||
import { findTag, hexToBech32 } from "@/Utils";
|
||||
import { setBookmarked, setPinned } from "@/Utils/Login";
|
||||
|
||||
import messages from "../messages";
|
||||
import Text from "../Text/Text";
|
||||
import ProfileImage from "../User/ProfileImage";
|
||||
import HiddenNote from "./HiddenNote";
|
||||
import { NoteProps } from "./Note";
|
||||
import messages from "../../messages";
|
||||
import Text from "../../Text/Text";
|
||||
import ProfileImage from "../../User/ProfileImage";
|
||||
import { NoteProps } from "../EventComponent";
|
||||
import HiddenNote from "../HiddenNote";
|
||||
import Poll from "../Poll";
|
||||
import { NoteContextMenu, NoteTranslation } from "./NoteContextMenu";
|
||||
import NoteFooter from "./NoteFooter";
|
||||
import NoteTime from "./NoteTime";
|
||||
import Poll from "./Poll";
|
||||
import ReactionsModal from "./ReactionsModal";
|
||||
import Reveal from "./Reveal";
|
||||
|
||||
const TEXT_TRUNCATE_LENGTH = 400;
|
||||
|
||||
export function NoteInner(props: NoteProps) {
|
||||
const { data: ev, highlight, options: opt, ignoreModeration = false, className, waitUntilInView } = props;
|
||||
@ -42,10 +40,9 @@ export function NoteInner(props: NoteProps) {
|
||||
const login = useLogin();
|
||||
const { pinned, bookmarked } = useLogin();
|
||||
const { publisher, system } = useEventPublisher();
|
||||
const [translated, setTranslated] = useState<NoteTranslation>();
|
||||
const [showTranslation, setShowTranslation] = useState(true);
|
||||
const [translated, setTranslated] = useState<NoteTranslation>();
|
||||
const { formatMessage } = useIntl();
|
||||
const [showMore, setShowMore] = useState(false);
|
||||
|
||||
const options = {
|
||||
showHeader: true,
|
||||
@ -79,101 +76,6 @@ export function NoteInner(props: NoteProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const ToggleShowMore = () => (
|
||||
<a
|
||||
className="highlight"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setShowMore(!showMore);
|
||||
}}>
|
||||
{showMore ? (
|
||||
<FormattedMessage defaultMessage="Show less" id="qyJtWy" />
|
||||
) : (
|
||||
<FormattedMessage defaultMessage="Show more" id="aWpBzj" />
|
||||
)}
|
||||
</a>
|
||||
);
|
||||
|
||||
const innerContent = useMemo(() => {
|
||||
const body = translated && showTranslation ? translated.text : ev?.content ?? "";
|
||||
const id = translated && showTranslation ? `${ev.id}-translated` : ev.id;
|
||||
const shouldTruncate = opt?.truncate && body.length > TEXT_TRUNCATE_LENGTH;
|
||||
|
||||
return (
|
||||
<>
|
||||
{shouldTruncate && showMore && <ToggleShowMore />}
|
||||
<Text
|
||||
id={id}
|
||||
highlighText={props.searchedValue}
|
||||
content={body}
|
||||
tags={ev.tags}
|
||||
creator={ev.pubkey}
|
||||
depth={props.depth}
|
||||
disableMedia={!(options.showMedia ?? true)}
|
||||
disableMediaSpotlight={!(props.options?.showMediaSpotlight ?? true)}
|
||||
truncate={shouldTruncate && !showMore ? TEXT_TRUNCATE_LENGTH : undefined}
|
||||
/>
|
||||
{shouldTruncate && !showMore && <ToggleShowMore />}
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
showMore,
|
||||
ev,
|
||||
translated,
|
||||
showTranslation,
|
||||
props.searchedValue,
|
||||
props.depth,
|
||||
options.showMedia,
|
||||
props.options?.showMediaSpotlight,
|
||||
opt?.truncate,
|
||||
TEXT_TRUNCATE_LENGTH,
|
||||
]);
|
||||
|
||||
const transformBody = () => {
|
||||
if (!login.appData.item.showContentWarningPosts) {
|
||||
const contentWarning = ev.tags.find(a => a[0] === "content-warning");
|
||||
if (contentWarning) {
|
||||
return (
|
||||
<Reveal
|
||||
message={
|
||||
<>
|
||||
<FormattedMessage
|
||||
defaultMessage="The author has marked this note as a <i>sensitive topic</i>"
|
||||
id="StKzTE"
|
||||
values={{
|
||||
i: c => <i>{c}</i>,
|
||||
}}
|
||||
/>
|
||||
{contentWarning[1] && (
|
||||
<>
|
||||
|
||||
<FormattedMessage
|
||||
defaultMessage="Reason: <i>{reason}</i>"
|
||||
id="6OSOXl"
|
||||
values={{
|
||||
i: c => <i>{c}</i>,
|
||||
reason: contentWarning[1],
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
. <FormattedMessage defaultMessage="Click here to load anyway" id="IoQq+a" />.{" "}
|
||||
<Link to="/settings/moderation">
|
||||
<i>
|
||||
<FormattedMessage defaultMessage="Settings" id="D3idYv" />
|
||||
</i>
|
||||
</Link>
|
||||
</>
|
||||
}>
|
||||
{innerContent}
|
||||
</Reveal>
|
||||
);
|
||||
}
|
||||
}
|
||||
return innerContent;
|
||||
};
|
||||
|
||||
function goToEvent(e: React.MouseEvent, eTarget: TaggedNostrEvent) {
|
||||
if (opt?.canClick === false) {
|
||||
return;
|
||||
@ -359,7 +261,7 @@ export function NoteInner(props: NoteProps) {
|
||||
</div>
|
||||
)}
|
||||
<div className="body" onClick={e => goToEvent(e, ev, true)}>
|
||||
{transformBody()}
|
||||
<NoteText {...props} translated={translated} showTranslation={showTranslation} login={login} />
|
||||
{translation()}
|
||||
{pollOptions()}
|
||||
</div>
|
@ -1,7 +1,7 @@
|
||||
import { NostrLink } from "@snort/system";
|
||||
import { useEventFeed } from "@snort/system-react";
|
||||
|
||||
import Note from "@/Components/Event/Note";
|
||||
import Note from "@/Components/Event/EventComponent";
|
||||
import PageSpinner from "@/Components/PageSpinner";
|
||||
|
||||
export default function NoteQuote({ link, depth }: { link: NostrLink; depth?: number }) {
|
96
packages/app/src/Components/Event/Note/NoteText.tsx
Normal file
96
packages/app/src/Components/Event/Note/NoteText.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
import React, { useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { NoteProps } from "@/Components/Event/EventComponent";
|
||||
import { NoteTranslation } from "@/Components/Event/Note/NoteContextMenu";
|
||||
import Reveal from "@/Components/Event/Reveal";
|
||||
import Text from "@/Components/Text/Text";
|
||||
import { LoginSession } from "@/Utils/Login";
|
||||
|
||||
const TEXT_TRUNCATE_LENGTH = 400;
|
||||
export const NoteText = function InnerContent(
|
||||
props: NoteProps & { translated: NoteTranslation; showTranslation?: boolean; login: LoginSession },
|
||||
) {
|
||||
const { data: ev, options, translated, showTranslation, login } = props;
|
||||
const [showMore, setShowMore] = useState(false);
|
||||
const body = translated && showTranslation ? translated.text : ev?.content ?? "";
|
||||
const id = translated && showTranslation ? `${ev.id}-translated` : ev.id;
|
||||
const shouldTruncate = options?.truncate && body.length > TEXT_TRUNCATE_LENGTH;
|
||||
|
||||
const ToggleShowMore = () => (
|
||||
<a
|
||||
className="highlight"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setShowMore(!showMore);
|
||||
}}>
|
||||
{showMore ? (
|
||||
<FormattedMessage defaultMessage="Show less" id="qyJtWy" />
|
||||
) : (
|
||||
<FormattedMessage defaultMessage="Show more" id="aWpBzj" />
|
||||
)}
|
||||
</a>
|
||||
);
|
||||
|
||||
const innerContent = (
|
||||
<>
|
||||
{shouldTruncate && showMore && <ToggleShowMore />}
|
||||
<Text
|
||||
id={id}
|
||||
highlighText={props.searchedValue}
|
||||
content={body}
|
||||
tags={ev.tags}
|
||||
creator={ev.pubkey}
|
||||
depth={props.depth}
|
||||
disableMedia={!(options?.showMedia ?? true)}
|
||||
disableMediaSpotlight={!(props.options?.showMediaSpotlight ?? true)}
|
||||
truncate={shouldTruncate && !showMore ? TEXT_TRUNCATE_LENGTH : undefined}
|
||||
/>
|
||||
{shouldTruncate && !showMore && <ToggleShowMore />}
|
||||
</>
|
||||
);
|
||||
|
||||
if (!login.appData.item.showContentWarningPosts) {
|
||||
const contentWarning = ev.tags.find(a => a[0] === "content-warning");
|
||||
if (contentWarning) {
|
||||
return (
|
||||
<Reveal
|
||||
message={
|
||||
<>
|
||||
<FormattedMessage
|
||||
defaultMessage="The author has marked this note as a <i>sensitive topic</i>"
|
||||
id="StKzTE"
|
||||
values={{
|
||||
i: c => <i>{c}</i>,
|
||||
}}
|
||||
/>
|
||||
{contentWarning[1] && (
|
||||
<>
|
||||
|
||||
<FormattedMessage
|
||||
defaultMessage="Reason: <i>{reason}</i>"
|
||||
id="6OSOXl"
|
||||
values={{
|
||||
i: c => <i>{c}</i>,
|
||||
reason: contentWarning[1],
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
. <FormattedMessage defaultMessage="Click here to load anyway" id="IoQq+a" />.{" "}
|
||||
<Link to="/settings/moderation">
|
||||
<i>
|
||||
<FormattedMessage defaultMessage="Settings" id="D3idYv" />
|
||||
</i>
|
||||
</Link>
|
||||
</>
|
||||
}>
|
||||
{innerContent}
|
||||
</Reveal>
|
||||
);
|
||||
}
|
||||
}
|
||||
return innerContent;
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import "./Reactions.css";
|
||||
import "./ReactionsModal.css";
|
||||
|
||||
import { NostrLink, socialGraphInstance, TaggedNostrEvent } from "@snort/system";
|
||||
import { useEventReactions, useReactions } from "@snort/system-react";
|
||||
@ -12,7 +12,7 @@ import Tabs from "@/Components/Tabs/Tabs";
|
||||
import ProfileImage from "@/Components/User/ProfileImage";
|
||||
import { formatShort } from "@/Utils/Number";
|
||||
|
||||
import messages from "../messages";
|
||||
import messages from "../../messages";
|
||||
|
||||
interface ReactionsModalProps {
|
||||
show: boolean;
|
@ -7,7 +7,7 @@ import { useInView } from "react-intersection-observer";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import Note from "@/Components/Event/Note";
|
||||
import Note from "@/Components/Event/EventComponent";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
import useModeration from "@/Hooks/useModeration";
|
||||
import { eventLink, getDisplayName, hexToBech32 } from "@/Utils";
|
||||
|
@ -8,8 +8,8 @@ import { useNavigate, useParams } from "react-router-dom";
|
||||
|
||||
import BackButton from "@/Components/Button/BackButton";
|
||||
import Collapsed from "@/Components/Collapsed";
|
||||
import Note from "@/Components/Event/Note";
|
||||
import NoteGhost from "@/Components/Event/NoteGhost";
|
||||
import Note from "@/Components/Event/EventComponent";
|
||||
import NoteGhost from "@/Components/Event/Note/NoteGhost";
|
||||
import { chainKey, ThreadContext, ThreadContextWrapper } from "@/Hooks/useThreadContext";
|
||||
|
||||
import messages from "../messages";
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { TaggedNostrEvent } from "@snort/system";
|
||||
|
||||
import { transformTextCached } from "@/Hooks/useTextTransformCache";
|
||||
|
||||
export default function getEventMedia(event: TaggedNostrEvent) {
|
||||
const parsed = transformTextCached(event.id, event.content, event.tags);
|
||||
return parsed.filter(
|
||||
a => a.type === "media" && (a.mimeType?.startsWith("image/") || a.mimeType?.startsWith("video/")),
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user