long form note: fix text overflow, truncate in feed
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
import "./LongFormText.css";
|
import "./LongFormText.css";
|
||||||
import { CSSProperties, useCallback, useRef, useState } from "react";
|
import React, { CSSProperties, useCallback, useRef, useState } from "react";
|
||||||
import { FormattedMessage, FormattedNumber } from "react-intl";
|
import { FormattedMessage, FormattedNumber } from "react-intl";
|
||||||
import { NostrLink, TaggedNostrEvent } from "@snort/system";
|
import { NostrLink, TaggedNostrEvent } from "@snort/system";
|
||||||
import { useEventReactions } from "@snort/system-react";
|
import { useEventReactions } from "@snort/system-react";
|
||||||
@ -11,20 +11,25 @@ import useImgProxy from "@/Hooks/useImgProxy";
|
|||||||
import ProfilePreview from "@/Element/User/ProfilePreview";
|
import ProfilePreview from "@/Element/User/ProfilePreview";
|
||||||
import NoteFooter from "./NoteFooter";
|
import NoteFooter from "./NoteFooter";
|
||||||
import NoteTime from "./NoteTime";
|
import NoteTime from "./NoteTime";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
interface LongFormTextProps {
|
interface LongFormTextProps {
|
||||||
ev: TaggedNostrEvent;
|
ev: TaggedNostrEvent;
|
||||||
isPreview: boolean;
|
isPreview: boolean;
|
||||||
related: ReadonlyArray<TaggedNostrEvent>;
|
related: ReadonlyArray<TaggedNostrEvent>;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
|
truncate?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TEXT_TRUNCATE_LENGTH = 400;
|
||||||
|
|
||||||
export function LongFormText(props: LongFormTextProps) {
|
export function LongFormText(props: LongFormTextProps) {
|
||||||
const title = findTag(props.ev, "title");
|
const title = findTag(props.ev, "title");
|
||||||
const summary = findTag(props.ev, "summary");
|
const summary = findTag(props.ev, "summary");
|
||||||
const image = findTag(props.ev, "image");
|
const image = findTag(props.ev, "image");
|
||||||
const { proxy } = useImgProxy();
|
const { proxy } = useImgProxy();
|
||||||
const [reading, setReading] = useState(false);
|
const [reading, setReading] = useState(false);
|
||||||
|
const [showMore, setShowMore] = useState(false);
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const { reactions, reposts, zaps } = useEventReactions(NostrLink.fromEvent(props.ev), props.related);
|
const { reactions, reposts, zaps } = useEventReactions(NostrLink.fromEvent(props.ev), props.related);
|
||||||
|
|
||||||
@ -85,6 +90,25 @@ export function LongFormText(props: LongFormTextProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ToggleShowMore = () => (
|
||||||
|
<a
|
||||||
|
className="highlight cursor-pointer"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setShowMore(!showMore);
|
||||||
|
}}>
|
||||||
|
{showMore ? (
|
||||||
|
<FormattedMessage defaultMessage="Show less" id="qyJtWy" />
|
||||||
|
) : (
|
||||||
|
<FormattedMessage defaultMessage="Show more" id="aWpBzj" />
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
|
||||||
|
const shouldTruncate = props.truncate && props.ev.content.length > TEXT_TRUNCATE_LENGTH;
|
||||||
|
const content = shouldTruncate && !showMore ? props.ev.content.slice(0, TEXT_TRUNCATE_LENGTH) : props.ev.content;
|
||||||
|
|
||||||
function fullText() {
|
function fullText() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -113,7 +137,9 @@ export function LongFormText(props: LongFormTextProps) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<Markdown content={props.ev.content} tags={props.ev.tags} ref={ref} />
|
{shouldTruncate && showMore && <ToggleShowMore />}
|
||||||
|
<Markdown content={content} tags={props.ev.tags} ref={ref} />
|
||||||
|
{shouldTruncate && !showMore && <ToggleShowMore />}
|
||||||
<hr />
|
<hr />
|
||||||
<NoteFooter ev={props.ev} reposts={reposts} zaps={zaps} positive={reactions.positive} />
|
<NoteFooter ev={props.ev} reposts={reposts} zaps={zaps} positive={reactions.positive} />
|
||||||
</>
|
</>
|
||||||
@ -121,12 +147,7 @@ export function LongFormText(props: LongFormTextProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={classNames("long-form-note flex flex-col g16 p break-words")}>
|
||||||
className="long-form-note flex flex-col g16 p pointer"
|
|
||||||
onClick={e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
props.onClick?.();
|
|
||||||
}}>
|
|
||||||
<ProfilePreview
|
<ProfilePreview
|
||||||
pubkey={props.ev.pubkey}
|
pubkey={props.ev.pubkey}
|
||||||
actions={
|
actions={
|
||||||
|
@ -72,6 +72,7 @@ export default function Note(props: NoteProps) {
|
|||||||
related={props.related}
|
related={props.related}
|
||||||
isPreview={props.options?.longFormPreview ?? false}
|
isPreview={props.options?.longFormPreview ?? false}
|
||||||
onClick={() => props.onClick?.(ev)}
|
onClick={() => props.onClick?.(ev)}
|
||||||
|
truncate={props.options?.truncate}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user