feat: support image zoom (#355)
This commit is contained in:
parent
f1fd5f5468
commit
e7ee565aa8
|
|
@ -77,6 +77,7 @@
|
|||
"lottie-react": "^2.4.0",
|
||||
"mdast-util-to-string": "3.2.0",
|
||||
"mdast-util-toc": "6.1.1",
|
||||
"medium-zoom": "1.0.8",
|
||||
"mermaid": "10.1.0",
|
||||
"nanoid": "4.0.2",
|
||||
"next": "13.2.4",
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ dependencies:
|
|||
mdast-util-toc:
|
||||
specifier: 6.1.1
|
||||
version: 6.1.1
|
||||
medium-zoom:
|
||||
specifier: 1.0.8
|
||||
version: 1.0.8
|
||||
mermaid:
|
||||
specifier: 10.1.0
|
||||
version: 10.1.0(react-dom@18.2.0)(react@18.2.0)
|
||||
|
|
@ -10170,6 +10173,10 @@ packages:
|
|||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
dev: true
|
||||
|
||||
/medium-zoom@1.0.8:
|
||||
resolution: {integrity: sha512-CjFVuFq/IfrdqesAXfg+hzlDKu6A2n80ZIq0Kl9kWjoHh9j1N9Uvk5X0/MmN0hOfm5F9YBswlClhcwnmtwz7gA==}
|
||||
dev: false
|
||||
|
||||
/merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
dev: true
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import { useEffect, useRef, useState } from "react"
|
||||
import useOnClickOutside from "use-onclickoutside"
|
||||
import type { NoteMetadata } from "crossbell.js"
|
||||
import { PageContent } from "../common/PageContent"
|
||||
import { useState } from "react"
|
||||
import { useDate } from "~/hooks/useDate"
|
||||
import { PageContent } from "../common/PageContent"
|
||||
|
||||
import { Button, ButtonGroup } from "../ui/Button"
|
||||
import { useTranslation } from "next-i18next"
|
||||
|
||||
export const ImportPreview: React.FC<{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export const Avatar: React.FC<
|
|||
name?: string | null
|
||||
size?: number
|
||||
rounded?: boolean
|
||||
imageRef?: React.Ref<HTMLImageElement>
|
||||
imageRef?: React.MutableRefObject<HTMLImageElement>
|
||||
} & React.HTMLAttributes<HTMLSpanElement>
|
||||
> = ({ images, size, name, className, rounded, imageRef, ...props }) => {
|
||||
size = size || 60
|
||||
|
|
|
|||
|
|
@ -1,22 +1,70 @@
|
|||
import React from "react"
|
||||
import React, { useEffect } from "react"
|
||||
import { default as NextImage, ImageProps } from "next/image"
|
||||
import { toGateway, toIPFS } from "~/lib/ipfs-parser"
|
||||
import { useMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import { useGetState } from "~/hooks/useGetState"
|
||||
|
||||
export const Image: React.FC<
|
||||
{
|
||||
className?: string
|
||||
src?: string
|
||||
width?: number | string
|
||||
height?: number | string
|
||||
"original-src"?: string
|
||||
imageRef?: React.Ref<HTMLImageElement>
|
||||
} & React.HTMLAttributes<HTMLImageElement> &
|
||||
ImageProps
|
||||
> = ({ fill, className, alt, src, width, height, imageRef, ...props }) => {
|
||||
type TImageProps = {
|
||||
className?: string
|
||||
src?: string
|
||||
width?: number | string
|
||||
height?: number | string
|
||||
"original-src"?: string
|
||||
imageRef?: React.MutableRefObject<HTMLImageElement>
|
||||
zoom?: boolean
|
||||
} & React.HTMLAttributes<HTMLImageElement> &
|
||||
ImageProps
|
||||
|
||||
export const Image: React.FC<TImageProps> = ({
|
||||
fill,
|
||||
className,
|
||||
alt,
|
||||
src,
|
||||
width,
|
||||
height,
|
||||
imageRef,
|
||||
zoom,
|
||||
...props
|
||||
}) => {
|
||||
src = toIPFS(src)
|
||||
const [paddingTop, setPaddingTop] = React.useState("0")
|
||||
const [autoWidth, setAutoWidth] = React.useState(0)
|
||||
const noOptimization = className?.includes("no-optimization")
|
||||
const imageRefInternal = React.useRef<HTMLImageElement>(null)
|
||||
|
||||
const isMobileLayout = useMobileLayout()
|
||||
const getSrc = useGetState(src)
|
||||
|
||||
useEffect(() => {
|
||||
if (!imageRef) return
|
||||
if (!imageRefInternal.current) return
|
||||
|
||||
if (typeof imageRef === "object") {
|
||||
imageRef.current = imageRefInternal.current
|
||||
}
|
||||
}, [imageRef])
|
||||
useEffect(() => {
|
||||
const $image = imageRefInternal.current
|
||||
if (!$image) return
|
||||
if (isMobileLayout) {
|
||||
const clickHandler = () => {
|
||||
window.open(getSrc(), "_blank")
|
||||
}
|
||||
$image.addEventListener("click", clickHandler)
|
||||
return () => {
|
||||
$image.removeEventListener("click", clickHandler)
|
||||
}
|
||||
}
|
||||
if (zoom) {
|
||||
import("medium-zoom").then(({ default: mediumZoom }) => {
|
||||
mediumZoom($image, {
|
||||
margin: 10,
|
||||
background: "rgb(var(--tw-colors-i-white))",
|
||||
scrollOffset: 0,
|
||||
})
|
||||
})
|
||||
}
|
||||
}, [zoom, isMobileLayout])
|
||||
|
||||
if (!src) {
|
||||
return null
|
||||
|
|
@ -57,7 +105,7 @@ export const Image: React.FC<
|
|||
setAutoWidth(naturalWidth)
|
||||
}
|
||||
}}
|
||||
ref={imageRef}
|
||||
ref={imageRefInternal}
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
|
|
@ -89,9 +137,18 @@ export const Image: React.FC<
|
|||
setAutoWidth(naturalWidth)
|
||||
}
|
||||
}}
|
||||
ref={imageRef}
|
||||
ref={imageRefInternal}
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export const ZoomedImage: React.FC<TImageProps> = (props) => {
|
||||
return (
|
||||
<span className="text-center block">
|
||||
{/* eslint-disable-next-line jsx-a11y/alt-text */}
|
||||
<Image {...props} zoom />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { rehypeWrapCode } from "./rehype-wrap-code"
|
|||
import jsYaml from "js-yaml"
|
||||
import rehypeReact from "rehype-react"
|
||||
import { createElement, ReactElement } from "react"
|
||||
import { Image } from "~/components/ui/Image"
|
||||
import { ZoomedImage } from "~/components/ui/Image"
|
||||
import remarkDirective from "remark-directive"
|
||||
import remarkDirectiveRehype from "remark-directive-rehype"
|
||||
import { remarkYoutube } from "./remark-youtube"
|
||||
|
|
@ -177,7 +177,7 @@ export const renderPageContent = (
|
|||
.use(html ? () => (tree: any) => {} : rehypeReact, {
|
||||
createElement: createElement,
|
||||
components: {
|
||||
img: Image,
|
||||
img: ZoomedImage,
|
||||
anchor: Element,
|
||||
mention: Mention,
|
||||
mermaid: Mermaid,
|
||||
|
|
|
|||
Loading…
Reference in New Issue