feat: render pdf files via chromium pdfium plugin

This commit is contained in:
Gagancreates 2026-05-08 02:07:16 +05:30
parent b24113b78e
commit b3519433eb
3 changed files with 64 additions and 0 deletions

View file

@ -221,6 +221,9 @@ function createWindow() {
contextIsolation: true,
sandbox: true,
preload: preloadPath,
// Enable Chromium's built-in PDFium plugin so <iframe src="*.pdf">
// renders PDFs natively (zoom/scroll/print toolbar included).
plugins: true,
},
});

View file

@ -16,6 +16,7 @@ import { BasesView, type BaseConfig, DEFAULT_BASE_CONFIG } from '@/components/ba
import { HtmlFileViewer } from '@/components/html-file-viewer';
import { ImageFileViewer } from '@/components/image-file-viewer';
import { VideoFileViewer } from '@/components/video-file-viewer';
import { PdfFileViewer } from '@/components/pdf-file-viewer';
import { useDebounce } from './hooks/use-debounce';
import { SidebarContentPanel } from '@/components/sidebar-content';
import { SuggestedTopicsView } from '@/components/suggested-topics-view';
@ -4841,6 +4842,10 @@ function App() {
<div className="flex-1 min-h-0 overflow-hidden">
<VideoFileViewer path={selectedPath} />
</div>
) : selectedPath?.toLowerCase().endsWith('.pdf') ? (
<div className="flex-1 min-h-0 overflow-hidden">
<PdfFileViewer path={selectedPath} />
</div>
) : (
<div className="flex-1 overflow-auto p-4">
<pre className="text-sm font-mono text-foreground whitespace-pre-wrap">

View file

@ -0,0 +1,56 @@
import { useEffect, useState } from 'react'
import { ExternalLinkIcon, FileTextIcon, Loader2Icon } from 'lucide-react'
interface PdfFileViewerProps {
path: string
}
type State = 'loading' | 'ready' | 'error'
export function PdfFileViewer({ path }: PdfFileViewerProps) {
const [state, setState] = useState<State>('loading')
useEffect(() => {
setState('loading')
}, [path])
const src = `app://workspace/${path.split('/').map(encodeURIComponent).join('/')}`
if (state === 'error') {
return (
<div className="flex h-full w-full flex-col items-center justify-center gap-3 px-6 text-center text-muted-foreground">
<FileTextIcon className="size-6" />
<p className="text-sm font-medium text-foreground">Cannot preview this PDF</p>
<button
type="button"
onClick={() => {
void window.ipc.invoke('shell:openPath', { path })
}}
className="inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-xs font-medium text-foreground hover:bg-accent"
>
<ExternalLinkIcon className="size-3.5" />
Open in system
</button>
</div>
)
}
return (
<div className="relative h-full w-full">
<iframe
key={path}
src={src}
className="h-full w-full border-0 bg-white"
title="PDF preview"
onLoad={() => setState('ready')}
onError={() => setState('error')}
/>
{state === 'loading' && (
<div className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-background text-muted-foreground">
<Loader2Icon className="size-6 animate-spin" />
<p className="text-sm">Loading PDF</p>
</div>
)}
</div>
)
}