diff --git a/apps/web/src/common/dialog-controller.tsx b/apps/web/src/common/dialog-controller.tsx index c3a225851..52e9f3510 100644 --- a/apps/web/src/common/dialog-controller.tsx +++ b/apps/web/src/common/dialog-controller.tsx @@ -186,6 +186,12 @@ export function showPromptDialog(props: { )); } +export function showPdfViewDialog(props: { url: string; hash: string }) { + return showDialog("PdfViewDialog", (Dialog, perform) => ( + perform(null)} /> + )); +} + export function showEmailChangeDialog() { return showDialog("EmailChangeDialog", (Dialog, perform) => ( perform(null)} /> diff --git a/apps/web/src/components/attachment/index.tsx b/apps/web/src/components/attachment/index.tsx index 88f5e6fc9..f215892c9 100644 --- a/apps/web/src/components/attachment/index.tsx +++ b/apps/web/src/components/attachment/index.tsx @@ -33,6 +33,7 @@ import { FileWebClip, Icon, Loading, + PasswordInvisible, References, Rename, Reupload, @@ -42,11 +43,12 @@ import { showToast } from "../../utils/toast"; import { hashNavigate } from "../../navigation"; import { closeOpenedDialog, + showPdfViewDialog, showPromptDialog } from "../../common/dialog-controller"; import { store } from "../../stores/attachment-store"; import { db } from "../../common/db"; -import { saveAttachment } from "../../common/attachments"; +import { downloadAttachment, saveAttachment } from "../../common/attachments"; import { reuploadAttachment } from "../editor/picker"; import { Multiselect } from "../../common/multi-select"; import { Menu } from "../../hooks/use-menu"; @@ -59,6 +61,9 @@ import { useEffect, useState } from "react"; import { AppEventManager, AppEvents } from "../../common/app-events"; import { getFormattedDate } from "@notesnook/common"; import { MenuItem } from "@notesnook/ui"; +import { ScopedThemeProvider } from "../theme-provider"; +import { Lightbox } from "../lightbox"; +import ReactDOM from "react-dom"; const FILE_ICONS: Record = { "image/": FileImage, @@ -235,6 +240,56 @@ const AttachmentMenuItems: ( status?: AttachmentProgressStatus ) => MenuItem[] = (attachment, status) => { return [ + { + type: "button", + key: "preview-doc", + title: "Preview Document", + icon: PasswordInvisible.path, + isHidden: !(attachment.metadata.type === "application/pdf"), + onClick: async () => { + const blob = await downloadAttachment( + attachment.metadata.hash, + "blob", + attachment.id.toString() + ); + if (!blob) return; + await showPdfViewDialog({ + url: URL.createObjectURL(blob), + hash: attachment.metadata.hash + }); + } + }, + { + type: "button", + key: "preview-image", + title: "Preview Image", + icon: PasswordInvisible.path, + isHidden: !attachment.metadata.type.startsWith("image/"), + onClick: async () => { + const container = document.getElementById("dialogContainer"); + if (!(container instanceof HTMLElement)) return; + + const dataurl = await downloadAttachment( + attachment.metadata.hash, + "base64", + attachment.id.toString() + ); + if (!dataurl) + return showToast("error", "This image cannot be previewed."); + + ReactDOM.render( + + { + ReactDOM.unmountComponentAtNode(container); + }} + /> + , + container + ); + } + }, { type: "button", key: "notes", diff --git a/apps/web/src/dialogs/index.ts b/apps/web/src/dialogs/index.ts index 83e22590a..8a008f377 100644 --- a/apps/web/src/dialogs/index.ts +++ b/apps/web/src/dialogs/index.ts @@ -52,6 +52,7 @@ const MigrationDialog = React.lazy(() => import("./migration-dialog")); const EmailChangeDialog = React.lazy(() => import("./email-change-dialog")); const AddTagsDialog = React.lazy(() => import("./add-tags-dialog")); const ThemeDetailsDialog = React.lazy(() => import("./theme-details-dialog")); +const PdfViewDialog = React.lazy(() => import("./pdf-view-dialog")); export const Dialogs = { AddNotebookDialog, @@ -79,5 +80,6 @@ export const Dialogs = { EmailChangeDialog, AddTagsDialog, SettingsDialog, - ThemeDetailsDialog + ThemeDetailsDialog, + PdfViewDialog }; diff --git a/apps/web/src/dialogs/pdf-view-dialog.tsx b/apps/web/src/dialogs/pdf-view-dialog.tsx new file mode 100644 index 000000000..a5f11e68c --- /dev/null +++ b/apps/web/src/dialogs/pdf-view-dialog.tsx @@ -0,0 +1,40 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +import React from "react"; +import { Perform } from "../common/dialog-controller"; +import Dialog from "../components/dialog"; + +const PDFPreview = React.lazy(() => import("../components/pdf-preview")); + +type PdfViewDialogProps = { onClose: Perform; url: string; hash: string }; +function PdfViewDialog({ onClose, hash, url }: PdfViewDialogProps) { + return ( + onClose(false)} + noScroll + sx={{ bg: "transparent" }} + > + onClose(false)} /> + + ); +} + +export default PdfViewDialog;