diff --git a/packages/web/components/patterns/LibraryCards/LibraryHighlightGridCard.tsx b/packages/web/components/patterns/LibraryCards/LibraryHighlightGridCard.tsx
index 2358c10f3..3ad9d9fe1 100644
--- a/packages/web/components/patterns/LibraryCards/LibraryHighlightGridCard.tsx
+++ b/packages/web/components/patterns/LibraryCards/LibraryHighlightGridCard.tsx
@@ -1,5 +1,5 @@
import { Box, VStack, HStack } from '../../elements/LayoutPrimitives'
-import { useState } from 'react'
+import { useMemo, useState } from 'react'
import { CaretDown, CaretUp } from 'phosphor-react'
import { MetaStyle, timeAgo, TitleStyle } from './LibraryCardStyles'
import { styled } from '@stitches/react'
@@ -8,6 +8,7 @@ import { LibraryItemNode } from '../../../lib/networking/queries/useGetLibraryIt
import { Button } from '../../elements/Button'
import { theme } from '../../tokens/stitches.config'
import { HighlightItem } from '../../templates/homeFeed/HighlightItem'
+import { getHighlightLocation } from '../../templates/article/NotebookModal'
export const GridSeparator = styled(Box, {
height: '1px',
@@ -23,11 +24,42 @@ type LibraryHighlightGridCardProps = {
export function LibraryHighlightGridCard(
props: LibraryHighlightGridCardProps
): JSX.Element {
- const [isHovered, setIsHovered] = useState(false)
const [expanded, setExpanded] = useState(false)
const higlightCount = props.item.highlights?.length ?? 0
+ const sortedHighlights = useMemo(() => {
+ const sorted = (a: number, b: number) => {
+ if (a < b) {
+ return -1
+ }
+ if (a > b) {
+ return 1
+ }
+ return 0
+ }
+
+ if (!props.item.highlights) {
+ return []
+ }
+
+ return props.item.highlights.sort((a: Highlight, b: Highlight) => {
+ if (a.highlightPositionPercent && b.highlightPositionPercent) {
+ return sorted(a.highlightPositionPercent, b.highlightPositionPercent)
+ }
+ // We do this in a try/catch because it might be an invalid diff
+ // With PDF it will definitely be an invalid diff.
+ try {
+ const aPos = getHighlightLocation(a.patch)
+ const bPos = getHighlightLocation(b.patch)
+ if (aPos && bPos) {
+ return sorted(aPos, bPos)
+ }
+ } catch {}
+ return a.createdAt.localeCompare(b.createdAt)
+ })
+ }, [props.item.highlights])
+
return (
{
- setIsHovered(true)
- }}
- onMouseLeave={() => {
- setIsHovered(false)
- }}
>
{!expanded && (
- {(props.item.highlights ?? []).map((highlight) => (
+ {sortedHighlights.map((highlight) => (
) : null}
{isEditing && (
-
)
}
-
-type TextEditAreaProps = {
- setIsEditing: (editing: boolean) => void
- highlight: Highlight
- updateHighlight: (highlight: Highlight) => void
-}
-
-export const TextEditArea = (props: TextEditAreaProps): JSX.Element => {
- const [noteContent, setNoteContent] = useState(
- props.highlight.annotation ?? ''
- )
-
- const handleNoteContentChange = useCallback(
- (event: React.ChangeEvent): void => {
- setNoteContent(event.target.value)
- },
- [setNoteContent]
- )
-
- return (
-
-
-
-
-
-
-
- )
-}
diff --git a/packages/web/components/templates/homeFeed/HighlightItem.tsx b/packages/web/components/templates/homeFeed/HighlightItem.tsx
index ff2022bff..2b40a961d 100644
--- a/packages/web/components/templates/homeFeed/HighlightItem.tsx
+++ b/packages/web/components/templates/homeFeed/HighlightItem.tsx
@@ -1,12 +1,16 @@
import { styled } from '@stitches/react'
import { useRouter } from 'next/router'
import { DotsThreeVertical } from 'phosphor-react'
-import { Fragment, useMemo, useState } from 'react'
+import { Fragment, useCallback, useMemo, useState } from 'react'
import { Highlight } from '../../../lib/networking/fragments/highlightFragment'
import { Label } from '../../../lib/networking/fragments/labelFragment'
+import { deleteHighlightMutation } from '../../../lib/networking/mutations/deleteHighlightMutation'
+import { setLabelsForHighlight } from '../../../lib/networking/mutations/setLabelsForHighlight'
import { LibraryItemNode } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
+import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
import { Dropdown, DropdownOption } from '../../elements/DropdownElements'
+import { HighlightNoteTextEditArea } from '../../elements/HighlightNoteTextEditArea'
import { LabelChip } from '../../elements/LabelChip'
import {
Blockquote,
@@ -16,6 +20,8 @@ import {
VStack,
} from '../../elements/LayoutPrimitives'
import { StyledText } from '../../elements/StyledText'
+import { ConfirmationModal } from '../../patterns/ConfirmationModal'
+import { SetLabelsModal } from '../article/SetLabelsModal'
type HighlightItemProps = {
highlight: Highlight
@@ -44,89 +50,162 @@ export function HighlightItem(props: HighlightItemProps): JSX.Element {
[props.highlight.quote]
)
+ const [showConfirmDeleteHighlightId, setShowConfirmDeleteHighlightId] =
+ useState(undefined)
+ const [labelsTarget, setLabelsTarget] = useState(
+ undefined
+ )
+ const [, updateState] = useState({})
+
return (
- setHover(true)}
- onMouseLeave={() => setHover(false)}
- >
- {
- if (router && props.viewer) {
- const dest = `/${props.viewer}/${props.item.slug}#${props.highlight.id}`
- router.push(dest)
- }
- event.preventDefault()
- }}
+ <>
+ setHover(true)}
+ onMouseLeave={() => setHover(false)}
>
-
-
- {lines.map((line: string, index: number) => (
-
- {line}
- {index !== lines.length - 1 && (
- <>
-
-
- >
- )}
-
- ))}
-
-
- {props.highlight.labels?.map((label: Label, index: number) => (
-
- ))}
-
-
-
- setIsEditing(true)}
+ alignment="start"
+ distribution="start"
>
- {props.highlight.annotation
- ? props.highlight.annotation
- : 'Add your notes...'}
-
-
-
-
-
-
+ {
+ if (router && props.viewer) {
+ const dest = `/${props.viewer}/${props.item.slug}#${props.highlight.id}`
+ router.push(dest)
+ }
+ event.preventDefault()
+ }}
+ >
+
+ {lines.map((line: string, index: number) => (
+
+ {line}
+ {index !== lines.length - 1 && (
+ <>
+
+
+ >
+ )}
+
+ ))}
+
+
+ {props.highlight.labels?.map((label: Label, index: number) => (
+
+ ))}
+
+
+
+ {!isEditing && (
+ setIsEditing(true)}
+ >
+ {props.highlight.annotation
+ ? props.highlight.annotation
+ : 'Add your notes...'}
+
+ )}
+ {isEditing && (
+ {}}
+ />
+ )}
+
+
+
+
+
+ {showConfirmDeleteHighlightId && (
+ {
+ setShowConfirmDeleteHighlightId(undefined)
+ const result = await deleteHighlightMutation(
+ showConfirmDeleteHighlightId
+ )
+ if (result) {
+ showSuccessToast('Highlight deleted')
+ } else {
+ showErrorToast('Error deleting highlight')
+ }
+ }}
+ onOpenChange={() => setShowConfirmDeleteHighlightId(undefined)}
+ />
+ )}
+ {labelsTarget && (
+ {
+ const result = setLabelsForHighlight(
+ labelsTarget.id,
+ labels.map((label) => label.id)
+ )
+ return result
+ }}
+ />
+ )}
+ >
)
}
-function HighlightsMenu(): JSX.Element {
+type HighlightsMenuProps = {
+ highlight: Highlight
+
+ setLabelsTarget: (target: Highlight) => void
+ setShowConfirmDeleteHighlightId: (set: string) => void
+}
+
+function HighlightsMenu(props: HighlightsMenuProps): JSX.Element {
+ const copyHighlight = useCallback(() => {
+ ;(async () => {
+ await navigator.clipboard.writeText(props.highlight.quote)
+ showSuccessToast('Highlight copied')
+ })()
+ }, [props.highlight])
+
return (
{
- console.log('copy')
+ onSelect={async () => {
+ copyHighlight()
}}
title="Copy"
/>
{
- console.log('labels')
+ props.setLabelsTarget(props.highlight)
}}
title="Labels"
/>
- {
- console.log('delete')
+ props.setShowConfirmDeleteHighlightId(props.highlight.id)
}}
title="Delete"
- />
+ /> */}
)
}
diff --git a/packages/web/components/templates/homeFeed/HighlightsLayout.tsx b/packages/web/components/templates/homeFeed/HighlightsLayout.tsx
index 5fe514e0a..5f99162d5 100644
--- a/packages/web/components/templates/homeFeed/HighlightsLayout.tsx
+++ b/packages/web/components/templates/homeFeed/HighlightsLayout.tsx
@@ -1,5 +1,6 @@
import { DotsThreeVertical, HighlighterCircle } from 'phosphor-react'
import { useEffect, useState } from 'react'
+import { Toaster } from 'react-hot-toast'
import { LibraryItem } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
@@ -46,6 +47,7 @@ export function HighlightItemsLayout(
distribution="start"
alignment="start"
>
+