From 71749fa505f29e4f0cbb22ce7e9e559c24a9ecee Mon Sep 17 00:00:00 2001 From: Innei Date: Tue, 1 Oct 2024 20:06:41 +0800 Subject: [PATCH] refactor: get html media info implement, fixed #671 Signed-off-by: Innei --- apps/renderer/src/atoms/source-content.tsx | 3 +- .../src/components/ui/markdown/Markdown.tsx | 11 +++--- apps/renderer/src/components/ui/media.tsx | 36 ++++++++++++++++--- apps/renderer/src/lib/parse-html.ts | 12 ++----- .../src/modules/entry-content/index.tsx | 26 ++++++++------ 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/apps/renderer/src/atoms/source-content.tsx b/apps/renderer/src/atoms/source-content.tsx index e89de49b4..6ac184f92 100644 --- a/apps/renderer/src/atoms/source-content.tsx +++ b/apps/renderer/src/atoms/source-content.tsx @@ -22,8 +22,7 @@ export const useSourceContentModal = () => { content: () => , resizeable: true, clickOutsideToDismiss: true, - // The number was picked arbitrarily - resizeDefaultSize: { width: 900, height: 700 }, + max: true, }) }, [present], diff --git a/apps/renderer/src/components/ui/markdown/Markdown.tsx b/apps/renderer/src/components/ui/markdown/Markdown.tsx index 9b5d7c468..16c23cf79 100644 --- a/apps/renderer/src/components/ui/markdown/Markdown.tsx +++ b/apps/renderer/src/components/ui/markdown/Markdown.tsx @@ -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 = ( accessory?: React.ReactNode noMedia?: boolean - mediaInfo?: MediaInfo + mediaInfo?: MediaInfoRecord } & JSX.IntrinsicElements[A] & Partial<{ renderInlineStyle: boolean @@ -55,7 +55,6 @@ const HTMLImpl = ( const [remarkOptions, setRemarkOptions] = useState({ renderInlineStyle, noMedia, - mediaInfo, }) const [shouldForceReMountKey, setShouldForceReMountKey] = useState(0) @@ -87,7 +86,9 @@ const HTMLImpl = ( return ( - {createElement(as, { ...rest, ref: setRefElement }, markdownElement)} + + {createElement(as, { ...rest, ref: setRefElement }, markdownElement)} + {accessory && {accessory}} diff --git a/apps/renderer/src/components/ui/media.tsx b/apps/renderer/src/components/ui/media.tsx index 1d42fde2c..add667108 100644 --- a/apps/renderer/src/components/ui/media.tsx +++ b/apps/renderer/src/components/ui/media.tsx @@ -52,7 +52,15 @@ const MediaImpl: FC = ({ 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 = ({ case "photo": { return ( )} onError={errorHandle} className={cn( @@ -152,7 +162,7 @@ const MediaImpl: FC = ({ = ({ 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 +const MediaInfoRecordContext = createContext({}) + +const noop = {} as const +export const MediaInfoRecordProvider = ({ + children, + mediaInfo, +}: { + children: React.ReactNode + mediaInfo?: MediaInfoRecord +}) => { + return ( + + {children} + + ) +} diff --git a/apps/renderer/src/lib/parse-html.ts b/apps/renderer/src/lib/parse-html.ts index d73b34bbd..bc7a81175 100644 --- a/apps/renderer/src/lib/parse-html.ts +++ b/apps/renderer/src/lib/parse-html.ts @@ -31,14 +31,11 @@ function markInlineImage(node?: Element) { } } -export type MediaInfo = Record - 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", diff --git a/apps/renderer/src/modules/entry-content/index.tsx b/apps/renderer/src/modules/entry-content/index.tsx index a2854264b..1fd0e05e7 100644 --- a/apps/renderer/src/modules/entry-content/index.tsx +++ b/apps/renderer/src/modules/entry-content/index.tsx @@ -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 (