in frontend/src/js/components/viewer/CommentPanel/CommentPanel.tsx [79:142]
export function layoutComments(groups: CommentGroup[], margin: number, rootCommentId?: string): { [commentId: string]: number } {
if(groups.length === 0) {
return {};
}
// If a comment has been focused (ie selected by the user or the last one they have previously selected) then we want
// it to be next to the line it is attached to. Find the group that contains the focused comment.
const root = groups.find(({ comments }) => comments.some(({ id }) => id === rootCommentId));
const modifiedGroups = ([] as CommentGroup[]);
let ixRoot: number | undefined = undefined;
let offset = groups[0].top;
// Lay out the comment groups in order
groups.forEach((group, ix) => {
const modifiedGroup = { ...group };
if(root !== undefined && group.top === root.top) {
ixRoot = ix;
// Pull up the root group (if needed) so the focused comment is in the center
const beforeRootInGroup = takeWhile(root.comments, ({ id }) => id !== rootCommentId);
const offsetWithinGroup = sumBy(beforeRootInGroup, 'height') + (margin * beforeRootInGroup.length);
modifiedGroup.top -= offsetWithinGroup;
} else if(group.top < offset) {
// Push down the group so that it doesn't overlap with the previous group
modifiedGroup.top = offset;
}
modifiedGroups.push(modifiedGroup);
offset = (modifiedGroup.top + modifiedGroup.height) + margin;
});
if(ixRoot !== undefined) {
// Pull up any groups above the now relocated root group
let offset = modifiedGroups[ixRoot].top;
for(let i = (ixRoot - 1); i >= 0; i--) {
const group = modifiedGroups[i];
const overlap = (group.top + group.height) - offset;
if(overlap > 0) {
group.top -= overlap;
}
offset = group.top;
}
}
// Collapse each group into the individual comments and their positions
const ret = ({} as { [commentId: string]: number });
for(const group of modifiedGroups) {
let offset = 0;
for(const comment of group.comments) {
ret[comment.id] = group.top + offset;
offset += comment.height + margin;
}
}
return ret;
}