diff options
| author | Ahmad Mujahid <55625580+AhmadMuj@users.noreply.github.com> | 2025-02-17 13:25:16 +0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-17 09:25:16 +0000 |
| commit | e5cb9aa848009ea22c1385e4d33b7edf372979fb (patch) | |
| tree | 89470d8da8aab10f30bbfccea8d1b0cea08a1408 /apps/web/components/dashboard/preview/AssetContentSection.tsx | |
| parent | a14be108736133535e2828b6bbdc8d0a69accd63 (diff) | |
| download | karakeep-e5cb9aa848009ea22c1385e4d33b7edf372979fb.tar.zst | |
feat: Add PDF screenshot generation and display (#995)
* Updated pdf2json to 3.1.5
* Extract and store a screenshot from PDF files using pdf2pic
* Installing graphicsmagick and ghostscript
* Generate Missing PDF screenshot with tidyAssets worker for backward support
* Display PDF screenshot instead of the PDF in web if it exists.
* Display PDF screenshot in mobile app if exists.
* Updated pnpm-lock.yaml
* Removed console.log
* Revert the unnecessary changes in package.json
* Revert pnpm-lock changes
* Prevent rendering PDF files if the screenshot is not generated
* refactor: replace useEffect with useMemo for section initialization
* feat: show PDF file download button and handle large PDFs by defaulting to screenshot view
* feat: add file size to openapi spec
* feature: Add Assets preprocessing in fix mode to admin actions
* i18n: add reprocess_assets_fix_mode translation
* i18n: Add missing ar translations
* A bunch of fixes
* Fix openspec schema
---------
Co-authored-by: Mohamed Bassem <me@mbassem.com>
Diffstat (limited to 'apps/web/components/dashboard/preview/AssetContentSection.tsx')
| -rw-r--r-- | apps/web/components/dashboard/preview/AssetContentSection.tsx | 131 |
1 files changed, 103 insertions, 28 deletions
diff --git a/apps/web/components/dashboard/preview/AssetContentSection.tsx b/apps/web/components/dashboard/preview/AssetContentSection.tsx index 03ab8a43..8590d2ad 100644 --- a/apps/web/components/dashboard/preview/AssetContentSection.tsx +++ b/apps/web/components/dashboard/preview/AssetContentSection.tsx @@ -1,42 +1,117 @@ +import { useMemo, useState } from "react"; import Image from "next/image"; import Link from "next/link"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { useTranslation } from "@/lib/i18n/client"; +import { getAssetUrl } from "@hoarder/shared-react/utils/assetUtils"; import { BookmarkTypes, ZBookmark } from "@hoarder/shared/types/bookmarks"; -export function AssetContentSection({ bookmark }: { bookmark: ZBookmark }) { +// 20 MB +const BIG_FILE_SIZE = 20 * 1024 * 1024; + +function PDFContentSection({ bookmark }: { bookmark: ZBookmark }) { if (bookmark.content.type != BookmarkTypes.ASSET) { throw new Error("Invalid content type"); } + const { t } = useTranslation(); - switch (bookmark.content.assetType) { - case "image": { - return ( - <div className="relative h-full min-w-full"> - <Link - href={`/api/assets/${bookmark.content.assetId}`} - target="_blank" - > - <Image - alt="asset" - fill={true} - className="object-contain" - src={`/api/assets/${bookmark.content.assetId}`} - /> - </Link> - </div> - ); + const initialSection = useMemo(() => { + if (bookmark.content.type != BookmarkTypes.ASSET) { + throw new Error("Invalid content type"); } - case "pdf": { - return ( - <iframe - title={bookmark.content.assetId} - className="h-full w-full" - src={`/api/assets/${bookmark.content.assetId}`} - /> - ); + + const screenshot = bookmark.assets.find( + (item) => item.assetType === "assetScreenshot", + ); + const bigSize = + bookmark.content.size && bookmark.content.size > BIG_FILE_SIZE; + if (bigSize && screenshot) { + return "screenshot"; } - default: { + return "pdf"; + }, [bookmark]); + const [section, setSection] = useState(initialSection); + + const screenshot = bookmark.assets.find( + (r) => r.assetType === "assetScreenshot", + )?.id; + + const content = + section === "screenshot" && screenshot ? ( + <div className="relative h-full min-w-full"> + <Image + alt="screenshot" + src={getAssetUrl(screenshot)} + fill={true} + className="object-contain" + /> + </div> + ) : ( + <iframe + title={bookmark.content.assetId} + className="h-full w-full" + src={getAssetUrl(bookmark.content.assetId)} + /> + ); + + return ( + <div className="flex h-full flex-col items-center gap-2"> + <div className="flex w-full items-center justify-center gap-4"> + <Select onValueChange={setSection} value={section}> + <SelectTrigger className="w-fit"> + <SelectValue /> + </SelectTrigger> + <SelectContent> + <SelectGroup> + <SelectItem value="screenshot" disabled={!screenshot}> + {t("common.screenshot")} + </SelectItem> + <SelectItem value="pdf">PDF</SelectItem> + </SelectGroup> + </SelectContent> + </Select> + </div> + {content} + </div> + ); +} + +function ImageContentSection({ bookmark }: { bookmark: ZBookmark }) { + if (bookmark.content.type != BookmarkTypes.ASSET) { + throw new Error("Invalid content type"); + } + return ( + <div className="relative h-full min-w-full"> + <Link href={getAssetUrl(bookmark.content.assetId)} target="_blank"> + <Image + alt="asset" + fill={true} + className="object-contain" + src={getAssetUrl(bookmark.content.assetId)} + /> + </Link> + </div> + ); +} + +export function AssetContentSection({ bookmark }: { bookmark: ZBookmark }) { + if (bookmark.content.type != BookmarkTypes.ASSET) { + throw new Error("Invalid content type"); + } + switch (bookmark.content.assetType) { + case "image": + return <ImageContentSection bookmark={bookmark} />; + case "pdf": + return <PDFContentSection bookmark={bookmark} />; + default: return <div>Unsupported asset type</div>; - } } } |
