Skip to content

Commit

Permalink
Added preview for image in EditorContent (#950)
Browse files Browse the repository at this point in the history
* Added preview for image in EditorContent

* Updated styles of ImagePreview

* Updatd conditions to satisfy ImagePreview

---------

Co-authored-by: bot-bigbinary <[email protected]>
  • Loading branch information
gaagul and bot-bigbinary authored Dec 6, 2023
1 parent 236fdca commit d06760c
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 12 deletions.
52 changes: 52 additions & 0 deletions src/components/EditorContent/ImagePreview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { useEffect, useRef, useState } from "react";

import { useOnClickOutside } from "neetocommons/react-utils";
import { Close } from "neetoicons";
import { Button, Spinner } from "neetoui";
import { createPortal } from "react-dom";

const ImagePreview = ({ imagePreviewUrl, setImagePreviewUrl }) => {
const [isLoading, setIsLoading] = useState(true);

const imagePreviewRef = useRef(null);

useOnClickOutside(imagePreviewRef, () => setImagePreviewUrl(null), {
enabled: true,
});

useEffect(() => {
document.addEventListener(
"keydown",
e => e.key === "Escape" && setImagePreviewUrl(null)
);

return () =>
document.removeEventListener(
"keydown",
e => e.key === "Escape" && setImagePreviewUrl(null)
);
}, []);

return createPortal(
<div className="image-preview-wrapper">
<div className="close-button">
<Button
icon={Close}
style="secondary"
onClick={() => setImagePreviewUrl(null)}
/>
</div>
{isLoading && <Spinner className="spinner" />}
<img
alt="Image Preview"
className="image-preview"
ref={imagePreviewRef}
src={imagePreviewUrl}
onLoad={() => setIsLoading(false)}
/>
</div>,
document.body
);
};

export default ImagePreview;
48 changes: 36 additions & 12 deletions src/components/EditorContent/index.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React, { useEffect, useRef } from "react";
import React, { useEffect, useRef, useState } from "react";

import classnames from "classnames";
import DOMPurify from "dompurify";
import CopyToClipboardButton from "neetomolecules/CopyToClipboardButton";
import { not } from "ramda";
import { createRoot } from "react-dom/client";

import { EDITOR_CONTENT_CLASSNAME, SANITIZE_OPTIONS } from "./constants";
import ImagePreview from "./ImagePreview";
import { highlightCode, substituteVariables } from "./utils";

const EditorContent = ({
Expand All @@ -14,6 +16,7 @@ const EditorContent = ({
className,
...otherProps
}) => {
const [imagePreviewUrl, setImagePreviewUrl] = useState(null);
const editorContentRef = useRef(null);

const htmlContent = substituteVariables(highlightCode(content), variables);
Expand All @@ -37,24 +40,45 @@ const EditorContent = ({
);
preTag.appendChild(button);
});

const figureTags = editorContentRef.current?.querySelectorAll("figure");
figureTags.forEach(figureTag => {
const image = figureTag.querySelector("img");
const link = figureTag.querySelector("a");
if (
!image ||
not(window.getComputedStyle(link).pointerEvents === "none")
) {
return;
}
figureTag.style.cursor = "pointer";
figureTag.addEventListener("click", () => {
setImagePreviewUrl(image.src);
});
});
};

useEffect(() => {
injectCopyButtonToCodeBlocks();
}, [content]);

return (
<div
data-cy="neeto-editor-content"
ref={editorContentRef}
className={classnames(EDITOR_CONTENT_CLASSNAME, {
[className]: className,
})}
dangerouslySetInnerHTML={{
__html: sanitize(htmlContent, SANITIZE_OPTIONS),
}}
{...otherProps}
/>
<>
<div
data-cy="neeto-editor-content"
ref={editorContentRef}
className={classnames(EDITOR_CONTENT_CLASSNAME, {
[className]: className,
})}
dangerouslySetInnerHTML={{
__html: sanitize(htmlContent, SANITIZE_OPTIONS),
}}
{...otherProps}
/>
{imagePreviewUrl && (
<ImagePreview {...{ imagePreviewUrl, setImagePreviewUrl }} />
)}
</>
);
};

Expand Down
1 change: 1 addition & 0 deletions src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@import "./styles/editor/editor-content";
@import "./styles/editor/menu";
@import "./styles/editor/media-uploader";
@import "./styles/editor/image-preview";
@import "./styles/editor/emoji";
@import "./styles/editor/table";
@import "./styles/editor/link-popover";
Expand Down
29 changes: 29 additions & 0 deletions src/styles/editor/_image-preview.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.image-preview-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(var(--neeto-ui-gray-800), 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999999;

.close-button {
position: absolute;
top: 5px;
right: 5px;
}

.image-preview {
max-width: 70%;
max-height: 70%;
}

.spinner {
i {
background-color: rgb(var(--neeto-ui-gray-300));
}
}
}

0 comments on commit d06760c

Please sign in to comment.