From 40810d76c1aea756670a43cab021975e6ffec83e Mon Sep 17 00:00:00 2001 From: DIYgod Date: Wed, 7 Jun 2023 22:00:15 +0100 Subject: [PATCH] feat: blur data and fixed size for post images, close #440 --- next.config.js | 2 +- package.json | 1 + pnpm-lock.yaml | 11 +++++++++++ src/app/api/image/route.ts | 37 +++++++++++++++++++++++++++++++++++++ src/components/ui/Image.tsx | 13 ++++++++++++- src/markdown/index.ts | 6 ------ src/queries/page.ts | 15 +++++++++++++++ 7 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 src/app/api/image/route.ts diff --git a/next.config.js b/next.config.js index cae1fa0f..bb2ef29f 100644 --- a/next.config.js +++ b/next.config.js @@ -88,7 +88,7 @@ module.exports = withBundleAnalyzer( // https://github.com/kkomelin/isomorphic-dompurify/issues/54 // Fix isomorphic-dompurify in app router - config.externals = [...config.externals, "canvas", "jsdom"] + config.externals = [...config.externals, "canvas", "jsdom", "sharp"] return config }, diff --git a/package.json b/package.json index 295aba4f..27168b5b 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "pangu": "4.0.7", "path-to-regexp": "6.2.1", "pinyin-pro": "3.14.0", + "plaiceholder": "3.0.0", "prismjs": "1.29.0", "qier-progress": "1.0.4", "rc-dplayer": "0.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f5298d7..0c9260ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -224,6 +224,9 @@ dependencies: pinyin-pro: specifier: 3.14.0 version: 3.14.0 + plaiceholder: + specifier: 3.0.0 + version: 3.0.0(sharp@0.32.1) prismjs: specifier: 1.29.0 version: 1.29.0 @@ -11070,6 +11073,14 @@ packages: find-up: 4.1.0 dev: true + /plaiceholder@3.0.0(sharp@0.32.1): + resolution: {integrity: sha512-jwHxxHPnr1BwRzPCeZgEK2BMsEy2327sWynw3qb6XC/oGgGDUTPtR8pFxFQmNArhMBwhkUbUr5OPhhIJpCa8eQ==} + peerDependencies: + sharp: '>= 0.30.6' + dependencies: + sharp: 0.32.1 + dev: false + /pngjs@5.0.0: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} diff --git a/src/app/api/image/route.ts b/src/app/api/image/route.ts new file mode 100644 index 00000000..03f50a08 --- /dev/null +++ b/src/app/api/image/route.ts @@ -0,0 +1,37 @@ +import { getPlaiceholder } from "plaiceholder" + +import { cacheGet } from "~/lib/redis.server" +import { NextServerResponse, getQuery } from "~/lib/server-helper" + +const getImage = async (src: string) => { + return cacheGet({ + key: ["getImage", src], + noUpdate: true, + getValueFun: async () => { + const buffer = await fetch(src).then(async (res) => + Buffer.from(await res.arrayBuffer()), + ) + + const { + metadata: { height, width }, + ...plaiceholder + } = await getPlaiceholder(buffer, { size: 10 }) + + return { + base64: plaiceholder.base64, + size: { height, width }, + } + }, + }) +} + +export async function GET(req: Request) { + let { url } = getQuery(req) + if (!url) { + return new NextServerResponse() + .status(400) + .json({ error: "url is required" }) + } + const res = new NextServerResponse() + return res.status(200).json(await getImage(url)) +} diff --git a/src/components/ui/Image.tsx b/src/components/ui/Image.tsx index 2f8f822b..85d5a8cd 100644 --- a/src/components/ui/Image.tsx +++ b/src/components/ui/Image.tsx @@ -6,6 +6,7 @@ import React, { useEffect } from "react" import { useGetState } from "~/hooks/useGetState" import { useIsMobileLayout } from "~/hooks/useMobileLayout" import { toGateway, toIPFS } from "~/lib/ipfs-parser" +import { useGetImageInfo } from "~/queries/page" type TImageProps = { className?: string @@ -152,10 +153,20 @@ export const Image: React.FC = ({ } export const ZoomedImage: React.FC = (props) => { + const info = useGetImageInfo(props.src) + const autoProps = info?.data + ? { + width: info.data.size?.width, + height: info.data.size?.height, + blurDataURL: info.data.base64, + placeholder: "blur" as const, + } + : {} + return ( {/* eslint-disable-next-line jsx-a11y/alt-text */} - + ) } diff --git a/src/markdown/index.ts b/src/markdown/index.ts index 0608be17..ed820db8 100644 --- a/src/markdown/index.ts +++ b/src/markdown/index.ts @@ -219,12 +219,6 @@ export const renderPageContent = ( } }, }) - // .use(rehypeRewrite, { - // selector: "h1", - // rewrite: (node: any) => { - // node.tagName = "h2" - // }, - // }) .use(rehypePrism, { ignoreMissing: true, showLineNumbers: true, diff --git a/src/queries/page.ts b/src/queries/page.ts index 17b21c9e..6eb5ee62 100644 --- a/src/queries/page.ts +++ b/src/queries/page.ts @@ -419,3 +419,18 @@ export function useCheckMirror(characterId?: number) { return pageModel.checkMirror(characterId) }) } + +export function useGetImageInfo(src?: string) { + return useQuery(["getImageInfo", src], async () => { + if (!src) { + return + } + return (await (await fetch(`/api/image?url=${src}`)).json()) as { + size: { + width: number + height: number + } + base64: string + } + }) +}