Improve comments rendering

- Don't render summary/details if not needed
- Delay-render collapsed summary/details
This commit is contained in:
Lim Chee Aun 2024-10-31 18:48:13 +08:00
parent cbfd4ef333
commit 2f53fd332f
2 changed files with 132 additions and 111 deletions

8
src/locales/en.po generated
View file

@ -186,7 +186,7 @@ msgstr ""
#: src/pages/catchup.jsx:1445
#: src/pages/catchup.jsx:2056
#: src/pages/status.jsx:921
#: src/pages/status.jsx:1523
#: src/pages/status.jsx:1543
msgid "Replies"
msgstr ""
@ -3636,15 +3636,15 @@ msgstr ""
msgid "Unable to load post"
msgstr ""
#: src/pages/status.jsx:1455
#: src/pages/status.jsx:1473
msgid "{0, plural, one {# reply} other {<0>{1}</0> replies}}"
msgstr ""
#: src/pages/status.jsx:1473
#: src/pages/status.jsx:1491
msgid "{totalComments, plural, one {# comment} other {<0>{0}</0> comments}}"
msgstr ""
#: src/pages/status.jsx:1495
#: src/pages/status.jsx:1513
msgid "View post with its replies"
msgstr ""

View file

@ -1423,130 +1423,151 @@ function SubComments({
};
}, []);
// If not open, delay render replies
const [renderReplies, setRenderReplies] = useState(openBefore || open);
useEffect(() => {
let timer;
if (!openBefore && !open) {
timer = setTimeout(() => setRenderReplies(true), 100);
}
return () => clearTimeout(timer);
}, [openBefore, open]);
const Container = open ? 'div' : 'details';
const isDetails = Container === 'details';
return (
<details
<Container
ref={detailsRef}
class="replies"
open={openBefore || open}
onToggle={(e) => {
const { open } = e.target;
// use first reply as ID
cachedRepliesToggle[replies[0].id] = open;
}}
open={isDetails ? openBefore || open : undefined}
onToggle={
isDetails
? (e) => {
const { open } = e.target;
// use first reply as ID
cachedRepliesToggle[replies[0].id] = open;
}
: undefined
}
style={{
'--comments-level': level,
}}
data-comments-level={level}
data-comments-level-overflow={level > 4}
>
<summary class="replies-summary" hidden={open}>
<span class="avatars">
{accounts.map((a) => (
<Avatar
key={a.id}
url={a.avatarStatic}
title={`${a.displayName} @${a.username}`}
squircle={a?.bot}
/>
))}
</span>
<span class="replies-counts">
<b>
<Plural
value={replies.length}
one="# reply"
other={
<Trans>
<span title={replies.length}>
{shortenNumber(replies.length)}
</span>{' '}
replies
</Trans>
}
/>
</b>
{!sameCount && totalComments > 1 && (
<>
{' '}
&middot;{' '}
<span>
<Plural
value={totalComments}
one="# comment"
other={
<Trans>
<span title={totalComments}>
{shortenNumber(totalComments)}
</span>{' '}
comments
</Trans>
}
/>
</span>
</>
{!open && (
<summary class="replies-summary" hidden={open}>
<span class="avatars">
{accounts.map((a) => (
<Avatar
key={a.id}
url={a.avatarStatic}
title={`${a.displayName} @${a.username}`}
squircle={a?.bot}
/>
))}
</span>
<span class="replies-counts">
<b>
<Plural
value={replies.length}
one="# reply"
other={
<Trans>
<span title={replies.length}>
{shortenNumber(replies.length)}
</span>{' '}
replies
</Trans>
}
/>
</b>
{!sameCount && totalComments > 1 && (
<>
{' '}
&middot;{' '}
<span>
<Plural
value={totalComments}
one="# comment"
other={
<Trans>
<span title={totalComments}>
{shortenNumber(totalComments)}
</span>{' '}
comments
</Trans>
}
/>
</span>
</>
)}
</span>
<Icon icon="chevron-down" class="replies-summary-chevron" />
{!!parentLink && (
<Link
class="replies-parent-link"
to={parentLink.to}
onClick={parentLink.onClick}
title={t`View post with its replies`}
>
&raquo;
</Link>
)}
</span>
<Icon icon="chevron-down" class="replies-summary-chevron" />
{!!parentLink && (
<Link
class="replies-parent-link"
to={parentLink.to}
onClick={parentLink.onClick}
title={t`View post with its replies`}
>
&raquo;
</Link>
)}
</summary>
<ul>
{replies.map((r) => (
<li key={r.id}>
{/* <Link
</summary>
)}
{renderReplies && (
<ul>
{replies.map((r) => (
<li key={r.id}>
{/* <Link
class="status-link"
to={instance ? `/${instance}/s/${r.id}` : `/s/${r.id}`}
onClick={() => {
resetScrollPosition(r.id);
}}
> */}
<div class="status-focus" tabIndex={0}>
<Status
statusID={r.id}
instance={instance}
withinContext
size="s"
enableTranslate
onMediaClick={handleMediaClick}
showActionsBar
/>
{!r.replies?.length && r.repliesCount > 0 && (
<div class="replies-link">
<Icon icon="comment2" alt={t`Replies`} />{' '}
<span title={r.repliesCount}>
{shortenNumber(r.repliesCount)}
</span>
</div>
<div class="status-focus" tabIndex={0}>
<Status
statusID={r.id}
instance={instance}
withinContext
size="s"
enableTranslate
onMediaClick={handleMediaClick}
showActionsBar
/>
{!r.replies?.length && r.repliesCount > 0 && (
<div class="replies-link">
<Icon icon="comment2" alt={t`Replies`} />{' '}
<span title={r.repliesCount}>
{shortenNumber(r.repliesCount)}
</span>
</div>
)}
</div>
{/* </Link> */}
{r.replies?.length && (
<SubComments
instance={instance}
replies={r.replies}
level={r.level}
accWeight={!open ? r.weight : totalWeight}
openAll={openAll}
parentLink={{
to: instance ? `/${instance}/s/${r.id}` : `/s/${r.id}`,
onClick: () => {
resetScrollPosition(r.id);
},
}}
/>
)}
</div>
{/* </Link> */}
{r.replies?.length && (
<SubComments
instance={instance}
replies={r.replies}
level={r.level}
accWeight={!open ? r.weight : totalWeight}
openAll={openAll}
parentLink={{
to: instance ? `/${instance}/s/${r.id}` : `/s/${r.id}`,
onClick: () => {
resetScrollPosition(r.id);
},
}}
/>
)}
</li>
))}
</ul>
</details>
</li>
))}
</ul>
)}
</Container>
);
}