Merge pull request #1477 from omnivore-app/feat/web-pdf-notes

Allow creating notes on PDF highlights
This commit is contained in:
Jackson Harper 2022-11-30 10:46:54 +08:00 committed by GitHub
commit f0aaceabea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 14 deletions

View file

@ -35,11 +35,17 @@ export function HighlightNoteModal(
props.highlight?.annotation ?? ''
)
useConfirmListener(() => {
saveNoteChanges()
}, undefined, true)
useConfirmListener(
() => {
saveNoteChanges()
},
undefined,
true
)
const updatedAtMessage = props.highlight ? readableUpdatedAtMessage(props.highlight?.updatedAt) : undefined
const updatedAtMessage = props.highlight
? readableUpdatedAtMessage(props.highlight?.updatedAt)
: undefined
const handleNoteContentChange = useCallback(
(event: React.ChangeEvent<HTMLTextAreaElement>): void => {
@ -61,7 +67,8 @@ export function HighlightNoteModal(
} else {
showErrorToast('Error updating your note', { position: 'bottom-right' })
}
} if (!props.highlight && props.createHighlightForNote) {
}
if (!props.highlight && props.createHighlightForNote) {
const result = await props.createHighlightForNote(noteContent)
if (result) {
props.onOpenChange(true)
@ -99,7 +106,7 @@ export function HighlightNoteModal(
height: '248px',
fontSize: '14px',
border: '1px solid $textNonessential',
borderRadius: '6px'
borderRadius: '6px',
}}
autoFocus
placeholder={'Add your note here'}
@ -107,7 +114,10 @@ export function HighlightNoteModal(
onChange={handleNoteContentChange}
maxLength={4000}
/>
<ModalButtonBar onOpenChange={props.onOpenChange} acceptButtonLabel="Save" />
<ModalButtonBar
onOpenChange={props.onOpenChange}
acceptButtonLabel="Save"
/>
</VStack>
</form>
</ModalContent>

View file

@ -16,6 +16,7 @@ import { useCanShareNative } from '../../../lib/hooks/useCanShareNative'
import { webBaseURL } from '../../../lib/appConfig'
import { pspdfKitKey } from '../../../lib/appConfig'
import { HighlightsModal } from './HighlightsModal'
import { HighlightNoteModal } from './HighlightNoteModal'
export type PdfArticleContainerProps = {
viewerUsername: string
@ -31,6 +32,12 @@ export default function PdfArticleContainer(
const [shareTarget, setShareTarget] = useState<Highlight | undefined>(
undefined
)
const [noteTarget, setNoteTarget] = useState<Highlight | undefined>(undefined)
const [noteTargetPageIndex, setNoteTargetPageIndex] = useState<
number | undefined
>(undefined)
const highlightsRef = useRef<Highlight[]>([])
const canShareNative = useCanShareNative()
const getHighlightURL = useCallback(
@ -111,6 +118,30 @@ export default function PdfArticleContainer(
})
},
}
const note = {
type: 'custom' as const,
title: 'Note',
id: 'tooltip-note-annotation',
className: 'TooltipItem-Note',
onPress: async () => {
if (
annotation.customData &&
annotation.customData.omnivoreHighlight &&
(annotation.customData.omnivoreHighlight as Highlight).shortId
) {
const data = annotation.customData.omnivoreHighlight as Highlight
const savedHighlight = highlightsRef.current.find(
(other: Highlight) => {
return other.id === data.id
}
)
data.annotation = savedHighlight?.annotation ?? data.annotation
setNoteTargetPageIndex(annotation.pageIndex)
setNoteTarget(data)
}
instance.setSelectedAnnotation(null)
},
}
const share = {
type: 'custom' as const,
title: 'Share',
@ -128,15 +159,15 @@ export default function PdfArticleContainer(
instance.setSelectedAnnotation(null)
},
}
return [copy, remove]
return [copy, note, remove]
}
const annotationPresets = PSPDFKit.defaultAnnotationPresets;
const annotationPresets = PSPDFKit.defaultAnnotationPresets
annotationPresets.highlight = {
opacity: 0.45,
color: new PSPDFKit.Color({ r: 255, g: 210, b: 52 }),
blendMode: PSPDFKit.BlendMode.multiply,
};
}
instance = await PSPDFKit.load({
container: container || '.pdf-container',
@ -170,9 +201,14 @@ export default function PdfArticleContainer(
}
})
// Apply highlights to the PDF
// Store the highlights in the highlightsRef and apply them to the PDF
highlightsRef.current = props.article.highlights
for (const highlight of props.article.highlights) {
const patch = JSON.parse(highlight.patch)
if (highlight.annotation && patch.customData.omnivoreHighight) {
patch.customData.omnivoreHighight.annotation = highlight.annotation
}
const annotation = PSPDFKit.Annotations.fromSerializableObject(patch)
try {
@ -266,7 +302,7 @@ export default function PdfArticleContainer(
PSPDFKit.Annotations.toSerializableObject(annotation)
if (overlapping.size === 0) {
await createHighlightMutation({
const result = await createHighlightMutation({
id: id,
shortId: shortId,
quote: quote,
@ -275,6 +311,9 @@ export default function PdfArticleContainer(
suffix: surroundingText.suffix,
patch: JSON.stringify(serialized),
})
if (result) {
highlightsRef.current.push(result)
}
} else {
// Create a new single highlight in the PDF
const rects = highlightAnnotation.rects.concat(
@ -305,7 +344,7 @@ export default function PdfArticleContainer(
const mergedIds = overlapping.map(
(ha) => (ha.customData?.omnivoreHighlight as Highlight).id
)
await mergeHighlightMutation({
const result = await mergeHighlightMutation({
quote,
id,
shortId,
@ -315,6 +354,9 @@ export default function PdfArticleContainer(
articleId: props.article.id,
overlapHighlightIdList: mergedIds.toArray(),
})
if (result) {
highlightsRef.current.push(result)
}
}
}
)
@ -361,9 +403,30 @@ export default function PdfArticleContainer(
}}
/>
)}
{noteTarget && (
<HighlightNoteModal
highlight={noteTarget}
author={props.article.author ?? ''}
title={props.article.title}
onUpdate={(highlight: Highlight) => {
const savedHighlight = highlightsRef.current.find(
(other: Highlight) => {
return other.id == highlight.id
}
)
if (savedHighlight) {
savedHighlight.annotation = highlight.annotation
}
}}
onOpenChange={() => {
setNoteTarget(undefined)
}}
/>
)}
{props.showHighlightsModal && (
<HighlightsModal
highlights={props.article.highlights}
highlights={highlightsRef.current}
onOpenChange={() => props.setShowHighlightsModal(false)}
/>
)}