chore: Update translations

This commit is contained in:
2023-09-05 13:59:44 +00:00
parent b1459d0f49
commit df7353a43c
37 changed files with 7031 additions and 800 deletions

View File

@ -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}
/>

View File

@ -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 && (

View File

@ -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}>

View File

@ -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()}>

View File

@ -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;