import { useCallback, useMemo, useState, type KeyboardEvent } from 'react'
import { convertFileSrc } from '@tauri-apps/api/core'
import { ArrowSquareOut, FileDashed, ImageSquare, WarningCircle } from '@phosphor-icons/react'
import type { VaultEntry } from '../types'
import { isImagePreviewEntry, previewFileTypeLabel } from '../utils/filePreview'
import { focusNoteListContainer } from '../utils/neighborhoodHistory'
import { openLocalFile } from '../utils/url'
import { Button } from './ui/button'
interface FilePreviewProps {
entry: VaultEntry
}
interface FilePreviewFallbackProps {
icon: 'warning' | 'file'
title: string
description: string
onOpenExternal: () => void
}
function FilePreviewFallback({ icon, title, description, onOpenExternal }: FilePreviewFallbackProps) {
const Icon = icon === 'warning' ? WarningCircle : FileDashed
return (
)
}
function FilePreviewHeader({
entry,
isImage,
fileTypeLabel,
onOpenExternal,
}: {
entry: VaultEntry
isImage: boolean
fileTypeLabel: string
onOpenExternal: () => void
}) {
const HeaderIcon = isImage ? ImageSquare : FileDashed
return (
{entry.title}
{fileTypeLabel}
)
}
function FilePreviewImage({
entry,
imageSrc,
onImageError,
}: {
entry: VaultEntry
imageSrc: string
onImageError: () => void
}) {
return (
)
}
function shouldRenderImagePreview(isImage: boolean, imageSrc: string | null, imageFailed: boolean): imageSrc is string {
return isImage && imageSrc !== null && !imageFailed
}
function FilePreviewBody({
entry,
isImage,
imageSrc,
imageFailed,
onImageError,
onOpenExternal,
}: {
entry: VaultEntry
isImage: boolean
imageSrc: string | null
imageFailed: boolean
onImageError: () => void
onOpenExternal: () => void
}) {
if (shouldRenderImagePreview(isImage, imageSrc, imageFailed)) {
return
}
return (
)
}
export function FilePreview({ entry }: FilePreviewProps) {
const [imageFailed, setImageFailed] = useState(false)
const isImage = isImagePreviewEntry(entry)
const imageSrc = useMemo(() => (isImage ? convertFileSrc(entry.path) : null), [entry.path, isImage])
const fileTypeLabel = previewFileTypeLabel(entry)
const handleImageError = useCallback(() => setImageFailed(true), [])
const handleOpenExternal = useCallback(() => {
void openLocalFile(entry.path).catch((error) => {
console.warn('Failed to open file with default app:', error)
})
}, [entry.path])
const handleKeyDown = useCallback((event: KeyboardEvent) => {
if (event.key !== 'Escape') return
event.preventDefault()
focusNoteListContainer(document)
}, [])
return (
)
}