From a4ed72439faf97c6fc6f8087d1215244ab2cec73 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 1 Feb 2023 17:00:09 +0800 Subject: [PATCH] Sort highlights in notebooks --- .../templates/article/NotebookModal.tsx | 37 +++++++++++++++++-- .../networking/fragments/highlightFragment.ts | 2 + 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/web/components/templates/article/NotebookModal.tsx b/packages/web/components/templates/article/NotebookModal.tsx index 4215435c4..a629f6fdf 100644 --- a/packages/web/components/templates/article/NotebookModal.tsx +++ b/packages/web/components/templates/article/NotebookModal.tsx @@ -17,7 +17,7 @@ import { TrashIcon } from '../../elements/images/TrashIcon' import { theme } from '../../tokens/stitches.config' import type { Highlight } from '../../../lib/networking/fragments/highlightFragment' import { HighlightView } from '../../patterns/HighlightView' -import { useCallback, useRef, useState } from 'react' +import { useCallback, useMemo, useRef, useState } from 'react' import { StyledTextArea } from '../../elements/StyledTextArea' import { ConfirmationModal } from '../../patterns/ConfirmationModal' import { DotsThree } from 'phosphor-react' @@ -27,6 +27,7 @@ import { Label } from '../../../lib/networking/fragments/labelFragment' import { setLabelsForHighlight } from '../../../lib/networking/mutations/setLabelsForHighlight' import { updateHighlightMutation } from '../../../lib/networking/mutations/updateHighlightMutation' import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers' +import { diff_match_patch } from 'diff-match-patch' type NotebookModalProps = { highlights: Highlight[] @@ -36,6 +37,12 @@ type NotebookModalProps = { onOpenChange: (open: boolean) => void } +export const getHighlightLocation = (patch: string): number | undefined => { + const dmp = new diff_match_patch() + const patches = dmp.patch_fromText(patch) + return patches[0].start1 || undefined +} + export function NotebookModal(props: NotebookModalProps): JSX.Element { const [showConfirmDeleteHighlightId, setShowConfirmDeleteHighlightId] = useState(undefined) @@ -44,6 +51,30 @@ export function NotebookModal(props: NotebookModalProps): JSX.Element { ) const [, updateState] = useState({}) + const sortedHighlights = useMemo(() => { + const sorted = (a: number, b: number) => { + if (a < b) { + return -1 + } + if (a > b) { + return 1 + } + return 0 + } + + return props.highlights.sort((a: Highlight, b: Highlight) => { + if (a.highlightPositionPercent && b.highlightPositionPercent) { + return sorted(a.highlightPositionPercent, b.highlightPositionPercent) + } + const aPos = getHighlightLocation(a.patch) + const bPos = getHighlightLocation(b.patch) + if (aPos && bPos) { + return sorted(aPos, bPos) + } + return a.createdAt.localeCompare(b.createdAt) + }) + }, [props.highlights]) + return ( @@ -57,7 +88,7 @@ export function NotebookModal(props: NotebookModalProps): JSX.Element { - {props.highlights.map((highlight) => ( + {sortedHighlights.map((highlight) => ( ))} - {props.highlights.length === 0 && ( + {sortedHighlights.length === 0 && ( You have not added any highlights or notes to this document diff --git a/packages/web/lib/networking/fragments/highlightFragment.ts b/packages/web/lib/networking/fragments/highlightFragment.ts index d7ca16cf4..47a938a6c 100644 --- a/packages/web/lib/networking/fragments/highlightFragment.ts +++ b/packages/web/lib/networking/fragments/highlightFragment.ts @@ -11,6 +11,7 @@ export const highlightFragment = gql` patch annotation createdByMe + createdAt updatedAt sharedAt highlightPositionPercent @@ -33,6 +34,7 @@ export type Highlight = { patch: string annotation?: string createdByMe: boolean + createdAt: string updatedAt: string sharedAt: string labels?: Label[]