chore: Update translations
This commit is contained in:
@ -106,7 +106,7 @@ export default function Note(props: NoteProps) {
|
||||
return <ZapGoal ev={ev} />;
|
||||
}
|
||||
|
||||
return <NoteInner {...props} />
|
||||
return <NoteInner {...props} />;
|
||||
}
|
||||
|
||||
export function NoteInner(props: NoteProps) {
|
||||
@ -393,7 +393,7 @@ export function NoteInner(props: NoteProps) {
|
||||
{options.showContextMenu && (
|
||||
<NoteContextMenu
|
||||
ev={ev}
|
||||
react={async () => { }}
|
||||
react={async () => {}}
|
||||
onTranslated={t => setTranslated(t)}
|
||||
setShowReactions={setShowReactions}
|
||||
/>
|
||||
|
@ -116,7 +116,13 @@ export default function Poll(props: PollProps) {
|
||||
{opt === voting ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<Text id={props.ev.id} content={desc} tags={props.ev.tags} creator={props.ev.pubkey} disableMediaSpotlight={true} />
|
||||
<Text
|
||||
id={props.ev.id}
|
||||
content={desc}
|
||||
tags={props.ev.tags}
|
||||
creator={props.ev.pubkey}
|
||||
disableMediaSpotlight={true}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{showResults && (
|
||||
|
@ -37,7 +37,7 @@ export default function Text({
|
||||
disableLinkPreview,
|
||||
truncate,
|
||||
className,
|
||||
onClick
|
||||
onClick,
|
||||
}: TextProps) {
|
||||
const [showSpotlight, setShowSpotlight] = useState(false);
|
||||
const [imageIdx, setImageIdx] = useState(0);
|
||||
@ -60,7 +60,7 @@ export default function Text({
|
||||
return null;
|
||||
} else if (lenCtr + a.content.length > truncate) {
|
||||
lenCtr += a.content.length;
|
||||
return <div className="text-frag">{a.content.slice(0, truncate - lenCtr)}...</div>
|
||||
return <div className="text-frag">{a.content.slice(0, truncate - lenCtr)}...</div>;
|
||||
} else {
|
||||
lenCtr += a.content.length;
|
||||
}
|
||||
@ -109,7 +109,7 @@ export default function Text({
|
||||
}
|
||||
|
||||
return elements.map(a => renderChunk(a));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div dir="auto" className={`text${className ? ` ${className}` : ""}`} onClick={onClick}>
|
||||
|
@ -106,7 +106,9 @@ const Timeline = (props: TimelineProps) => {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{mainFeed.map(e => <Note key={e.id} data={e} related={relatedFeed(e.id)} ignoreModeration={props.ignoreModeration} depth={0} />)}
|
||||
{mainFeed.map(e => (
|
||||
<Note key={e.id} data={e} related={relatedFeed(e.id)} ignoreModeration={props.ignoreModeration} depth={0} />
|
||||
))}
|
||||
{(props.loadMore === undefined || props.loadMore === true) && (
|
||||
<div className="flex f-center">
|
||||
<button type="button" onClick={() => feed.loadMore()}>
|
||||
|
@ -18,101 +18,110 @@ import ProfileImage from "Element/ProfileImage";
|
||||
import Icon from "Icons/Icon";
|
||||
|
||||
export interface TimelineFollowsProps {
|
||||
postsOnly: boolean;
|
||||
postsOnly: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of notes by "subject"
|
||||
*/
|
||||
const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
const [latest, setLatest] = useState(unixNow());
|
||||
const feed = useSyncExternalStore(cb => FollowsFeed.hook(cb, "*"), () => FollowsFeed.snapshot())
|
||||
const reactions = useReactions("follows-feed-reactions", feed.map(a => a.id));
|
||||
const system = useContext(SnortContext);
|
||||
const login = useLogin();
|
||||
const { muted, isMuted } = useModeration();
|
||||
const { ref, inView } = useInView();
|
||||
const [latest, setLatest] = useState(unixNow());
|
||||
const feed = useSyncExternalStore(
|
||||
cb => FollowsFeed.hook(cb, "*"),
|
||||
() => FollowsFeed.snapshot()
|
||||
);
|
||||
const reactions = useReactions(
|
||||
"follows-feed-reactions",
|
||||
feed.map(a => a.id)
|
||||
);
|
||||
const system = useContext(SnortContext);
|
||||
const login = useLogin();
|
||||
const { muted, isMuted } = useModeration();
|
||||
const { ref, inView } = useInView();
|
||||
|
||||
const sortedFeed = useMemo(() => orderDescending(feed), [feed]);
|
||||
const sortedFeed = useMemo(() => orderDescending(feed), [feed]);
|
||||
|
||||
const filterPosts = useCallback(
|
||||
function <T extends NostrEvent>(nts: Array<T>) {
|
||||
const a = nts.filter(a => a.kind !== EventKind.LiveEvent);
|
||||
return a
|
||||
?.filter(a => (props.postsOnly ? !a.tags.some(b => b[0] === "e") : true))
|
||||
.filter(a => !isMuted(a.pubkey) && login.follows.item.includes(a.pubkey));
|
||||
},
|
||||
[props.postsOnly, muted, login.follows.timestamp]
|
||||
);
|
||||
const filterPosts = useCallback(
|
||||
function <T extends NostrEvent>(nts: Array<T>) {
|
||||
const a = nts.filter(a => a.kind !== EventKind.LiveEvent);
|
||||
return a
|
||||
?.filter(a => (props.postsOnly ? !a.tags.some(b => b[0] === "e") : true))
|
||||
.filter(a => !isMuted(a.pubkey) && login.follows.item.includes(a.pubkey));
|
||||
},
|
||||
[props.postsOnly, muted, login.follows.timestamp]
|
||||
);
|
||||
|
||||
const mainFeed = useMemo(() => {
|
||||
return filterPosts((sortedFeed ?? []).filter(a => a.created_at <= latest));
|
||||
}, [sortedFeed, filterPosts, latest, login.follows.timestamp]);
|
||||
const mainFeed = useMemo(() => {
|
||||
return filterPosts((sortedFeed ?? []).filter(a => a.created_at <= latest));
|
||||
}, [sortedFeed, filterPosts, latest, login.follows.timestamp]);
|
||||
|
||||
const latestFeed = useMemo(() => {
|
||||
return filterPosts((sortedFeed ?? []).filter(a => a.created_at > latest));
|
||||
}, [sortedFeed, latest]);
|
||||
const latestFeed = useMemo(() => {
|
||||
return filterPosts((sortedFeed ?? []).filter(a => a.created_at > latest));
|
||||
}, [sortedFeed, latest]);
|
||||
|
||||
const relatedFeed = useCallback(
|
||||
(id: u256) => {
|
||||
return (reactions?.data ?? []).filter(a => findTag(a, "e") === id);
|
||||
},
|
||||
[reactions]
|
||||
);
|
||||
const relatedFeed = useCallback(
|
||||
(id: u256) => {
|
||||
return (reactions?.data ?? []).filter(a => findTag(a, "e") === id);
|
||||
},
|
||||
[reactions]
|
||||
);
|
||||
|
||||
const liveStreams = useMemo(() => {
|
||||
return (sortedFeed ?? []).filter(a => a.kind === EventKind.LiveEvent && findTag(a, "status") === "live");
|
||||
}, [sortedFeed]);
|
||||
const liveStreams = useMemo(() => {
|
||||
return (sortedFeed ?? []).filter(a => a.kind === EventKind.LiveEvent && findTag(a, "status") === "live");
|
||||
}, [sortedFeed]);
|
||||
|
||||
const latestAuthors = useMemo(() => {
|
||||
return dedupeByPubkey(latestFeed).map(e => e.pubkey);
|
||||
}, [latestFeed]);
|
||||
const latestAuthors = useMemo(() => {
|
||||
return dedupeByPubkey(latestFeed).map(e => e.pubkey);
|
||||
}, [latestFeed]);
|
||||
|
||||
function onShowLatest(scrollToTop = false) {
|
||||
setLatest(unixNow());
|
||||
if (scrollToTop) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
function onShowLatest(scrollToTop = false) {
|
||||
setLatest(unixNow());
|
||||
if (scrollToTop) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
return (
|
||||
<>
|
||||
<LiveStreams evs={liveStreams} />
|
||||
{latestFeed.length > 0 && (
|
||||
<>
|
||||
<LiveStreams evs={liveStreams} />
|
||||
{latestFeed.length > 0 && (
|
||||
<>
|
||||
<div className="card latest-notes" onClick={() => onShowLatest()} ref={ref}>
|
||||
{latestAuthors.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
values={{ n: latestFeed.length }}
|
||||
/>
|
||||
<Icon name="arrowUp" />
|
||||
</div>
|
||||
{!inView && (
|
||||
<div className="card latest-notes latest-notes-fixed pointer fade-in" onClick={() => onShowLatest(true)}>
|
||||
{latestAuthors.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
values={{ n: latestFeed.length }}
|
||||
/>
|
||||
<Icon name="arrowUp" />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{mainFeed.map(a => <Note data={a as TaggedNostrEvent} related={relatedFeed(a.id)} key={a.id} depth={0} />)}
|
||||
<div className="flex f-center p">
|
||||
<AsyncButton onClick={async () => {
|
||||
await FollowsFeed.loadMore(system, login, sortedFeed[sortedFeed.length - 1].created_at);
|
||||
}}>
|
||||
<FormattedMessage defaultMessage="Load more" />
|
||||
</AsyncButton>
|
||||
<div className="card latest-notes" onClick={() => onShowLatest()} ref={ref}>
|
||||
{latestAuthors.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
values={{ n: latestFeed.length }}
|
||||
/>
|
||||
<Icon name="arrowUp" />
|
||||
</div>
|
||||
{!inView && (
|
||||
<div className="card latest-notes latest-notes-fixed pointer fade-in" onClick={() => onShowLatest(true)}>
|
||||
{latestAuthors.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
values={{ n: latestFeed.length }}
|
||||
/>
|
||||
<Icon name="arrowUp" />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
)}
|
||||
{mainFeed.map(a => (
|
||||
<Note data={a as TaggedNostrEvent} related={relatedFeed(a.id)} key={a.id} depth={0} />
|
||||
))}
|
||||
<div className="flex f-center p">
|
||||
<AsyncButton
|
||||
onClick={async () => {
|
||||
await FollowsFeed.loadMore(system, login, sortedFeed[sortedFeed.length - 1].created_at);
|
||||
}}>
|
||||
<FormattedMessage defaultMessage="Load more" />
|
||||
</AsyncButton>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default TimelineFollows;
|
||||
|
Reference in New Issue
Block a user