Improve highlight scrolling from notebooks

This commit is contained in:
Jackson Harper
2023-04-03 13:46:19 +08:00
parent 25530eb411
commit f20cbed563
13 changed files with 303 additions and 182 deletions

View File

@ -18,7 +18,6 @@ type HighlightViewProps = {
highlight: Highlight
author?: string
title?: string
scrollToHighlight?: (arg: string) => void
updateHighlight: (highlight: Highlight) => void
}
@ -67,13 +66,7 @@ export function HighlightView(props: HighlightViewProps): JSX.Element {
paddingLeft: '15px',
}}
>
<StyledQuote
onClick={() => {
if (props.scrollToHighlight) {
props.scrollToHighlight(props.highlight.id)
}
}}
>
<StyledQuote>
<SpanBox
css={{
'> *': {

View File

@ -18,14 +18,15 @@ import { LabelChip } from '../../elements/LabelChip'
import { Label } from '../../../lib/networking/fragments/labelFragment'
import { Recommendation } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { Avatar } from '../../elements/Avatar'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
type ArticleContainerProps = {
viewer: UserBasicData
article: ArticleAttributes
labels: Label[]
articleMutations: ArticleMutations
isAppleAppEmbed: boolean
highlightBarDisabled: boolean
highlightsBaseURL: string
margin?: number
fontSize?: number
fontFamily?: string
@ -107,15 +108,12 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
const [showReportIssuesModal, setShowReportIssuesModal] = useState(false)
const [fontSize, setFontSize] = useState(props.fontSize ?? 20)
// iOS app embed can overide the original margin and line height
const [maxWidthPercentageOverride, setMaxWidthPercentageOverride] = useState<
number | null
>(null)
const [lineHeightOverride, setLineHeightOverride] = useState<number | null>(
null
)
const [fontFamilyOverride, setFontFamilyOverride] = useState<string | null>(
null
)
const [maxWidthPercentageOverride, setMaxWidthPercentageOverride] =
useState<number | null>(null)
const [lineHeightOverride, setLineHeightOverride] =
useState<number | null>(null)
const [fontFamilyOverride, setFontFamilyOverride] =
useState<string | null>(null)
const [highContrastText, setHighContrastText] = useState(
props.highContrastText ?? false
)
@ -388,13 +386,14 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
<Box css={{ height: '100px' }} />
</Box>
<HighlightsLayer
viewer={props.viewer}
item={props.article}
scrollToHighlight={highlightHref}
highlights={props.article.highlights}
articleTitle={props.article.title}
articleAuthor={props.article.author ?? ''}
articleId={props.article.id}
isAppleAppEmbed={props.isAppleAppEmbed}
highlightsBaseURL={props.highlightsBaseURL}
highlightBarDisabled={props.highlightBarDisabled}
showHighlightsModal={props.showHighlightsModal}
setShowHighlightsModal={props.setShowHighlightsModal}

View File

@ -1,12 +1,22 @@
import { useState } from 'react'
import { Highlight } from '../../../lib/networking/fragments/highlightFragment'
import {
LibraryItem,
ReadableItem,
} from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
import { HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
import { HighlightView } from '../../patterns/HighlightView'
import { HighlightsMenu } from '../homeFeed/HighlightItem'
type HighlightViewItemProps = {
viewer: UserBasicData
item: ReadableItem
highlight: Highlight
scrollToHighlight?: (arg: string) => void
viewInReader: (highlightId: string) => void
deleteHighlightAction: () => void
updateHighlight: (highlight: Highlight) => void
@ -26,7 +36,6 @@ export function HighlightViewItem(props: HighlightViewItemProps): JSX.Element {
<VStack css={{ width: '100%' }}>
<HighlightView
highlight={props.highlight}
scrollToHighlight={props.scrollToHighlight}
updateHighlight={props.updateHighlight}
/>
<SpanBox css={{ mb: '15px' }} />
@ -42,7 +51,10 @@ export function HighlightViewItem(props: HighlightViewItemProps): JSX.Element {
}}
>
<HighlightsMenu
item={props.item}
viewer={props.viewer}
highlight={props.highlight}
viewInReader={props.viewInReader}
setLabelsTarget={props.setSetLabelsTarget}
setShowConfirmDeleteHighlightId={
props.setShowConfirmDeleteHighlightId

View File

@ -26,17 +26,24 @@ import { isTouchScreenDevice } from '../../../lib/deviceType'
import { SetLabelsModal } from './SetLabelsModal'
import { setLabelsForHighlight } from '../../../lib/networking/mutations/setLabelsForHighlight'
import { Label } from '../../../lib/networking/fragments/labelFragment'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
import { ReadableItem } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { useRouter } from 'next/router'
type HighlightsLayerProps = {
viewer: UserBasicData
item: ReadableItem
highlights: Highlight[]
articleId: string
articleTitle: string
articleAuthor: string
isAppleAppEmbed: boolean
highlightBarDisabled: boolean
showHighlightsModal: boolean
highlightsBaseURL: string
scrollToHighlight: MutableRefObject<string | null>
setShowHighlightsModal: React.Dispatch<React.SetStateAction<boolean>>
articleMutations: ArticleMutations
}
@ -59,6 +66,7 @@ interface SpeakingSectionEvent extends Event {
}
export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
const router = useRouter()
const [highlights, setHighlights] = useState(props.highlights)
const [highlightModalAction, setHighlightModalAction] =
useState<HighlightActionProps>({ highlightModalAction: 'none' })
@ -68,15 +76,13 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
>([])
const focusedHighlightMousePos = useRef({ pageX: 0, pageY: 0 })
const [focusedHighlight, setFocusedHighlight] = useState<
Highlight | undefined
>(undefined)
const [focusedHighlight, setFocusedHighlight] =
useState<Highlight | undefined>(undefined)
const [selectionData, setSelectionData] = useSelection(highlightLocations)
const [labelsTarget, setLabelsTarget] = useState<Highlight | undefined>(
undefined
)
const [labelsTarget, setLabelsTarget] =
useState<Highlight | undefined>(undefined)
const canShareNative = useCanShareNative()
@ -141,7 +147,10 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
`[omnivore-highlight-id="${props.scrollToHighlight.current}"]`
)
if (anchorElement) {
anchorElement.scrollIntoView({ behavior: 'auto' })
anchorElement.scrollIntoView({
block: 'center',
behavior: 'auto',
})
}
}
}, [highlights, setHighlightLocations, props.scrollToHighlight])
@ -181,23 +190,20 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
[highlights, highlightLocations]
)
const handleNativeShare = useCallback(
(highlightID: string) => {
navigator
?.share({
title: props.articleTitle,
url: `${props.highlightsBaseURL}/${highlightID}`,
})
.then(() => {
setFocusedHighlight(undefined)
})
.catch((error) => {
console.log(error)
setFocusedHighlight(undefined)
})
},
[props.articleTitle, props.highlightsBaseURL]
)
// const handleNativeShare = useCallback((highlightID: string) => {
// // navigator
// // ?.share({
// // title: props.articleTitle,
// // url: `${props.highlightsBaseURL}/${highlightID}`,
// // })
// // .then(() => {
// // setFocusedHighlight(undefined)
// // })
// // .catch((error) => {
// // console.log(error)
// // setFocusedHighlight(undefined)
// // })
// }, [])
const openNoteModal = useCallback(
(inputs: HighlightActionProps) => {
@ -282,7 +288,6 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
}
},
[
handleNativeShare,
highlights,
openNoteModal,
props.articleId,
@ -408,37 +413,37 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
})
}
break
case 'share':
if (props.isAppleAppEmbed) {
window?.webkit?.messageHandlers.highlightAction?.postMessage({
actionID: 'share',
highlightID: focusedHighlight?.id,
})
}
// case 'share':
// if (props.isAppleAppEmbed) {
// window?.webkit?.messageHandlers.highlightAction?.postMessage({
// actionID: 'share',
// highlightID: focusedHighlight?.id,
// })
// }
window?.AndroidWebKitMessenger?.handleIdentifiableMessage(
'shareHighlight',
JSON.stringify({
highlightID: focusedHighlight?.id,
})
)
// window?.AndroidWebKitMessenger?.handleIdentifiableMessage(
// 'shareHighlight',
// JSON.stringify({
// highlightID: focusedHighlight?.id,
// })
// )
if (focusedHighlight) {
if (canShareNative) {
handleNativeShare(focusedHighlight.shortId)
} else {
setHighlightModalAction({
highlight: focusedHighlight,
highlightModalAction: 'share',
})
}
} else {
await createHighlightCallback('share')
}
break
case 'unshare':
console.log('unshare')
break // TODO: implement -- need to show confirmation dialog
// if (focusedHighlight) {
// if (canShareNative) {
// handleNativeShare(focusedHighlight.shortId)
// } else {
// setHighlightModalAction({
// highlight: focusedHighlight,
// highlightModalAction: 'share',
// })
// }
// } else {
// await createHighlightCallback('share')
// }
// break
// case 'unshare':
// console.log('unshare')
// break // TODO: implement -- need to show confirmation dialog
case 'setHighlightLabels':
if (props.isAppleAppEmbed) {
window?.webkit?.messageHandlers.highlightAction?.postMessage({
@ -454,7 +459,6 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
[
createHighlightCallback,
focusedHighlight,
handleNativeShare,
openNoteModal,
props.highlightBarDisabled,
props.isAppleAppEmbed,
@ -667,9 +671,28 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
if (props.showHighlightsModal) {
return (
<NotebookModal
viewer={props.viewer}
item={props.item}
highlights={highlights}
pageId={props.articleId}
onClose={handleCloseNotebook}
viewHighlightInReader={(highlightId) => {
// The timeout here is a bit of a hack to work around rerendering
setTimeout(() => {
const target = document.querySelector(
`[omnivore-highlight-id="${highlightId}"]`
)
target?.scrollIntoView({
block: 'center',
behavior: 'auto',
})
}, 1)
history.replaceState(
undefined,
window.location.href,
`#${highlightId}`
)
props.setShowHighlightsModal(false)
}}
/>
)
}

View File

@ -20,14 +20,22 @@ import { HighlightNoteBox } from '../../patterns/HighlightNotes'
import { HighlightViewItem } from './HighlightViewItem'
import { ConfirmationModal } from '../../patterns/ConfirmationModal'
import { TrashIcon } from '../../elements/images/TrashIcon'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
import {
LibraryItem,
ReadableItem,
} from '../../../lib/networking/queries/useGetLibraryItemsQuery'
type NotebookProps = {
pageId: string
viewer: UserBasicData
item: ReadableItem
highlights: Highlight[]
scrollToHighlight?: (arg: string) => void
sizeMode: 'normal' | 'maximized'
viewInReader: (highlightId: string) => void
onAnnotationsChanged?: (
highlights: Highlight[],
deletedAnnotations: Highlight[]
@ -242,7 +250,7 @@ export function Notebook(props: NotebookProps): JSX.Element {
id: noteId,
shortId: nanoid(8),
type: 'NOTE',
articleId: props.pageId,
articleId: props.item.id,
annotation: text,
})
console.log('success creating annotation note: ', success)
@ -277,7 +285,7 @@ export function Notebook(props: NotebookProps): JSX.Element {
return
}
},
[annotations, props.pageId]
[annotations, props.item]
)
return (
<VStack
@ -304,8 +312,10 @@ export function Notebook(props: NotebookProps): JSX.Element {
{sortedHighlights.map((highlight) => (
<HighlightViewItem
key={highlight.id}
item={props.item}
viewer={props.viewer}
highlight={highlight}
scrollToHighlight={props.scrollToHighlight}
viewInReader={props.viewInReader}
setSetLabelsTarget={setLabelsTarget}
setShowConfirmDeleteHighlightId={setShowConfirmDeleteHighlightId}
deleteHighlightAction={() => {

View File

@ -17,11 +17,16 @@ import { MenuTrigger } from '../../elements/MenuTrigger'
import { highlightsAsMarkdown } from '../homeFeed/HighlightItem'
import 'react-markdown-editor-lite/lib/index.css'
import { Notebook } from './Notebook'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
import { ReadableItem } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
type NotebookModalProps = {
pageId: string
viewer: UserBasicData
item: ReadableItem
highlights: Highlight[]
scrollToHighlight?: (arg: string) => void
viewHighlightInReader: (arg: string) => void
onClose: (highlights: Highlight[], deletedAnnotations: Highlight[]) => void
}
@ -31,16 +36,6 @@ export const getHighlightLocation = (patch: string): number | undefined => {
return patches[0].start1 || undefined
}
type AnnotationInfo = {
loaded: boolean
note: Highlight | undefined
noteId: string
allAnnotations: Highlight[]
deletedAnnotations: Highlight[]
}
export function NotebookModal(props: NotebookModalProps): JSX.Element {
const [sizeMode, setSizeMode] = useState<'normal' | 'maximized'>('normal')
const [showConfirmDeleteNote, setShowConfirmDeleteNote] = useState(false)
@ -73,6 +68,14 @@ export function NotebookModal(props: NotebookModalProps): JSX.Element {
})()
}, [allAnnotations])
const viewInReader = useCallback(
(highlightId) => {
props.viewHighlightInReader(highlightId)
handleClose()
},
[props, handleClose]
)
return (
<ModalRoot defaultOpen onOpenChange={handleClose}>
<ModalOverlay />
@ -141,6 +144,7 @@ export function NotebookModal(props: NotebookModalProps): JSX.Element {
<Notebook
{...props}
sizeMode={sizeMode}
viewInReader={viewInReader}
onAnnotationsChanged={handleAnnotationsChange}
/>
</ModalContent>

View File

@ -2,7 +2,7 @@ import { ArticleAttributes } from '../../../lib/networking/queries/useGetArticle
import { Box } from '../../elements/LayoutPrimitives'
import { v4 as uuidv4 } from 'uuid'
import { nanoid } from 'nanoid'
import { useState, useEffect, useCallback, useRef } from 'react'
import { useState, useEffect, useRef } from 'react'
import { isDarkTheme } from '../../../lib/themeUpdater'
import PSPDFKit from 'pspdfkit'
import { Instance, HighlightAnnotation, List, Annotation, Rect } from 'pspdfkit'
@ -12,15 +12,15 @@ import { deleteHighlightMutation } from '../../../lib/networking/mutations/delet
import { articleReadingProgressMutation } from '../../../lib/networking/mutations/articleReadingProgressMutation'
import { mergeHighlightMutation } from '../../../lib/networking/mutations/mergeHighlightMutation'
import { useCanShareNative } from '../../../lib/hooks/useCanShareNative'
import { webBaseURL } from '../../../lib/appConfig'
import { pspdfKitKey } from '../../../lib/appConfig'
import { NotebookModal } from './NotebookModal'
import { HighlightNoteModal } from './HighlightNoteModal'
import { showErrorToast } from '../../../lib/toastHelpers'
import { HEADER_HEIGHT, MOBILE_HEADER_HEIGHT } from '../homeFeed/HeaderSpacer'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
export type PdfArticleContainerProps = {
viewerUsername: string
viewer: UserBasicData
article: ArticleAttributes
showHighlightsModal: boolean
setShowHighlightsModal: React.Dispatch<React.SetStateAction<boolean>>
@ -30,43 +30,41 @@ export default function PdfArticleContainer(
props: PdfArticleContainerProps
): JSX.Element {
const containerRef = useRef<HTMLDivElement | null>(null)
const [shareTarget, setShareTarget] = useState<Highlight | undefined>(
undefined
)
const [shareTarget, setShareTarget] =
useState<Highlight | undefined>(undefined)
const [notebookKey, setNotebookKey] = useState<string>(uuidv4())
const [noteTarget, setNoteTarget] = useState<Highlight | undefined>(undefined)
const [noteTargetPageIndex, setNoteTargetPageIndex] = useState<
number | undefined
>(undefined)
const [noteTargetPageIndex, setNoteTargetPageIndex] =
useState<number | undefined>(undefined)
const highlightsRef = useRef<Highlight[]>([])
const canShareNative = useCanShareNative()
const getHighlightURL = useCallback(
(highlightID: string): string =>
`${webBaseURL}/${props.viewerUsername}/${props.article.slug}/highlights/${highlightID}`,
[props.article.slug, props.viewerUsername]
)
// const getHighlightURL = useCallback(
// (highlightID: string): string =>
// `${webBaseURL}/${props.viewerUsername}/${props.article.slug}/highlights/${highlightID}`,
// [props.article.slug, props.viewerUsername]
// )
const nativeShare = useCallback(
async (highlightID: string, title: string) => {
await navigator?.share({
title: title,
url: getHighlightURL(highlightID),
})
},
[getHighlightURL]
)
// const nativeShare = useCallback(
// async (highlightID: string, title: string) => {
// await navigator?.share({
// title: title,
// url: getHighlightURL(highlightID),
// })
// },
// [getHighlightURL]
// )
const handleOpenShare = useCallback(
(highlight: Highlight) => {
if (canShareNative) {
nativeShare(highlight.shortId, props.article.title)
} else {
setShareTarget(highlight)
}
},
[nativeShare, canShareNative, props.article.title]
)
// const handleOpenShare = useCallback(
// (highlight: Highlight) => {
// if (canShareNative) {
// nativeShare(highlight.shortId, props.article.title)
// } else {
// setShareTarget(highlight)
// }
// },
// [nativeShare, canShareNative, props.article.title]
// )
const annotationOmnivoreId = (annotation: Annotation): string | undefined => {
if (
@ -178,23 +176,23 @@ export default function PdfArticleContainer(
instance.setSelectedAnnotation(null)
},
}
const share = {
type: 'custom' as const,
title: 'Share',
id: 'tooltip-share-annotation',
className: 'TooltipItem-Share',
onPress: () => {
if (
annotation.customData &&
annotation.customData.omnivoreHighlight &&
(annotation.customData.omnivoreHighlight as Highlight).shortId
) {
const data = annotation.customData.omnivoreHighlight as Highlight
handleOpenShare(data)
}
instance.setSelectedAnnotation(null)
},
}
// const share = {
// type: 'custom' as const,
// title: 'Share',
// id: 'tooltip-share-annotation',
// className: 'TooltipItem-Share',
// onPress: () => {
// if (
// annotation.customData &&
// annotation.customData.omnivoreHighlight &&
// (annotation.customData.omnivoreHighlight as Highlight).shortId
// ) {
// const data = annotation.customData.omnivoreHighlight as Highlight
// handleOpenShare(data)
// }
// instance.setSelectedAnnotation(null)
// },
// }
return [copy, note, remove]
}
@ -424,7 +422,6 @@ export default function PdfArticleContainer(
document.addEventListener('deleteHighlightbyId', async (event) => {
const annotationId = (event as CustomEvent).detail as string
console.log(' DELETING ANNOTATION BY ID: ', annotationId)
for (let pageIdx = 0; pageIdx < instance.totalPageCount; pageIdx++) {
const annotations = await instance.getAnnotations(pageIdx)
for (let annIdx = 0; annIdx < annotations.size; annIdx++) {
@ -433,7 +430,6 @@ export default function PdfArticleContainer(
continue
}
const storedId = annotationOmnivoreId(annotation)
console.log(' --- storedId:', storedId)
if (storedId == annotationId) {
await instance.delete(annotation)
await deleteHighlightMutation(annotationId)
@ -495,7 +491,8 @@ export default function PdfArticleContainer(
{props.showHighlightsModal && (
<NotebookModal
key={notebookKey}
pageId={props.article.id}
viewer={props.viewer}
item={props.article}
highlights={highlightsRef.current}
onClose={(updatedHighlights, deletedAnnotations) => {
console.log(
@ -511,6 +508,10 @@ export default function PdfArticleContainer(
})
props.setShowHighlightsModal(false)
}}
viewHighlightInReader={(highlightId) => {
// TODO: scroll to highlight in PDF
props.setShowHighlightsModal(false)
}}
/>
)}
</Box>

View File

@ -1,19 +1,50 @@
import { Item } from '@radix-ui/react-dropdown-menu'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { DotsThreeVertical } from 'phosphor-react'
import { useCallback } from 'react'
import { Highlight } from '../../../lib/networking/fragments/highlightFragment'
import { ReadableItem } 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 { Box } from '../../elements/LayoutPrimitives'
import {
Dropdown,
DropdownOption,
DropdownSeparator,
} from '../../elements/DropdownElements'
import { Box, SpanBox } from '../../elements/LayoutPrimitives'
import { theme } from '../../tokens/stitches.config'
import { styled, theme } from '../../tokens/stitches.config'
type HighlightsMenuProps = {
viewer: UserBasicData
item: ReadableItem
highlight: Highlight
viewInReader: (highlightId: string) => void
setLabelsTarget: (target: Highlight) => void
setShowConfirmDeleteHighlightId: (set: string) => void
}
const StyledLinkItem = styled('a', {
display: 'flex',
fontSize: '14px',
fontWeight: '400',
py: '10px',
px: '15px',
borderRadius: 3,
cursor: 'pointer',
color: '$utilityTextDefault',
textDecoration: 'none',
'&:hover': {
outline: 'none',
backgroundColor: '$grayBgHover',
},
})
export function HighlightsMenu(props: HighlightsMenuProps): JSX.Element {
const copyHighlight = useCallback(() => {
const quote = props.highlight.quote
@ -69,6 +100,28 @@ export function HighlightsMenu(props: HighlightsMenuProps): JSX.Element {
}}
title="Delete"
/>
<DropdownSeparator />
<Link
href={`/${props.viewer.profile.username}/${props.item.slug}#${props.highlight.id}`}
>
<StyledLinkItem
onClick={(event) => {
console.log('event.ctrlKey: ', event.ctrlKey, event.metaKey)
if (event.ctrlKey || event.metaKey) {
window.open(
`/${props.viewer.profile.username}/${props.item.slug}#${props.highlight.id}`,
'_blank'
)
return
}
props.viewInReader(props.highlight.id)
event.preventDefault()
event.stopPropagation()
}}
>
View In Reader
</StyledLinkItem>
</Link>
</Dropdown>
)
}

View File

@ -1,5 +1,6 @@
import { useRouter } from 'next/router'
import { HighlighterCircle } from 'phosphor-react'
import { useCallback, useEffect, useMemo, useReducer, useState } from 'react'
import { useCallback, useEffect, useReducer, useState } from 'react'
import { Toaster } from 'react-hot-toast'
import { Highlight } from '../../../lib/networking/fragments/highlightFragment'
import {
@ -361,6 +362,8 @@ type HighlightListProps = {
}
function HighlightList(props: HighlightListProps): JSX.Element {
const router = useRouter()
const exportHighlights = useCallback(() => {
;(async () => {
if (!props.item.node.highlights) {
@ -373,6 +376,36 @@ function HighlightList(props: HighlightListProps): JSX.Element {
})()
}, [props.item.node.highlights])
const viewInReader = useCallback(
(highlightId) => {
if (!router || !router.isReady || !props.viewer) {
showErrorToast('Error navigating to highlight')
return
}
console.log(
'pushing user: ',
props.viewer,
'slug: ',
props.item.node.slug
)
router.push(
{
pathname: '/[username]/[slug]',
query: {
username: props.viewer.profile.username,
slug: props.item.node.slug,
},
hash: highlightId,
},
`${props.viewer.profile.username}/${props.item.node.slug}#${highlightId}`,
{
scroll: false,
}
)
},
[router, props]
)
return (
<VStack
css={{
@ -418,11 +451,15 @@ function HighlightList(props: HighlightListProps): JSX.Element {
</Dropdown>
</HStack>
<HStack css={{ width: '100%', height: '100%' }}>
<Notebook
sizeMode="normal"
pageId={props.item.node.id}
highlights={props.item.node.highlights ?? []}
/>
{props.viewer && (
<Notebook
sizeMode="normal"
viewer={props.viewer}
item={props.item.node}
highlights={props.item.node.highlights ?? []}
viewInReader={viewInReader}
/>
)}
</HStack>
</VStack>
)

View File

@ -4,7 +4,6 @@ type AppEnvironment = 'prod' | 'dev' | 'demo' | 'local'
type BaseURLs = {
webBaseURL: string
serverBaseURL: string
highlightsBaseURL: string
}
type BaseURLRecords = Record<AppEnvironment, BaseURLs>
@ -14,22 +13,18 @@ const baseURLRecords: BaseURLRecords = {
prod: {
webBaseURL: process.env.NEXT_PUBLIC_BASE_URL ?? '',
serverBaseURL: process.env.NEXT_PUBLIC_SERVER_BASE_URL ?? '',
highlightsBaseURL: process.env.NEXT_PUBLIC_HIGHLIGHTS_BASE_URL ?? '',
},
dev: {
webBaseURL: process.env.NEXT_PUBLIC_DEV_BASE_URL ?? '',
serverBaseURL: process.env.NEXT_PUBLIC_DEV_SERVER_BASE_URL ?? '',
highlightsBaseURL: process.env.NEXT_PUBLIC_DEV_HIGHLIGHTS_BASE_URL ?? '',
},
demo: {
webBaseURL: process.env.NEXT_PUBLIC_DEMO_BASE_URL ?? '',
serverBaseURL: process.env.NEXT_PUBLIC_DEMO_SERVER_BASE_URL ?? '',
highlightsBaseURL: process.env.NEXT_PUBLIC_DEMO_HIGHLIGHTS_BASE_URL ?? '',
},
local: {
webBaseURL: process.env.NEXT_PUBLIC_LOCAL_BASE_URL ?? '',
serverBaseURL: process.env.NEXT_PUBLIC_LOCAL_SERVER_BASE_URL ?? '',
highlightsBaseURL: process.env.NEXT_PUBLIC_LOCAL_HIGHLIGHTS_BASE_URL ?? '',
},
}
@ -43,16 +38,6 @@ function serverBaseURL(env: AppEnvironment): string {
return value
}
function highlightsURL(env: AppEnvironment): string {
const value = baseURLRecords[appEnv].highlightsBaseURL
if (value.length == 0) {
throw new Error(
`Couldn't find environment variable for highlights base url in ${env} environment`
)
}
return value
}
function webURL(env: AppEnvironment): string {
const value = baseURLRecords[appEnv].webBaseURL
if (value.length == 0) {
@ -96,6 +81,4 @@ export const gqlEndpoint = `${serverBaseURL(appEnv)}/api/graphql`
export const fetchEndpoint = `${serverBaseURL(appEnv)}/api`
export const highlightsBaseURL = highlightsURL(appEnv)
export const webBaseURL = webURL(appEnv)

View File

@ -11,6 +11,12 @@ import { Label } from './../fragments/labelFragment'
import { showErrorToast, showSuccessToast } from '../../toastHelpers'
import { Highlight, highlightFragment } from '../fragments/highlightFragment'
export interface ReadableItem {
id: string
title: string
slug: string
}
export type LibraryItemsQueryInput = {
limit: number
sortDescending: boolean

View File

@ -346,7 +346,7 @@ export default function Home(): JSX.Element {
article={article}
showHighlightsModal={showHighlightsModal}
setShowHighlightsModal={setShowHighlightsModal}
viewerUsername={viewerData.me?.profile?.username}
viewer={viewerData.me}
/>
) : (
<VStack
@ -362,10 +362,10 @@ export default function Home(): JSX.Element {
>
{article && viewerData?.me ? (
<ArticleContainer
viewer={viewerData.me}
article={article}
isAppleAppEmbed={false}
highlightBarDisabled={false}
highlightsBaseURL={`${webBaseURL}/${viewerData.me?.profile?.username}/${slug}/highlights`}
fontSize={readerSettings.fontSize}
margin={readerSettings.marginWidth}
lineHeight={readerSettings.lineHeight}

View File

@ -13,6 +13,7 @@ import { mergeHighlightMutation } from '../../../../lib/networking/mutations/mer
import { updateHighlightMutation } from '../../../../lib/networking/mutations/updateHighlightMutation'
import { articleReadingProgressMutation } from '../../../../lib/networking/mutations/articleReadingProgressMutation'
import Script from 'next/script'
import { useGetViewerQuery } from '../../../../lib/networking/queries/useGetViewerQuery'
type AppArticleEmbedContentProps = {
slug: string
@ -28,9 +29,8 @@ export default function AppArticleEmbed(): JSX.Element {
const router = useRouter()
const [contentProps, setContentProps] = useState<
AppArticleEmbedContentProps | undefined
>(undefined)
const [contentProps, setContentProps] =
useState<AppArticleEmbedContentProps | undefined>(undefined)
useEffect(() => {
if (!router.isReady) return
@ -62,7 +62,7 @@ export default function AppArticleEmbed(): JSX.Element {
function AppArticleEmbedContent(
props: AppArticleEmbedContentProps
): JSX.Element {
const scrollRef = useRef<HTMLDivElement | null>(null)
const { viewerData } = useGetViewerQuery()
const [showHighlightsModal, setShowHighlightsModal] = useState(false)
const { articleData } = useGetArticleQuery({
@ -71,7 +71,7 @@ function AppArticleEmbedContent(
includeFriendsHighlights: false,
})
if (articleData) {
if (articleData && viewerData?.me) {
return (
<Box>
<Script async src="/static/scripts/mathJaxConfiguration.js" />
@ -86,10 +86,10 @@ function AppArticleEmbedContent(
className="disable-webkit-callout"
>
<ArticleContainer
viewer={viewerData.me}
article={articleData.article.article}
isAppleAppEmbed={true}
highlightBarDisabled={props.highlightBarDisabled}
highlightsBaseURL={`${webBaseURL}/${props.username}/${props.slug}/highlights`}
fontSize={props.fontSize}
margin={props.margin}
fontFamily={props.fontFamily}