mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Some checks failed
Build Docker Images / Build docker images (push) Has been cancelled
Build Self-Hosting Docker Images / Build self-host docker images (push) Has been cancelled
Run tests / Run Codebase tests (push) Has been cancelled
Run tests / Build docker images (push) Has been cancelled
* fix: Library Header layout shift * Bump Github Actions versions. * Self-Hosting Changes * Fix Minio Environment Variable * Just make pdfs successful, due to lack of PDFHandler * Fix issue where flag was set wrong * Added an NGINX Example file * Add some documentation for self-hosting via Docker Compose * Make some adjustments to Puppeteer due to failing sites. * adjust timings * Add start of Mail Service * Fix Docker Files * More email service stuff * Add Guide to use Zapier for Email-Importing. * Ensure that if no env is provided it uses the old email settings * Add some instructions for self-hosted email * Add SNS Endpoints for Mail Watcher * Add steps and functionality for using SES and SNS for email * Uncomment a few jobs. * Added option for Firefox for parser. Was having issues with Chromium on Docker. * Add missing space. Co-authored-by: Russ Taylor <729694+russtaylor@users.noreply.github.com> * Fix some wording on the Guide * update browser extension to handle self-hosted instances * add slight documentation to options page * Fix MV * Do raw handlers for Medium * Fix images in Medium * Update self-hosting/GUIDE.md Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com> * Update Guide with other variables * Add The Verge to JS-less handlers * Update regex and image-proxy * Update self-hosting/nginx/nginx.conf Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com> * Update regex and image-proxy * Update self-hosting/docker-compose/docker-compose.yml Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com> * Fix Minio for Export * Merge to main * Update GUIDE with newer NGINX * Update nginx config to include api/save route * Enable Native PDF View for PDFS * Enable Native PDF View for PDFS * feat:lover packages test * feat:working build * feat:alpine build * docs:api dockerfile docs * Write a PDF.js wrapper to replace pspdfkit * Revert changes for replication, set settings to have default mode * build folder got removed due to gitignore on pdf * Add Box shadow to pdf pages * Add Toggle for Progress in PDFS, enabled native viewer toggle * Update node version to LTS * Update node version to LTS * Fix Linting issues * Fix Linting issues * Make env variable nullable * Add touchend listener for mobile * Make changes to PDF for mobile * fix(android): change serverUrl to selfhosted first * feat:2 stage alpine content fetch * feat:separated start script * fix:changed to node 22 * Add back youtube functionality and add guide * trigger build * Fix cache issue on YouTube * Allow empty AWS_S3_ENDPOINT * Allow empty AWS_S3_ENDPOINT * Add GCHR for all images * Add GCHR For self hosting. * Add GCHR For self hosting. * Test prebuilt. * Test prebuilt * Test prebuilt... * Fix web image * Remove Web Image (For now) * Move docker-compose to images * Move docker-compose files to correct locations * Remove the need for ARGS * Update packages, and Typescript versions * Fix * Fix issues with build on Web * Correct push * Fix Linting issues * Fix Trace import * Add missing types * Fix Tasks * Add information into guide about self-build * Fix issues with PDF Viewer --------- Co-authored-by: keumky2 <keumky2@woowahan.com> Co-authored-by: William Theaker <wtheaker@nvidia.com> Co-authored-by: Russ Taylor <729694+russtaylor@users.noreply.github.com> Co-authored-by: David Adams <david@dadams2.com> Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com> Co-authored-by: m1xxos <66390094+m1xxos@users.noreply.github.com> Co-authored-by: Adil <mr.adil777@gmail.com>
290 lines
9.5 KiB
TypeScript
290 lines
9.5 KiB
TypeScript
import {
|
|
ArticleAttributes,
|
|
ArticleReadingProgressMutationInput,
|
|
useUpdateItemReadStatus,
|
|
} from '../../../../lib/networking/library_items/useLibraryItems'
|
|
import { HStack, VStack } from '../../../elements/LayoutPrimitives'
|
|
import React, { useEffect, useRef, useState } from 'react'
|
|
import { UserBasicData } from '../../../../lib/networking/queries/useGetViewerQuery'
|
|
import 'react-sliding-pane/dist/react-sliding-pane.css'
|
|
import {
|
|
CreateHighlightInput,
|
|
useCreateHighlight,
|
|
useDeleteHighlight,
|
|
useMergeHighlight,
|
|
useUpdateHighlight,
|
|
} from '../../../../lib/networking/highlights/useItemHighlights'
|
|
import 'pdfjs-dist/web/pdf_viewer.css'
|
|
import { EventBus, PDFViewer } from 'pdfjs-dist/types/web/pdf_viewer'
|
|
import PdfViewer from './PdfViewer'
|
|
import PdfToolbar from './PdfToolbar'
|
|
import PdfSearchBar from './PdfSearchBar'
|
|
import { NotebookHeader } from '../NotebookHeader'
|
|
import { NotebookContent } from '../Notebook'
|
|
import { ResizableSidebar } from '../ResizableSidebar'
|
|
import { PDFDocumentProxy } from 'pdfjs-dist'
|
|
import { PDFLinkService } from 'pdfjs-dist/types/web/pdf_link_service'
|
|
import PdfSideBar from './PdfSideBar'
|
|
|
|
export type PdfArticleContainerProps = {
|
|
viewer: UserBasicData
|
|
article: ArticleAttributes
|
|
showHighlightsModal: boolean
|
|
setShowHighlightsModal: React.Dispatch<React.SetStateAction<boolean>>
|
|
}
|
|
|
|
export default function PdfArticleContainer(props: PdfArticleContainerProps) {
|
|
// @ts-ignore
|
|
const pdfJS = import('pdfjs-dist/build/pdf.min.mjs')
|
|
const containerRef = useRef<HTMLDivElement | null>(null)
|
|
const [pdfViewer, setPdfViewer] = useState<PDFViewer | null>(null)
|
|
const [eventBus, setEventBus] = useState<EventBus | null>(null)
|
|
const [pageNumber, setPageNumber] = useState<number>(1)
|
|
const [pageCount, setTotalPageCount] = useState<number>(0)
|
|
const [showSearch, setShowSearch] = useState(false)
|
|
const [showToolbar, setShowToolbar] = useState(true)
|
|
const [saveLatestPage, setSaveLatestPage] = useState(true);
|
|
|
|
const [sidebarActive, setSidebarActive] = useState<boolean>(false)
|
|
|
|
const createHighlight = useCreateHighlight()
|
|
const deleteHighlight = useDeleteHighlight()
|
|
const mergeHighlight = useMergeHighlight()
|
|
const updateHighlight = useUpdateHighlight()
|
|
const updateItemReadStatus = useUpdateItemReadStatus()
|
|
|
|
const createPdfViewer = async (): Promise<PDFViewer> => {
|
|
const pdfJSLib = await pdfJS
|
|
const pdfjsViewer = await import('pdfjs-dist/web/pdf_viewer.mjs')
|
|
|
|
pdfJSLib.GlobalWorkerOptions.workerSrc =
|
|
window.location.origin + '/pdfjs-dist/pdf.worker.min.mjs'
|
|
|
|
const eventBus = new pdfjsViewer.EventBus()
|
|
const pdfLinkService = new pdfjsViewer.PDFLinkService({
|
|
eventBus,
|
|
})
|
|
const pdfFindController = new pdfjsViewer.PDFFindController({
|
|
eventBus,
|
|
linkService: pdfLinkService,
|
|
})
|
|
|
|
const pdfScriptingManager = new pdfjsViewer.PDFScriptingManager({
|
|
eventBus,
|
|
sandboxBundleSrc: window.location.origin + '/pdfjs-dist/pdf.sandbox.mjs',
|
|
})
|
|
|
|
const pdfViewer = new pdfjsViewer.PDFViewer({
|
|
container: containerRef.current!,
|
|
eventBus,
|
|
linkService: pdfLinkService,
|
|
findController: pdfFindController,
|
|
scriptingManager: pdfScriptingManager,
|
|
})
|
|
pdfScriptingManager.setViewer(pdfViewer)
|
|
pdfLinkService.pdfViewer = pdfViewer
|
|
|
|
return pdfViewer
|
|
}
|
|
|
|
const loadPdfDocument = async (): Promise<PDFDocumentProxy> => {
|
|
const pdfJsLib = await pdfJS
|
|
const loadingTask = pdfJsLib.getDocument({
|
|
url: props.article.url,
|
|
cMapUrl: window.location.origin + '/pdfjs-dist/cmaps/',
|
|
cMapPacked: true,
|
|
enableXfa: true,
|
|
})
|
|
|
|
return loadingTask.promise
|
|
}
|
|
|
|
useEffect(() => {
|
|
// Uses the existing mechanism to hide the reader toolbar from pspdfkit
|
|
const updateReaderSettings = () => {
|
|
const show = localStorage.getItem('reader-show-pdf-tool-bar')
|
|
const showBar = show ? JSON.parse(show) == true : true
|
|
setShowToolbar(showBar)
|
|
|
|
const latestPage = localStorage.getItem('reader-remember-latest-page')
|
|
const latestPageSave = latestPage ? JSON.parse(latestPage) == true : false
|
|
setSaveLatestPage(latestPageSave)
|
|
}
|
|
|
|
document.addEventListener('pdfReaderUpdateSettings', updateReaderSettings)
|
|
updateReaderSettings();
|
|
|
|
;(async () => {
|
|
const pdfViewer = await createPdfViewer()
|
|
const pdfDocument = await loadPdfDocument()
|
|
|
|
setTotalPageCount(pdfDocument.numPages)
|
|
pdfViewer.setDocument(pdfDocument)
|
|
|
|
const linkService = pdfViewer.linkService as PDFLinkService
|
|
linkService.setDocument(pdfDocument, null)
|
|
|
|
// Doesn't seem to get applied straight away, causing an issue where the scale would
|
|
// be set to 0. We do a 200 ms timeout to avoid this bug.
|
|
setTimeout(() => {
|
|
pdfViewer.currentScale = 1
|
|
pdfViewer.scrollPageIntoView({
|
|
pageNumber: props.article.readingProgressAnchorIndex,
|
|
})
|
|
}, 200)
|
|
|
|
setPdfViewer(pdfViewer)
|
|
setEventBus(pdfViewer.eventBus)
|
|
|
|
pdfViewer.eventBus.on(
|
|
'pagechanging',
|
|
(e: { previous: number; pageNumber: number }) => {
|
|
console.log('Page Changing....')
|
|
setPageNumber(e.pageNumber)
|
|
}
|
|
)
|
|
})()
|
|
}, [])
|
|
|
|
return (
|
|
<VStack css={{ width: '100%' }}>
|
|
{showSearch && <PdfSearchBar pdfViewer={pdfViewer} eventBus={eventBus} />}
|
|
{showToolbar && (
|
|
<PdfToolbar
|
|
setShowSidebar={setSidebarActive}
|
|
sidebarActive={sidebarActive}
|
|
viewer={props.viewer}
|
|
article={props.article}
|
|
pdfViewer={pdfViewer}
|
|
eventBus={eventBus}
|
|
pageNumber={pageNumber}
|
|
setPageNumber={setPageNumber}
|
|
totalPageNumbers={pageCount}
|
|
showSearch={showSearch}
|
|
setShowSearch={setShowSearch}
|
|
/>
|
|
)}
|
|
|
|
<HStack>
|
|
<PdfSideBar
|
|
setPage={(page: number) => {
|
|
if (pdfViewer) {
|
|
pdfViewer.currentPageNumber = page
|
|
}
|
|
}}
|
|
pdfDocument={pdfViewer?.pdfDocument}
|
|
activePage={pageNumber}
|
|
sidebarActive={sidebarActive}
|
|
totalPages={pageCount}
|
|
/>
|
|
<PdfViewer
|
|
viewer={props.viewer}
|
|
article={props.article}
|
|
containerRef={containerRef}
|
|
eventBus={eventBus}
|
|
sidebarActive={sidebarActive}
|
|
saveLatestPage={saveLatestPage}
|
|
pdfViewer={pdfViewer}
|
|
articleMutations={{
|
|
createHighlightMutation: async (input: CreateHighlightInput) => {
|
|
try {
|
|
return await createHighlight.mutateAsync({
|
|
itemId: props.article.id,
|
|
slug: props.article.slug,
|
|
input,
|
|
})
|
|
} catch (err) {
|
|
console.log('error creating highlight', err)
|
|
return undefined
|
|
}
|
|
},
|
|
deleteHighlightMutation: async (
|
|
_libraryItemId: string,
|
|
highlightId: string
|
|
) => {
|
|
try {
|
|
await deleteHighlight.mutateAsync({
|
|
itemId: props.article.id,
|
|
slug: props.article.slug,
|
|
highlightId,
|
|
})
|
|
return true
|
|
} catch (err) {
|
|
console.log('error deleting highlight', err)
|
|
return false
|
|
}
|
|
},
|
|
mergeHighlightMutation: async (input) => {
|
|
try {
|
|
const result = await mergeHighlight.mutateAsync({
|
|
itemId: props.article.id,
|
|
slug: props.article.slug,
|
|
input,
|
|
})
|
|
return result?.highlight
|
|
} catch (err) {
|
|
console.log('error merging highlight', err)
|
|
return undefined
|
|
}
|
|
},
|
|
updateHighlightMutation: async (input) => {
|
|
try {
|
|
const result = await updateHighlight.mutateAsync({
|
|
itemId: props.article.id,
|
|
slug: props.article.slug,
|
|
input,
|
|
})
|
|
return result?.id
|
|
} catch (err) {
|
|
console.log('error updating highlight', err)
|
|
return undefined
|
|
}
|
|
},
|
|
articleReadingProgressMutation: async (
|
|
input: ArticleReadingProgressMutationInput
|
|
) => {
|
|
try {
|
|
await updateItemReadStatus.mutateAsync({
|
|
itemId: props.article.id,
|
|
slug: props.article.slug,
|
|
input,
|
|
})
|
|
} catch {
|
|
return false
|
|
}
|
|
return true
|
|
},
|
|
}}
|
|
/>
|
|
</HStack>
|
|
<ResizableSidebar
|
|
isShow={props.showHighlightsModal}
|
|
onClose={() => {
|
|
props.setShowHighlightsModal(false)
|
|
}}
|
|
>
|
|
<NotebookHeader
|
|
viewer={props.viewer}
|
|
item={props.article}
|
|
setShowNotebook={props.setShowHighlightsModal}
|
|
/>
|
|
<NotebookContent
|
|
viewer={props.viewer}
|
|
item={props.article}
|
|
viewInReader={(highlightId) => {
|
|
const highlight = props.article.highlights?.filter(
|
|
(it) => it.id == highlightId
|
|
)
|
|
if (highlight && highlight.length == 1) {
|
|
const pageId = highlight[0].highlightPositionAnchorIndex
|
|
|
|
if (pdfViewer) {
|
|
pdfViewer.currentPageNumber = pageId ?? 1
|
|
}
|
|
}
|
|
}}
|
|
/>
|
|
</ResizableSidebar>
|
|
</VStack>
|
|
)
|
|
}
|