refactor: get html media info implement, fixed #671
Signed-off-by: Innei <i@innei.in>
This commit is contained in:
parent
1ac465cbb9
commit
71749fa505
|
|
@ -22,8 +22,7 @@ export const useSourceContentModal = () => {
|
|||
content: () => <SourceContentView src={src} />,
|
||||
resizeable: true,
|
||||
clickOutsideToDismiss: true,
|
||||
// The number was picked arbitrarily
|
||||
resizeDefaultSize: { width: 900, height: 700 },
|
||||
max: true,
|
||||
})
|
||||
},
|
||||
[present],
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { createElement, Fragment, memo, useEffect, useMemo, useState } from "react"
|
||||
|
||||
import type { MediaInfo } from "~/lib/parse-html"
|
||||
import { parseHtml } from "~/lib/parse-html"
|
||||
import type { RemarkOptions } from "~/lib/parse-markdown"
|
||||
import { parseMarkdown } from "~/lib/parse-markdown"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { useWrappedElementSize } from "~/providers/wrapped-element-provider"
|
||||
|
||||
import { MediaContainerWidthProvider } from "../media"
|
||||
import type { MediaInfoRecord } from "../media"
|
||||
import { MediaContainerWidthProvider, MediaInfoRecordProvider } from "../media"
|
||||
import { MarkdownRenderContainerRefContext } from "./context"
|
||||
|
||||
export const Markdown: Component<
|
||||
|
|
@ -45,7 +45,7 @@ const HTMLImpl = <A extends keyof JSX.IntrinsicElements = "div">(
|
|||
|
||||
accessory?: React.ReactNode
|
||||
noMedia?: boolean
|
||||
mediaInfo?: MediaInfo
|
||||
mediaInfo?: MediaInfoRecord
|
||||
} & JSX.IntrinsicElements[A] &
|
||||
Partial<{
|
||||
renderInlineStyle: boolean
|
||||
|
|
@ -55,7 +55,6 @@ const HTMLImpl = <A extends keyof JSX.IntrinsicElements = "div">(
|
|||
const [remarkOptions, setRemarkOptions] = useState({
|
||||
renderInlineStyle,
|
||||
noMedia,
|
||||
mediaInfo,
|
||||
})
|
||||
const [shouldForceReMountKey, setShouldForceReMountKey] = useState(0)
|
||||
|
||||
|
|
@ -87,7 +86,9 @@ const HTMLImpl = <A extends keyof JSX.IntrinsicElements = "div">(
|
|||
return (
|
||||
<MarkdownRenderContainerRefContext.Provider value={refElement}>
|
||||
<MediaContainerWidthProvider width={containerWidth}>
|
||||
{createElement(as, { ...rest, ref: setRefElement }, markdownElement)}
|
||||
<MediaInfoRecordProvider mediaInfo={mediaInfo}>
|
||||
{createElement(as, { ...rest, ref: setRefElement }, markdownElement)}
|
||||
</MediaInfoRecordProvider>
|
||||
</MediaContainerWidthProvider>
|
||||
{accessory && <Fragment key={shouldForceReMountKey}>{accessory}</Fragment>}
|
||||
</MarkdownRenderContainerRefContext.Provider>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,15 @@ const MediaImpl: FC<MediaProps> = ({
|
|||
thumbnail,
|
||||
...props
|
||||
}) => {
|
||||
const { src, style, type, previewImageUrl, showFallback, blurhash, ...rest } = props
|
||||
const { src, style, type, previewImageUrl, showFallback, blurhash, height, width, ...rest } =
|
||||
props
|
||||
|
||||
const ctxMediaInfo = useContext(MediaInfoRecordContext)
|
||||
const ctxHeight = ctxMediaInfo[src!]?.height
|
||||
const ctxWidth = ctxMediaInfo[src!]?.width
|
||||
|
||||
const finalHeight = height || ctxHeight
|
||||
const finalWidth = width || ctxWidth
|
||||
|
||||
const [imgSrc, setImgSrc] = useState(() =>
|
||||
proxy && src && !failedList.has(src)
|
||||
|
|
@ -130,6 +138,8 @@ const MediaImpl: FC<MediaProps> = ({
|
|||
case "photo": {
|
||||
return (
|
||||
<img
|
||||
height={finalHeight}
|
||||
width={finalWidth}
|
||||
{...(rest as ImgHTMLAttributes<HTMLImageElement>)}
|
||||
onError={errorHandle}
|
||||
className={cn(
|
||||
|
|
@ -152,7 +162,7 @@ const MediaImpl: FC<MediaProps> = ({
|
|||
<span
|
||||
className={cn(
|
||||
"center",
|
||||
!(props.width || props.height) && "size-full",
|
||||
!(finalWidth || finalHeight) && "size-full",
|
||||
"relative cursor-card bg-stone-100 object-cover",
|
||||
mediaContainerClassName,
|
||||
)}
|
||||
|
|
@ -172,11 +182,11 @@ const MediaImpl: FC<MediaProps> = ({
|
|||
handleOnLoad,
|
||||
imgSrc,
|
||||
mediaContainerClassName,
|
||||
finalHeight,
|
||||
finalWidth,
|
||||
mediaLoadState,
|
||||
popper,
|
||||
previewImageSrc,
|
||||
props.height,
|
||||
props.width,
|
||||
rest,
|
||||
src,
|
||||
thumbnail,
|
||||
|
|
@ -388,3 +398,21 @@ export const MediaContainerWidthProvider = ({
|
|||
const useMediaContainerWidth = () => {
|
||||
return useContext(MediaContainerWidthContext)
|
||||
}
|
||||
|
||||
export type MediaInfoRecord = Record<string, { width?: number; height?: number }>
|
||||
const MediaInfoRecordContext = createContext<MediaInfoRecord>({})
|
||||
|
||||
const noop = {} as const
|
||||
export const MediaInfoRecordProvider = ({
|
||||
children,
|
||||
mediaInfo,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
mediaInfo?: MediaInfoRecord
|
||||
}) => {
|
||||
return (
|
||||
<MediaInfoRecordContext.Provider value={mediaInfo || noop}>
|
||||
{children}
|
||||
</MediaInfoRecordContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,14 +31,11 @@ function markInlineImage(node?: Element) {
|
|||
}
|
||||
}
|
||||
|
||||
export type MediaInfo = Record<string, { width?: number; height?: number }>
|
||||
|
||||
export const parseHtml = (
|
||||
content: string,
|
||||
options?: Partial<{
|
||||
renderInlineStyle: boolean
|
||||
noMedia?: boolean
|
||||
mediaInfo?: MediaInfo
|
||||
}>,
|
||||
) => {
|
||||
const file = new VFile(content)
|
||||
|
|
@ -99,13 +96,7 @@ export const parseHtml = (
|
|||
markInlineImage(node)
|
||||
return createElement(MarkdownLink, { ...props } as any)
|
||||
},
|
||||
img: ({ ...props }) => {
|
||||
return createElement(Img, {
|
||||
...props,
|
||||
width: props.src ? options?.mediaInfo?.[props.src]?.width : props.width,
|
||||
height: props.src ? options?.mediaInfo?.[props.src]?.height : props.height,
|
||||
})
|
||||
},
|
||||
img: Img,
|
||||
|
||||
h1: createHeadingRenderer(1),
|
||||
h2: createHeadingRenderer(2),
|
||||
|
|
@ -216,6 +207,7 @@ const Img: Components["img"] = ({ node, ...props }) => {
|
|||
...props,
|
||||
proxy: { height: 0, width: 700 },
|
||||
}
|
||||
|
||||
if (node?.properties.inline) {
|
||||
return createElement(Media, {
|
||||
type: "photo",
|
||||
|
|
|
|||
|
|
@ -145,21 +145,25 @@ export const EntryContentRender: Component<{
|
|||
: undefined,
|
||||
[readerFontFamily],
|
||||
)
|
||||
const mediaInfo = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
(entry?.entries.media ?? data?.entries.media)
|
||||
?.filter((m) => m.type === "photo")
|
||||
.map((cur) => [
|
||||
cur.url,
|
||||
{
|
||||
width: cur.width,
|
||||
height: cur.height,
|
||||
},
|
||||
]) ?? [],
|
||||
),
|
||||
[entry?.entries.media, data?.entries.media],
|
||||
)
|
||||
|
||||
if (!entry) return null
|
||||
|
||||
const content = entry?.entries.content ?? data?.entries.content
|
||||
const mediaInfo = Object.fromEntries(
|
||||
(entry.entries.media ?? data?.entries.media)
|
||||
?.filter((m) => m.type === "photo")
|
||||
.map((cur) => [
|
||||
cur.url,
|
||||
{
|
||||
width: cur.width,
|
||||
height: cur.height,
|
||||
},
|
||||
]) ?? [],
|
||||
)
|
||||
|
||||
return (
|
||||
<EntryContentProvider
|
||||
|
|
|
|||
Loading…
Reference in New Issue