diff --git a/package.json b/package.json
index 4a72fb053..acb2e7e62 100644
--- a/package.json
+++ b/package.json
@@ -63,6 +63,7 @@
"react-i18next": "^11.15.3",
"react-icons": "^4.3.1",
"react-redux": "^7.2.6",
+ "react-zoom-pan-pinch": "^3.3.0",
"redux": "^4.1.2",
"rehype-katex": "5.0.0",
"remark-math": "3.0.1",
diff --git a/src/components/Layout/MDXContent.tsx b/src/components/Layout/MDXContent.tsx
index 692ce12c6..7f2fb1f0a 100644
--- a/src/components/Layout/MDXContent.tsx
+++ b/src/components/Layout/MDXContent.tsx
@@ -18,6 +18,8 @@ import { useTotalContributors } from "components/Avatar/Contributors";
import replaceInternalHref from "utils/anchor";
import { Pre } from "components/MDXComponents/Pre";
+import { ImageZoomable } from "components/MDXComponents/ImageZoomable";
+
export default function MDXContent(props: {
data: any;
className?: string;
@@ -79,6 +81,7 @@ export default function MDXContent(props: {
...MDXConponents,
Link,
pre: Pre,
+ img: ImageZoomable,
}}
>
{data}
diff --git a/src/components/MDXComponents/ImageZoomable.tsx b/src/components/MDXComponents/ImageZoomable.tsx
new file mode 100644
index 000000000..713604855
--- /dev/null
+++ b/src/components/MDXComponents/ImageZoomable.tsx
@@ -0,0 +1,171 @@
+import { Box, Fade, IconButton} from "@mui/material";
+
+import ZoomInIcon from "@mui/icons-material/ZoomIn";
+import ZoomOutIcon from "@mui/icons-material/ZoomOut";
+import AutorenewIcon from "@mui/icons-material/Autorenew";
+import FullscreenIcon from "@mui/icons-material/Fullscreen";
+import FullscreenExitIcon from "@mui/icons-material/FullscreenExit";
+
+import React, {
+ PropsWithChildren,
+ useRef,
+ useState,
+ } from "react";
+import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
+
+type ImageZoomableWrapperProps = PropsWithChildren<{
+ src: string;
+ alt: string;
+}>
+
+export const ImageZoomable: React.FC = ({ src, alt }) => {
+
+ const [isFullscreen, setIsFullScreen] = useState(false);
+ const [isHovered, setIsHovered] = useState(false);
+ const [isDragging, setIsDragging] = useState(false);
+ const [isTouchMoving, setTouchMoving] = useState(false);
+ const ImageZoomableRef = useRef(null);
+ const contextIconSize = isFullscreen ? ("medium") : ("small");
+ var contextCursor = isDragging ? ("grabbing") : ("grab");
+
+ const fullscreen = () => {
+ if (ImageZoomableRef.current) {
+ if (isFullscreen) {
+ setIsFullScreen(false);
+ let ele_overlay = ImageZoomableRef.current.getElementsByClassName("zoom-overlay")[0] as HTMLElement;
+ ele_overlay.style.opacity = "0";
+ ele_overlay.style.transition = "opacity .15s ease-in-out";
+
+ ImageZoomableRef.current.parentElement!.style.height = "unset";
+ ImageZoomableRef.current.parentElement!.style.border = "none";
+
+ } else {
+
+ setIsFullScreen(true);
+ let ele_overlay = ImageZoomableRef.current.getElementsByClassName("zoom-overlay")[0] as HTMLElement;
+ ele_overlay.style.opacity = "1";
+ ele_overlay.style.transition = "opacity .3s ease-in-out";
+
+ ImageZoomableRef.current.parentElement!.style.height = "50px";
+ ImageZoomableRef.current.parentElement!.style.border = "1px grey dashed";
+
+ }
+ }
+ }
+
+ return (
+ {
+ contextCursor = "grab";
+ setIsHovered(true);
+ }}
+ onMouseLeave={() => {
+ if (!isFullscreen) {
+ setIsHovered(false);
+ }
+ }}
+ onMouseDown={() => {
+ setIsDragging(true);
+ contextCursor = "grabbing";
+ }}
+ onMouseUp={() => {
+ setIsDragging(false);
+ contextCursor = "grab";
+ }}
+ onTouchMove={() => {
+ setTouchMoving(true);
+ }}
+ onTouchStart={()=>{
+ setTouchMoving(true);
+ setTimeout(() => {
+ setTouchMoving(false);
+ }, 4000);
+ }}
+ >
+
+
+ {({ zoomIn, zoomOut, resetTransform, ...rest }) => (
+
+
+
+ zoomIn()}
+ >
+
+
+ zoomOut()}
+ >
+
+
+ resetTransform()}
+ >
+
+
+ fullscreen()}
+ >
+ { isFullscreen ? (
+ ) : (
+
+ ) }
+
+
+
+
+
+
+
+ )}
+
+
+
+ );
+};
diff --git a/yarn.lock b/yarn.lock
index d4fb38621..f7fbe4409 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11742,6 +11742,11 @@ react-transition-group@^4.4.5:
loose-envify "^1.4.0"
prop-types "^15.6.2"
+react-zoom-pan-pinch@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.npmmirror.com/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.3.0.tgz#873648438c5244d89fcc2127614046928429cbe0"
+ integrity sha512-vy1h8aenDzXye+HRqANZaSA8IPHoqOiuDPFBkswoyPUH8uMfsmbeH6gFI4r4BhEJa0xIlcA+FbvhidRWKGUrOg==
+
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"