diff --git a/packages/web/lib/networking/queries/useGetHighlights.tsx b/packages/web/lib/networking/queries/useGetHighlights.tsx
index 505bf4e28..09edb9a33 100644
--- a/packages/web/lib/networking/queries/useGetHighlights.tsx
+++ b/packages/web/lib/networking/queries/useGetHighlights.tsx
@@ -48,6 +48,7 @@ export const useGetHighlights = (
id
title
author
+ slug
}
}
cursor
diff --git a/packages/web/pages/highlights.tsx b/packages/web/pages/highlights.tsx
index cf62a1f0d..5c760e3c9 100644
--- a/packages/web/pages/highlights.tsx
+++ b/packages/web/pages/highlights.tsx
@@ -1,31 +1,51 @@
-import { useRouter } from 'next/router'
+import {
+ autoUpdate,
+ offset,
+ size,
+ useFloating,
+ useHover,
+ useInteractions,
+} from '@floating-ui/react'
+import { NextRouter, useRouter } from 'next/router'
import { useCallback, useMemo, useState } from 'react'
+import { Toaster } from 'react-hot-toast'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
+import { TrashIcon } from '../components/elements/icons/TrashIcon'
import { LabelChip } from '../components/elements/LabelChip'
import { Box, HStack, VStack } from '../components/elements/LayoutPrimitives'
+import { ConfirmationModal } from '../components/patterns/ConfirmationModal'
+import { HighlightHoverActions } from '../components/patterns/HighlightHoverActions'
import { HighlightViewNote } from '../components/patterns/HighlightNotes'
+import { SetHighlightLabelsModalPresenter } from '../components/templates/article/SetLabelsModalPresenter'
import { EmptyHighlights } from '../components/templates/homeFeed/EmptyHighlights'
import { LibraryFilterMenu } from '../components/templates/navMenu/LibraryMenu'
+import { theme } from '../components/tokens/stitches.config'
import { useApplyLocalTheme } from '../lib/hooks/useApplyLocalTheme'
import { useFetchMore } from '../lib/hooks/useFetchMoreScroll'
import { Highlight } from '../lib/networking/fragments/highlightFragment'
+import { deleteHighlightMutation } from '../lib/networking/mutations/deleteHighlightMutation'
import { useGetHighlights } from '../lib/networking/queries/useGetHighlights'
+import {
+ useGetViewerQuery,
+ UserBasicData,
+} from '../lib/networking/queries/useGetViewerQuery'
import { highlightColor } from '../lib/themeUpdater'
+import { showErrorToast, showSuccessToast } from '../lib/toastHelpers'
const PAGE_SIZE = 10
export default function HighlightsPage(): JSX.Element {
const router = useRouter()
+ const viewer = useGetViewerQuery()
const [showFilterMenu, setShowFilterMenu] = useState(false)
const [_, setShowAddLinkModal] = useState(false)
useApplyLocalTheme()
- const { isLoading, isValidating, mutate, setSize, size, data, error } =
- useGetHighlights({
- first: PAGE_SIZE,
- })
+ const { isLoading, setSize, size, data, mutate } = useGetHighlights({
+ first: PAGE_SIZE,
+ })
const hasMore = useMemo(() => {
if (!data) {
@@ -65,6 +85,8 @@ export default function HighlightsPage(): JSX.Element {
return (
+
+
{highlights.map((highlight) => {
- return
+ return (
+ viewer.viewerData?.me && (
+
+ )
+ )
})}
@@ -91,11 +123,18 @@ export default function HighlightsPage(): JSX.Element {
type HighlightCardProps = {
highlight: Highlight
+ viewer: UserBasicData
+ router: NextRouter
+ mutate: () => void
}
-type HighlightAnnotationProps = HighlightCardProps
+type HighlightAnnotationProps = {
+ highlight: Highlight
+}
-function HighlightAnnotation({ highlight }: HighlightAnnotationProps): JSX.Element {
+function HighlightAnnotation({
+ highlight,
+}: HighlightAnnotationProps): JSX.Element {
const [noteMode, setNoteMode] = useState<'edit' | 'preview'>('preview')
const [annotation, setAnnotation] = useState(highlight.annotation)
@@ -115,8 +154,63 @@ function HighlightAnnotation({ highlight }: HighlightAnnotationProps): JSX.Eleme
}
function HighlightCard(props: HighlightCardProps): JSX.Element {
+ const [isOpen, setIsOpen] = useState(false)
+ const [showConfirmDeleteHighlightId, setShowConfirmDeleteHighlightId] =
+ useState(undefined)
+ const [labelsTarget, setLabelsTarget] = useState(
+ undefined
+ )
+
+ const viewInReader = useCallback(
+ (highlightId: string) => {
+ const router = props.router
+ const viewer = props.viewer
+ const item = props.highlight.libraryItem
+
+ if (!router || !router.isReady || !viewer || !item) {
+ showErrorToast('Error navigating to highlight')
+ return
+ }
+
+ router.push(
+ {
+ pathname: '/[username]/[slug]',
+ query: {
+ username: viewer.profile.username,
+ slug: item.slug,
+ },
+ hash: highlightId,
+ },
+ `${viewer.profile.username}/${item.slug}#${highlightId}`,
+ {
+ scroll: false,
+ }
+ )
+ },
+ [props.highlight.libraryItem, props.viewer, props.router]
+ )
+
+ const { refs, floatingStyles, context } = useFloating({
+ open: isOpen,
+ onOpenChange: setIsOpen,
+ middleware: [
+ offset({
+ mainAxis: -25,
+ }),
+ size(),
+ ],
+ placement: 'top-end',
+ whileElementsMounted: autoUpdate,
+ })
+
+ const hover = useHover(context)
+
+ const { getReferenceProps, getFloatingProps } = useInteractions([hover])
+
return (
-
-
-
- {props.highlight.quote && (
-
- {props.highlight.quote}
-
- )}
-
- {props.highlight.labels && (
-
- {props.highlight.labels.map((label) => {
- return (
-
- )
- })}
-
- )}
-
+
+ {props.highlight.quote && (
+
+ {props.highlight.quote}
+
+ )}
+
+ {props.highlight.labels && (
+
- {props.highlight.libraryItem?.title}
-
- {
+ return (
+
+ )
+ })}
+
+ )}
+
+ {props.highlight.libraryItem?.title}
+
+
+ {props.highlight.libraryItem?.author}
+
+ {showConfirmDeleteHighlightId && (
+ {
+ ;(async () => {
+ const highlightId = showConfirmDeleteHighlightId
+ const success = await deleteHighlightMutation(
+ props.highlight.libraryItem?.id || '',
+ showConfirmDeleteHighlightId
+ )
+ props.mutate()
+ if (success) {
+ showSuccessToast('Highlight deleted.', {
+ position: 'bottom-right',
+ })
+ const event = new CustomEvent('deleteHighlightbyId', {
+ detail: highlightId,
+ })
+ document.dispatchEvent(event)
+ } else {
+ showErrorToast('Error deleting highlight', {
+ position: 'bottom-right',
+ })
+ }
+ })()
+ setShowConfirmDeleteHighlightId(undefined)
}}
- >
- {props.highlight.libraryItem?.author}
-
-
-
+ onOpenChange={() => setShowConfirmDeleteHighlightId(undefined)}
+ icon={
+
+ }
+ />
+ )}
+ {labelsTarget && (
+ {
+ // Don't actually need to do something here
+ console.log('update highlight: ', highlight)
+ }}
+ onOpenChange={() => {
+ props.mutate()
+ setLabelsTarget(undefined)
+ }}
+ />
+ )}
+
)
}