feat(ImagePreview): fix positioning & add preview (WxH) (#60)

* yes

* forgot zoom factor

* lint -_- fr

* remove comments and fix loading spinner and check for mouseOnlyMode
This commit is contained in:
Creation's 2024-10-17 11:06:43 -04:00 committed by GitHub
parent 39909d95c4
commit 7220b98b3e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 96 additions and 26 deletions

View file

@ -24,17 +24,22 @@ let isDragging: boolean = false;
let shouldKeepPreviewOpenTimeout: NodeJS.Timeout | null = null; let shouldKeepPreviewOpenTimeout: NodeJS.Timeout | null = null;
let shouldKeepPreviewOpen: boolean = false; let shouldKeepPreviewOpen: boolean = false;
let hoverDelayTimeout: NodeJS.Timeout | null = null; let hoverDelayTimeout: NodeJS.Timeout | null = null;
let lastMouseEvent: MouseEvent | null = null;
let observer: MutationObserver | null = null; let observer: MutationObserver | null = null;
function deleteCurrentPreview() { function deleteCurrentPreview() {
if (!currentPreview || !currentPreviewFile || !currentPreviewFileSize || !currentPreviewType) return; if (!currentPreview || !currentPreviewFile || !currentPreviewFileSize || !currentPreviewType || !loadingSpinner) return;
currentPreview.remove(); currentPreview.remove();
loadingSpinner = null;
lastMouseEvent = null;
currentPreview = null; currentPreview = null;
currentPreviewFile = null; currentPreviewFile = null;
currentPreviewFileSize = null; currentPreviewFileSize = null;
currentPreviewType = null; currentPreviewType = null;
lastMouseEvent = null;
loadingSpinner = null;
zoomLevel = 1; zoomLevel = 1;
} }
@ -126,9 +131,19 @@ function loadImagePreview(url: string) {
const fileName = document.createElement("span"); const fileName = document.createElement("span");
const fileSize = document.createElement("span"); const fileSize = document.createElement("span");
fileSize.className = "file-size";
const fileSizeSpan = document.createElement("p");
const showingSize = document.createElement("p");
const mimeTypeSpan = document.createElement("span"); const mimeTypeSpan = document.createElement("span");
const updatePositionAfterLoad = () => {
if (lastMouseEvent && currentPreview) {
updatePreviewPosition(lastMouseEvent, currentPreview);
}
};
fileName.textContent = url.split("/").pop()?.split("?")[0] || ""; fileName.textContent = url.split("/").pop()?.split("?")[0] || "";
mimeTypeSpan.textContent = mimeType; mimeTypeSpan.textContent = mimeType;
if (currentPreviewType === "video") { if (currentPreviewType === "video") {
@ -146,11 +161,25 @@ function loadImagePreview(url: string) {
video.onloadeddata = () => { video.onloadeddata = () => {
currentPreviewFileSize = [video.videoWidth, video.videoHeight]; currentPreviewFileSize = [video.videoWidth, video.videoHeight];
fileSize.textContent = `${currentPreviewFileSize[0]}x${currentPreviewFileSize[1]}`; fileSizeSpan.textContent = `${currentPreviewFileSize[0]}x${currentPreviewFileSize[1]}`;
fileSize.appendChild(fileSizeSpan);
requestAnimationFrame(() => {
if (!currentPreviewFileSize) return;
const showingMediaSize = [video.clientWidth, video.clientHeight];
if (showingMediaSize[0] !== currentPreviewFileSize[0] && showingMediaSize[1] !== currentPreviewFileSize[1]) {
showingSize.textContent = showingMediaSize ? `(${showingMediaSize[0]}x${showingMediaSize[1]})` : "";
fileSize.appendChild(showingSize);
}
});
if (loadingSpinner) loadingSpinner.remove(); if (loadingSpinner) loadingSpinner.remove();
video.style.display = "block"; video.style.display = "block";
updatePositionAfterLoad();
}; };
preview.appendChild(video); preview.appendChild(video);
currentPreviewFile = video; currentPreviewFile = video;
} else { } else {
@ -159,10 +188,25 @@ function loadImagePreview(url: string) {
img.className = "preview-media"; img.className = "preview-media";
img.onload = () => { img.onload = () => {
currentPreviewFileSize = [img.naturalWidth, img.naturalHeight]; currentPreviewFileSize = [img.naturalWidth, img.naturalHeight];
fileSize.textContent = `${currentPreviewFileSize[0]}x${currentPreviewFileSize[1]}`; fileSizeSpan.textContent = `${currentPreviewFileSize[0]}x${currentPreviewFileSize[1]}`;
fileSize.appendChild(fileSizeSpan);
requestAnimationFrame(() => {
if (!currentPreviewFileSize) return;
const showingMediaSize = [img.clientWidth, img.clientHeight];
if (showingMediaSize[0] !== currentPreviewFileSize[0] && showingMediaSize[1] !== currentPreviewFileSize[1]) {
showingSize.textContent = showingMediaSize ? `(${showingMediaSize[0]}x${showingMediaSize[1]})` : "";
fileSize.appendChild(showingSize);
}
});
if (loadingSpinner) loadingSpinner.remove(); if (loadingSpinner) loadingSpinner.remove();
img.style.display = "block"; img.style.display = "block";
updatePositionAfterLoad();
}; };
preview.appendChild(img); preview.appendChild(img);
currentPreviewFile = img; currentPreviewFile = img;
} }
@ -172,6 +216,7 @@ function loadImagePreview(url: string) {
fileInfo.appendChild(fileSize); fileInfo.appendChild(fileSize);
preview.appendChild(fileInfo); preview.appendChild(fileInfo);
if (settings.store.mouseOnlyMode) {
currentPreviewFile.addEventListener("mouseover", () => { currentPreviewFile.addEventListener("mouseover", () => {
if (currentPreview && !isCtrlHeld) { if (currentPreview && !isCtrlHeld) {
shouldKeepPreviewOpen = true; shouldKeepPreviewOpen = true;
@ -185,13 +230,15 @@ function loadImagePreview(url: string) {
shouldKeepPreviewOpen = false; shouldKeepPreviewOpen = false;
} }
}); });
}
currentPreview.addEventListener("wheel", (event: WheelEvent) => { currentPreview.addEventListener("wheel", (event: WheelEvent) => {
const zoomSpeed = 0.0005; const [{ zoomFactor }, zoomSpeed] = [settings.store, 0.0005];
if (isCtrlHeld || event.target === currentPreview || event.target === currentPreviewFile) { if (isCtrlHeld || event.target === currentPreview || event.target === currentPreviewFile) {
event.preventDefault(); event.preventDefault();
zoomLevel += event.deltaY * -zoomSpeed;
zoomLevel += event.deltaY * -zoomSpeed * zoomFactor;
zoomLevel = Math.min(Math.max(zoomLevel, 0.5), 10); zoomLevel = Math.min(Math.max(zoomLevel, 0.5), 10);
@ -210,6 +257,7 @@ function loadImagePreview(url: string) {
} }
}); });
currentPreview.addEventListener("mousedown", (event: MouseEvent) => { currentPreview.addEventListener("mousedown", (event: MouseEvent) => {
if ((isCtrlHeld || shouldKeepPreviewOpen) && currentPreview) { if ((isCtrlHeld || shouldKeepPreviewOpen) && currentPreview) {
isDragging = true; isDragging = true;
@ -244,9 +292,12 @@ function updatePreviewPosition(mouseEvent: MouseEvent, element: HTMLElement) {
if (top + previewHeight > window.innerHeight) { if (top + previewHeight > window.innerHeight) {
top = mouseEvent.pageY - previewHeight - padding; top = mouseEvent.pageY - previewHeight - padding;
if (top < padding) { if (top < padding) {
top = window.innerHeight - previewHeight - padding; top = window.innerHeight - previewHeight - padding * 2;
} }
} else {
top = Math.min(top, window.innerHeight - previewHeight - padding * 2);
} }
currentPreview.style.left = `${left}px`; currentPreview.style.left = `${left}px`;
@ -263,10 +314,8 @@ function updatePreviewPosition(mouseEvent: MouseEvent, element: HTMLElement) {
function addHoverListener(element: Element) { function addHoverListener(element: Element) {
element.setAttribute("data-processed", "true"); element.setAttribute("data-processed", "true");
let lastMouseEvent: MouseEvent | null = null;
element.addEventListener("mouseover", event => { element.addEventListener("mouseover", event => {
if (currentPreview) { if (currentPreview || loadingSpinner) {
if (isCtrlHeld) return; if (isCtrlHeld) return;
deleteCurrentPreview(); deleteCurrentPreview();
@ -334,12 +383,10 @@ function addHoverListener(element: Element) {
} }
function handleKeydown(event: KeyboardEvent) { function handleKeydown(event: KeyboardEvent) {
if (event.key === "Control") { if (event.key === "Control" && currentPreview) {
isCtrlHeld = true; isCtrlHeld = true;
if (currentPreview) {
currentPreview.classList.add("allow-zoom-and-drag"); currentPreview.classList.add("allow-zoom-and-drag");
} }
}
} }
function handleKeyup(event: KeyboardEvent) { function handleKeyup(event: KeyboardEvent) {
@ -373,6 +420,7 @@ function removeHoverListeners() {
processedElements.forEach(element => { processedElements.forEach(element => {
const clone = element.cloneNode(true); const clone = element.cloneNode(true);
element.replaceWith(clone); element.replaceWith(clone);
element.removeAttribute("data-processed");
}); });
} }

View file

@ -43,6 +43,12 @@ const settings = definePluginSettings({
default: 0.5, default: 0.5,
markers: [0, 1, 2, 3, 4, 5], markers: [0, 1, 2, 3, 4, 5],
}, },
zoomFactor: {
type: OptionType.SLIDER,
description: "Speed at which the image zooms in",
default: 1.5,
markers: [1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5],
},
}); });
const mimeTypes = { const mimeTypes = {

View file

@ -1,7 +1,7 @@
.image-preview { .image-preview {
position: fixed; position: fixed;
z-index: 1000; z-index: 1000;
pointer-events: auto; pointer-events: none;
border: 2px solid var(--background-secondary); border: 2px solid var(--background-secondary);
background-color: var(--background-primary); background-color: var(--background-primary);
border-radius: 4px; border-radius: 4px;
@ -16,6 +16,7 @@
.image-preview.allow-zoom-and-drag { .image-preview.allow-zoom-and-drag {
background-color: transparent; background-color: transparent;
border: none; border: none;
pointer-events: auto;
} }
.image-preview .file-info { .image-preview .file-info {
@ -40,6 +41,21 @@
border: 1px solid var(--background-secondary); border: 1px solid var(--background-secondary);
} }
.file-size {
display: flex;
flex-direction: row;
gap: 5px;
}
.image-preview .file-info span p {
padding: 0;
margin: 0;
}
.image-preview .file-info span p:last-child:not(:first-child) {
color: var(--text-muted);
}
.image-preview.allow-zoom-and-drag .file-info { .image-preview.allow-zoom-and-drag .file-info {
display: none; display: none;
} }