mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-03-11 00:18:51 +01:00
Smarter logic for auto-collapsing
This logic is getting similar to HackerWeb's
This commit is contained in:
parent
54849b60a9
commit
4c188ab59b
1 changed files with 52 additions and 41 deletions
|
@ -42,7 +42,6 @@ import useTitle from '../utils/useTitle';
|
||||||
import getInstanceStatusURL from './../utils/get-instance-status-url';
|
import getInstanceStatusURL from './../utils/get-instance-status-url';
|
||||||
|
|
||||||
const LIMIT = 40;
|
const LIMIT = 40;
|
||||||
const THREAD_LIMIT = 20;
|
|
||||||
|
|
||||||
let cachedRepliesToggle = {};
|
let cachedRepliesToggle = {};
|
||||||
let cachedStatusesMap = {};
|
let cachedStatusesMap = {};
|
||||||
|
@ -293,6 +292,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
account: _r.account,
|
account: _r.account,
|
||||||
repliesCount: _r.repliesCount,
|
repliesCount: _r.repliesCount,
|
||||||
content: _r.content,
|
content: _r.content,
|
||||||
|
weight: calcStatusWeight(_r),
|
||||||
replies: expandReplies(_r.__replies),
|
replies: expandReplies(_r.__replies),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -304,13 +304,19 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
isThread: ancestorsIsThread,
|
isThread: ancestorsIsThread,
|
||||||
accountID: s.account.id,
|
accountID: s.account.id,
|
||||||
repliesCount: s.repliesCount,
|
repliesCount: s.repliesCount,
|
||||||
|
weight: calcStatusWeight(s),
|
||||||
})),
|
})),
|
||||||
{ id, accountID: heroStatus.account.id },
|
{
|
||||||
|
id,
|
||||||
|
accountID: heroStatus.account.id,
|
||||||
|
weight: calcStatusWeight(heroStatus),
|
||||||
|
},
|
||||||
...nestedDescendants.map((s) => ({
|
...nestedDescendants.map((s) => ({
|
||||||
id: s.id,
|
id: s.id,
|
||||||
accountID: s.account.id,
|
accountID: s.account.id,
|
||||||
descendant: true,
|
descendant: true,
|
||||||
thread: s.account.id === heroStatus.account.id,
|
thread: s.account.id === heroStatus.account.id,
|
||||||
|
weight: calcStatusWeight(s),
|
||||||
replies: expandReplies(s.__replies),
|
replies: expandReplies(s.__replies),
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
|
@ -412,6 +418,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
states.reloadStatusPage = 0;
|
states.reloadStatusPage = 0;
|
||||||
cachedStatusesMap = {};
|
cachedStatusesMap = {};
|
||||||
cachedRepliesToggle = {};
|
cachedRepliesToggle = {};
|
||||||
|
statusWeightCache.clear();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -458,7 +465,6 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
return statuses.length - limit;
|
return statuses.length - limit;
|
||||||
}, [statuses.length, limit]);
|
}, [statuses.length, limit]);
|
||||||
|
|
||||||
const hasManyStatuses = statuses.length > THREAD_LIMIT;
|
|
||||||
const hasDescendants = statuses.some((s) => s.descendant);
|
const hasDescendants = statuses.some((s) => s.descendant);
|
||||||
const ancestors = statuses.filter((s) => s.ancestor);
|
const ancestors = statuses.filter((s) => s.ancestor);
|
||||||
|
|
||||||
|
@ -589,6 +595,12 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const totalWeight = useMemo(() => {
|
||||||
|
return statuses.reduce((acc, status) => {
|
||||||
|
return acc + status.weight;
|
||||||
|
}, 0);
|
||||||
|
}, [id, statuses?.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
|
@ -778,6 +790,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
thread,
|
thread,
|
||||||
replies,
|
replies,
|
||||||
repliesCount,
|
repliesCount,
|
||||||
|
weight,
|
||||||
} = status;
|
} = status;
|
||||||
const isHero = statusID === id;
|
const isHero = statusID === id;
|
||||||
return (
|
return (
|
||||||
|
@ -898,10 +911,10 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
{descendant && replies?.length > 0 && (
|
{descendant && replies?.length > 0 && (
|
||||||
<SubComments
|
<SubComments
|
||||||
instance={instance}
|
instance={instance}
|
||||||
hasManyStatuses={hasManyStatuses}
|
|
||||||
replies={replies}
|
replies={replies}
|
||||||
hasParentThread={thread}
|
hasParentThread={thread}
|
||||||
level={1}
|
level={1}
|
||||||
|
accWeight={totalWeight}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{uiState === 'loading' &&
|
{uiState === 'loading' &&
|
||||||
|
@ -980,33 +993,8 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SubComments({
|
function SubComments({ replies, instance, hasParentThread, level, accWeight }) {
|
||||||
hasManyStatuses,
|
|
||||||
replies,
|
|
||||||
instance,
|
|
||||||
hasParentThread,
|
|
||||||
level,
|
|
||||||
previousOpen,
|
|
||||||
}) {
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
// Set isBrief = true:
|
|
||||||
// - if less than or 2 replies
|
|
||||||
// - if replies have no sub-replies
|
|
||||||
// - if total number of characters of content from replies is less than 500
|
|
||||||
let isBrief = false;
|
|
||||||
if (replies.length <= 2) {
|
|
||||||
const containsSubReplies = replies.some(
|
|
||||||
(r) => r.repliesCount > 0 || r.replies?.length > 0,
|
|
||||||
);
|
|
||||||
if (!containsSubReplies) {
|
|
||||||
let totalLength = replies.reduce((acc, reply) => {
|
|
||||||
const { content } = reply;
|
|
||||||
const length = htmlContentLength(content);
|
|
||||||
return acc + length;
|
|
||||||
}, 0);
|
|
||||||
isBrief = totalLength < 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Total comments count, including sub-replies
|
// Total comments count, including sub-replies
|
||||||
const diveDeep = (replies) => {
|
const diveDeep = (replies) => {
|
||||||
|
@ -1026,16 +1014,12 @@ function SubComments({
|
||||||
.slice(0, 3);
|
.slice(0, 3);
|
||||||
|
|
||||||
let open = false;
|
let open = false;
|
||||||
// const open =
|
if (accWeight < 5) {
|
||||||
// !previousOpen &&
|
open = true;
|
||||||
// (!hasParentThread || totalComments === 1) &&
|
} else if (!hasParentThread && totalComments === 1) {
|
||||||
// (isBrief || !hasManyStatuses);
|
const shortReply = calcStatusWeight(replies[0]) < 2;
|
||||||
if (hasParentThread) {
|
if (shortReply) open = true;
|
||||||
open = totalComments === 1;
|
|
||||||
} else {
|
|
||||||
open = isBrief;
|
|
||||||
}
|
}
|
||||||
if (!previousOpen && !open) open = true;
|
|
||||||
const openBefore = cachedRepliesToggle[replies[0].id];
|
const openBefore = cachedRepliesToggle[replies[0].id];
|
||||||
|
|
||||||
const handleMediaClick = useCallback((e, i, media, status) => {
|
const handleMediaClick = useCallback((e, i, media, status) => {
|
||||||
|
@ -1060,6 +1044,12 @@ function SubComments({
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const totalWeight = useMemo(() => {
|
||||||
|
return replies?.reduce((acc, reply) => {
|
||||||
|
return acc + reply?.weight;
|
||||||
|
}, 0);
|
||||||
|
}, [replies?.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<details
|
<details
|
||||||
ref={detailsRef}
|
ref={detailsRef}
|
||||||
|
@ -1134,10 +1124,9 @@ function SubComments({
|
||||||
{r.replies?.length && (
|
{r.replies?.length && (
|
||||||
<SubComments
|
<SubComments
|
||||||
instance={instance}
|
instance={instance}
|
||||||
hasManyStatuses={hasManyStatuses}
|
|
||||||
replies={r.replies}
|
replies={r.replies}
|
||||||
level={level + 1}
|
level={level + 1}
|
||||||
previousOpen={open}
|
accWeight={!open ? totalWeight : accWeight + totalWeight}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
|
@ -1147,4 +1136,26 @@ function SubComments({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MEDIA_VIRTUAL_LENGTH = 140;
|
||||||
|
const POLL_VIRTUAL_LENGTH = 35;
|
||||||
|
const CARD_VIRTUAL_LENGTH = 70;
|
||||||
|
const WEIGHT_SEGMENT = 140;
|
||||||
|
const statusWeightCache = new Map();
|
||||||
|
function calcStatusWeight(status) {
|
||||||
|
const cachedWeight = statusWeightCache.get(status.id);
|
||||||
|
if (cachedWeight) return cachedWeight;
|
||||||
|
const { spoilerText, content, mediaAttachments, poll, card } = status;
|
||||||
|
const length = htmlContentLength(spoilerText + content);
|
||||||
|
const mediaLength = mediaAttachments?.length ? MEDIA_VIRTUAL_LENGTH : 0;
|
||||||
|
const pollLength = (poll?.options?.length || 0) * POLL_VIRTUAL_LENGTH;
|
||||||
|
const cardLength =
|
||||||
|
card && (mediaAttachments?.length || poll?.options?.length)
|
||||||
|
? 0
|
||||||
|
: CARD_VIRTUAL_LENGTH;
|
||||||
|
const totalLength = length + mediaLength + pollLength + cardLength;
|
||||||
|
const weight = totalLength / WEIGHT_SEGMENT;
|
||||||
|
statusWeightCache.set(status.id, weight);
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
export default memo(StatusPage);
|
export default memo(StatusPage);
|
||||||
|
|
Loading…
Reference in a new issue