Skip to content

Commit e0bcb71

Browse files
committed
fix(media-preview): solve image cls
Signed-off-by: Innei <i@innei.in>
1 parent c8cdfd1 commit e0bcb71

File tree

6 files changed

+70
-26
lines changed

6 files changed

+70
-26
lines changed

apps/renderer/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"path-to-regexp": "8.1.0",
7777
"posthog-js": "1.163.0",
7878
"re-resizable": "6.9.18",
79+
"react-blurhash": "^0.3.0",
7980
"react-error-boundary": "4.0.13",
8081
"react-fast-marquee": "1.6.5",
8182
"react-hook-form": "7.53.0",

apps/renderer/src/components/ui/markdown/Markdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const HTMLImpl = <A extends keyof JSX.IntrinsicElements = "div">(
5656

5757
useEffect(() => {
5858
setRemarkOptions((options) => {
59-
if (renderInlineStyle === options.renderInlineStyle || noMedia === options.noMedia) {
59+
if (JSON.stringify(options) === JSON.stringify({ renderInlineStyle, noMedia })) {
6060
return options
6161
}
6262

apps/renderer/src/components/ui/media/hooks.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ export const usePreviewMedia = (entryId?: string) => {
2525
clickOutsideToDismiss: true,
2626
})
2727
},
28-
[present],
28+
[entryId, present],
2929
)
3030
}

apps/renderer/src/components/ui/media/preview-media.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { MediaModel } from "@follow/shared/hono"
22
import type { FC } from "react"
33
import { Fragment, useCallback, useEffect, useRef, useState } from "react"
4+
import { Blurhash } from "react-blurhash"
45
import { Keyboard, Mousewheel } from "swiper/modules"
56
import type { SwiperRef } from "swiper/react"
67
import { Swiper, SwiperSlide } from "swiper/react"
@@ -125,6 +126,9 @@ export const PreviewMediaContent: FC<{
125126
className="h-full w-auto object-contain"
126127
alt="cover"
127128
src={src}
129+
height={media[0].height}
130+
width={media[0].width}
131+
blurhash={media[0].blurhash}
128132
/>
129133
)}
130134
</Wrapper>
@@ -236,8 +240,9 @@ const FallbackableImage: FC<
236240
src: string
237241
containerClassName?: string
238242
fallbackUrl?: string
243+
blurhash?: string
239244
}
240-
> = ({ src, onError, fallbackUrl, containerClassName, ...props }) => {
245+
> = ({ src, onError, fallbackUrl, containerClassName, blurhash, ...props }) => {
241246
const [currentSrc, setCurrentSrc] = useState(() => replaceImgUrlIfNeed(src))
242247
const [isAllError, setIsAllError] = useState(false)
243248

@@ -281,11 +286,32 @@ const FallbackableImage: FC<
281286
<div className={cn("flex size-full flex-col", containerClassName)}>
282287
{isLoading && !isAllError && (
283288
<div className="center absolute inset-0 size-full">
284-
<i className="i-mgc-loading-3-cute-re size-8 animate-spin text-white/80" />
289+
{blurhash ? (
290+
<Blurhash
291+
hash={blurhash}
292+
resolutionX={32}
293+
resolutionY={32}
294+
className="!size-full"
295+
style={{ aspectRatio: `${props.width} / ${props.height}` }}
296+
/>
297+
) : (
298+
<i className="i-mgc-loading-3-cute-re size-8 animate-spin text-white/80" />
299+
)}
285300
</div>
286301
)}
287302
{!isAllError && (
288-
<img src={currentSrc} onLoad={() => setIsLoading(false)} onError={handleError} {...props} />
303+
<img
304+
src={currentSrc}
305+
onLoad={() => setIsLoading(false)}
306+
onError={handleError}
307+
height={props.height}
308+
width={props.width}
309+
{...props}
310+
className={cn(
311+
blurhash && !isLoading ? "duration-500 ease-in-out animate-in fade-in-0" : "",
312+
props.className,
313+
)}
314+
/>
289315
)}
290316
{isAllError && (
291317
<div

apps/renderer/src/lib/parse-html.ts

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Element, Text } from "hast"
2+
import type { Schema } from "hast-util-sanitize"
23
import type { Components } from "hast-util-to-jsx-runtime"
34
import { toJsxRuntime } from "hast-util-to-jsx-runtime"
45
import { toText } from "hast-util-to-text"
@@ -32,29 +33,26 @@ export const parseHtml = (
3233
const file = new VFile(content)
3334
const { renderInlineStyle = false, noMedia = false } = options || {}
3435

36+
const rehypeSchema: Schema = { ...defaultSchema }
37+
38+
if (noMedia) {
39+
rehypeSchema.tagNames = rehypeSchema.tagNames?.filter(
40+
(tag) => tag !== "img" && tag !== "picture",
41+
)
42+
} else {
43+
rehypeSchema.tagNames = [...rehypeSchema.tagNames!, "video", "style"]
44+
rehypeSchema.attributes = {
45+
...rehypeSchema.attributes,
46+
"*": renderInlineStyle
47+
? [...rehypeSchema.attributes!["*"], "style", "class"]
48+
: rehypeSchema.attributes!["*"],
49+
video: ["src", "poster"],
50+
}
51+
}
52+
3553
const pipeline = unified()
3654
.use(rehypeParse, { fragment: true })
37-
.use(
38-
rehypeSanitize,
39-
noMedia
40-
? {
41-
...defaultSchema,
42-
tagNames: defaultSchema.tagNames?.filter((tag) => tag !== "img" && tag !== "picture"),
43-
}
44-
: {
45-
...defaultSchema,
46-
tagNames: [...defaultSchema.tagNames!, "video", "style"],
47-
attributes: {
48-
...defaultSchema.attributes,
49-
50-
"*": renderInlineStyle
51-
? [...defaultSchema.attributes!["*"], "style", "class"]
52-
: defaultSchema.attributes!["*"],
53-
54-
video: ["src", "poster"],
55-
},
56-
},
57-
)
55+
.use(rehypeSanitize, rehypeSchema)
5856

5957
.use(rehypeInferDescriptionMeta)
6058
.use(rehypeStringify)

pnpm-lock.yaml

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)