diff --git a/apps/client/src/widgets/NoteDetail.tsx b/apps/client/src/widgets/NoteDetail.tsx
index d0eb6530a..06270a59a 100644
--- a/apps/client/src/widgets/NoteDetail.tsx
+++ b/apps/client/src/widgets/NoteDetail.tsx
@@ -14,6 +14,7 @@ import ContentWidget from "./type_widgets/ContentWidget";
import WebView from "./type_widgets/WebView";
import "./NoteDetail.css";
import File from "./type_widgets/File";
+import Image from "./type_widgets/Image";
/**
* A `NoteType` altered by the note detail widget, taking into consideration whether the note is editable or not and adding special note types such as an empty one,
@@ -70,6 +71,7 @@ function getCorrespondingWidget(noteType: ExtendedNoteType | undefined, props: T
case "contentWidget": return
case "webView": return
case "file": return
+ case "image": return
default: break;
}
}
diff --git a/apps/client/src/widgets/type_widgets/Image.css b/apps/client/src/widgets/type_widgets/Image.css
new file mode 100644
index 000000000..1e638f86b
--- /dev/null
+++ b/apps/client/src/widgets/type_widgets/Image.css
@@ -0,0 +1,24 @@
+.type-image .note-detail {
+ height: 100%;
+}
+
+.note-detail-image {
+ height: 100%;
+}
+
+.note-detail-image-wrapper {
+ position: relative;
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+ justify-content: center;
+ height: 100%;
+}
+
+.note-detail-image-view {
+ display: block;
+ width: auto;
+ height: auto;
+ align-self: center;
+ flex-shrink: 0;
+}
\ No newline at end of file
diff --git a/apps/client/src/widgets/type_widgets/Image.tsx b/apps/client/src/widgets/type_widgets/Image.tsx
new file mode 100644
index 000000000..956a461bd
--- /dev/null
+++ b/apps/client/src/widgets/type_widgets/Image.tsx
@@ -0,0 +1,46 @@
+import { useEffect, useRef, useState } from "preact/hooks";
+import { createImageSrcUrl } from "../../services/utils";
+import { useTriliumEvent, useUniqueName } from "../react/hooks";
+import "./Image.css";
+import { TypeWidgetProps } from "./type_widget";
+import WheelZoom from 'vanilla-js-wheel-zoom';
+import image_context_menu from "../../menus/image_context_menu";
+import { refToJQuerySelector } from "../react/react_utils";
+import { copyImageReferenceToClipboard } from "../../services/image";
+
+export default function Image({ note, ntxId }: TypeWidgetProps) {
+ const uniqueId = useUniqueName("image");
+ const containerRef = useRef(null);
+
+ // Set up pan & zoom
+ useEffect(() => {
+ const zoomInstance = WheelZoom.create(`#${uniqueId}`, {
+ maxScale: 50,
+ speed: 1.3,
+ zoomOnClick: false
+ });
+
+ return () => zoomInstance.destroy();
+ }, [ note ]);
+
+ // Set up context menu
+ useEffect(() => image_context_menu.setupContextMenu(refToJQuerySelector(containerRef)), []);
+
+ // Copy reference events
+ useTriliumEvent("copyImageReferenceToClipboard", ({ ntxId: eventNtxId }) => {
+ if (eventNtxId !== ntxId) return;
+ copyImageReferenceToClipboard(refToJQuerySelector(containerRef));
+ });
+
+ return (
+
+
+
})
+
+
+ )
+}
diff --git a/apps/client/src/widgets/type_widgets_old/image.ts b/apps/client/src/widgets/type_widgets_old/image.ts
index e4afcbe1e..f5e337b7b 100644
--- a/apps/client/src/widgets/type_widgets_old/image.ts
+++ b/apps/client/src/widgets/type_widgets_old/image.ts
@@ -4,41 +4,6 @@ import imageContextMenuService from "../../menus/image_context_menu.js";
import imageService from "../../services/image.js";
import type FNote from "../../entities/fnote.js";
import type { EventData } from "../../components/app_context.js";
-import WheelZoom from 'vanilla-js-wheel-zoom';
-
-const TPL = /*html*/`
-
-
-
-
-
![]()
-
-
`;
class ImageTypeWidget extends TypeWidget {
@@ -49,40 +14,7 @@ class ImageTypeWidget extends TypeWidget {
return "image";
}
- doRender() {
- this.$widget = $(TPL);
- this.$imageWrapper = this.$widget.find(".note-detail-image-wrapper");
- this.$imageView = this.$widget.find(".note-detail-image-view").attr("id", `image-view-${utils.randomString(10)}`);
-
- const initZoom = async () => {
- const element = document.querySelector(`#${this.$imageView.attr("id")}`);
- if (element) {
- WheelZoom.create(`#${this.$imageView.attr("id")}`, {
- maxScale: 50,
- speed: 1.3,
- zoomOnClick: false
- });
- } else {
- requestAnimationFrame(initZoom);
- }
- };
- initZoom();
-
- imageContextMenuService.setupContextMenu(this.$imageView);
-
- super.doRender();
- }
-
- async doRefresh(note: FNote) {
- this.$imageView.prop("src", utils.createImageSrcUrl(note));
- }
-
copyImageReferenceToClipboardEvent({ ntxId }: EventData<"copyImageReferenceToClipboard">) {
- if (!this.isNoteContext(ntxId)) {
- return;
- }
-
- imageService.copyImageReferenceToClipboard(this.$imageWrapper);
}
async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {