Skip to content

Commit

Permalink
Add support for highly nested comments (#907)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeharding authored Nov 8, 2023
1 parent 21ffcfb commit 60510ee
Show file tree
Hide file tree
Showing 10 changed files with 404 additions and 105 deletions.
9 changes: 9 additions & 0 deletions src/TabbedRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,15 @@ export default function TabbedRoutes() {
</ActorRedirect>
</Route>,
// eslint-disable-next-line react/jsx-key
<Route
exact
path={`/${tab}/:actor/c/:community/comments/:id/thread/:threadCommentId`}
>
<ActorRedirect>
<PostDetail />
</ActorRedirect>
</Route>,
// eslint-disable-next-line react/jsx-key
<Route
exact
path={`/${tab}/:actor/c/:community/comments/:id/:commentPath`}
Expand Down
35 changes: 10 additions & 25 deletions src/features/comment/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IonIcon, IonItem } from "@ionic/react";
import { chevronDownOutline } from "ionicons/icons";
import { CommentView } from "lemmy-js-client";
import { css } from "@emotion/react";
import React, { MouseEvent, useEffect, useRef } from "react";
import React, { MouseEvent } from "react";
import Ago from "../labels/Ago";
import { maxWidthCss } from "../shared/AppContent";
import PersonLink from "../labels/links/PersonLink";
Expand All @@ -16,10 +16,6 @@ import CommentEllipsis from "./CommentEllipsis";
import { useAppSelector } from "../../store";
import Save from "../labels/Save";
import Edited from "../labels/Edited";
import {
scrollIntoView as scrollIntoView,
useScrollIntoViewWorkaround,
} from "../../helpers/dom";

const rainbowColors = [
"#FF0000", // Red
Expand Down Expand Up @@ -177,6 +173,7 @@ interface CommentProps {
comment: CommentView;
highlightedCommentId?: number;
depth?: number;
absoluteDepth?: number;
onClick?: (e: MouseEvent) => void;
collapsed?: boolean;
fullyCollapsed?: boolean;
Expand All @@ -194,6 +191,7 @@ export default function Comment({
comment: commentView,
highlightedCommentId,
depth,
absoluteDepth,
onClick,
collapsed,
fullyCollapsed,
Expand All @@ -202,25 +200,12 @@ export default function Comment({
className,
rootIndex,
}: CommentProps) {
const commentById = useAppSelector((state) => state.comment.commentById);
// eslint-disable-next-line no-undef
const commentRef = useRef<HTMLIonItemElement>(null);
const commentFromStore = useAppSelector(
(state) => state.comment.commentById[commentView.comment.id],
);

// Comment from slice might be more up to date, e.g. edits
const comment = commentById[commentView.comment.id] ?? commentView.comment;

useEffect(() => {
if (highlightedCommentId !== comment.id) return;

setTimeout(
() => {
if (!commentRef.current) return;

scrollIntoView(commentRef.current, 100);
},
useScrollIntoViewWorkaround ? 50 : 600,
);
}, [highlightedCommentId, comment]);
const comment = commentFromStore ?? commentView.comment;

return (
<AnimateHeight duration={200} height={fullyCollapsed ? 0 : "auto"}>
Expand All @@ -234,13 +219,13 @@ export default function Comment({
routerLink={routerLink}
href={undefined}
onClick={(e) => onClick?.(e)}
ref={commentRef}
className={`comment-${comment.id}`}
>
<PositionedContainer
depth={depth || 0}
depth={absoluteDepth === depth ? depth || 0 : (depth || 0) + 1}
highlighted={highlightedCommentId === comment.id}
>
<Container depth={depth || 0}>
<Container depth={absoluteDepth ?? depth ?? 0}>
<Header>
<StyledPersonLabel
person={commentView.creator}
Expand Down
11 changes: 8 additions & 3 deletions src/features/comment/CommentExpander.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ const StyledIonSpinner = styled(IonSpinner)`

interface CommentExpanderProps {
depth: number;
absoluteDepth: number;
comment: CommentView;
missing: number;
collapsed?: boolean;
}

export default function CommentExpander({
depth,
absoluteDepth,
comment,
missing,
collapsed,
Expand Down Expand Up @@ -95,10 +97,13 @@ export default function CommentExpander({

return (
<AnimateHeight duration={200} height={collapsed ? 0 : "auto"}>
<CommentHr depth={depth - 1} />
<CommentHr depth={depth} />
<CustomIonItem href={undefined} onClick={fetchChildren}>
<PositionedContainer depth={depth || 0} highlighted={false}>
<Container depth={depth || 0} hidden={loading}>
<PositionedContainer
depth={absoluteDepth === depth ? depth + 1 : depth + 2}
highlighted={false}
>
<Container depth={absoluteDepth + 1} hidden={loading}>
<MoreRepliesBlock hidden={loading}>
{missing} more {missing === 1 ? "reply" : "replies"}
<ChevronIcon icon={chevronDown} />
Expand Down
37 changes: 34 additions & 3 deletions src/features/comment/CommentTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { Person } from "lemmy-js-client";
import CommentExpander from "./CommentExpander";
import { OTapToCollapseType } from "../../services/db";
import { getOffsetTop, scrollIntoView } from "../../helpers/dom";
import ContinueThread from "./ContinueThread";

export const MAX_COMMENT_DEPTH = 10;

interface CommentTreeProps {
comment: CommentNodeI;
Expand All @@ -16,6 +19,7 @@ interface CommentTreeProps {
op: Person;
fullyCollapsed?: boolean;
rootIndex: number;
baseDepth: number;
}

export default function CommentTree({
Expand All @@ -25,6 +29,7 @@ export default function CommentTree({
op,
fullyCollapsed,
rootIndex,
baseDepth,
}: CommentTreeProps) {
const dispatch = useAppDispatch();
const collapsed = useAppSelector(
Expand Down Expand Up @@ -58,14 +63,38 @@ export default function CommentTree({
);
}

if (
comment.absoluteDepth - baseDepth > MAX_COMMENT_DEPTH &&
comment.comment_view.counts.child_count >= 2
) {
return (
<ContinueThread
depth={comment.absoluteDepth - baseDepth}
absoluteDepth={comment.absoluteDepth}
key={comment.comment_view.comment.id}
collapsed={collapsed || fullyCollapsed}
comment={comment}
/>
);
}

// eslint-disable-next-line no-sparse-arrays
const payload = [
<React.Fragment key={comment.comment_view.comment.id}>
{!first && <CommentHr depth={comment.depth} />}
{!first && (
<CommentHr
depth={
!comment.absoluteDepth
? 0
: Math.max(1, comment.absoluteDepth - baseDepth)
}
/>
)}
<Comment
comment={comment.comment_view}
highlightedCommentId={highlightedCommentId}
depth={comment.depth}
depth={comment.absoluteDepth - baseDepth}
absoluteDepth={comment.absoluteDepth}
onClick={(e) => {
if (
tapToCollapse === OTapToCollapseType.Neither ||
Expand All @@ -90,6 +119,7 @@ export default function CommentTree({
op={op}
fullyCollapsed={collapsed || fullyCollapsed}
rootIndex={rootIndex}
baseDepth={baseDepth}
/>
)),
];
Expand All @@ -99,7 +129,8 @@ export default function CommentTree({
<CommentExpander
key={`${comment.comment_view.comment.id}--expand`}
comment={comment.comment_view}
depth={comment.depth + 1}
depth={comment.absoluteDepth - baseDepth}
absoluteDepth={comment.absoluteDepth}
missing={comment.missing}
collapsed={collapsed || fullyCollapsed}
/>,
Expand Down
Loading

0 comments on commit 60510ee

Please sign in to comment.