From 4568d6ced5e2b39860a4d5d0b0dc7b9562b18ed0 Mon Sep 17 00:00:00 2001 From: Hugo ChunHo Lin Date: Wed, 11 Sep 2024 17:11:56 +0800 Subject: [PATCH 1/6] feat(markdown): display image with Next.js Image, add alt text displayed below (#218) --- .../components/markdown/markdown-renderer.tsx | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/markdown/markdown-renderer.tsx b/apps/web/src/components/markdown/markdown-renderer.tsx index 54fdb89c..13d121bf 100644 --- a/apps/web/src/components/markdown/markdown-renderer.tsx +++ b/apps/web/src/components/markdown/markdown-renderer.tsx @@ -1,13 +1,15 @@ -import React from 'react'; +"use client"; + +import React, { useState } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import rehypeRaw from 'rehype-raw'; +import Image from 'next/image'; import Anchor from './anchor'; import BlockQuote from './block-quote'; import CodeBlock from './code-block'; - interface MarkdownRendererProps { content: string; } @@ -20,7 +22,45 @@ const MarkdownRenderer: React.FC = ({ content }) => ( a: (props) => , sup: 'sup', sub: 'sub', - img: (props) => , + img: (props) => { + const [imageSize, setImageSize] = useState({ width: 1, height: 1 }); + + return ( +
+ {props.alt { + setImageSize({ + width: target.naturalWidth, + height: target.naturalHeight, + }); + }} + width={imageSize.width} + height={imageSize.height} + /> + {props.alt && ( +
+ {props.alt} +
+ )} +
+ ); + }, ul: (props) => (
    Date: Wed, 11 Sep 2024 17:19:13 +0800 Subject: [PATCH 2/6] fix(markdown): add isImageNode to prevent Hydration Error (#232) --- .../src/components/markdown/markdown-renderer.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/markdown/markdown-renderer.tsx b/apps/web/src/components/markdown/markdown-renderer.tsx index 13d121bf..45923e05 100644 --- a/apps/web/src/components/markdown/markdown-renderer.tsx +++ b/apps/web/src/components/markdown/markdown-renderer.tsx @@ -14,11 +14,22 @@ interface MarkdownRendererProps { content: string; } +const isImageNode = (node: any): node is Element => { + return node && node.type === 'element' && node.tagName === 'img'; +}; + const MarkdownRenderer: React.FC = ({ content }) => ( { + const hasImage = node && node.children && node.children.some(isImageNode); + if (hasImage) { + return <>{children}; + } + return

    {children}

    ; + }, a: (props) => , sup: 'sup', sub: 'sub', @@ -103,4 +114,4 @@ const MarkdownRenderer: React.FC = ({ content }) => (
    ); -export default MarkdownRenderer; +export default MarkdownRenderer; \ No newline at end of file From 2f739f6532239ded404960795adef3dbeb70baa9 Mon Sep 17 00:00:00 2001 From: Hugo ChunHo Lin Date: Wed, 11 Sep 2024 17:20:15 +0800 Subject: [PATCH 3/6] feat(markdown): adjust image margin styling (#218) --- apps/web/src/components/markdown/markdown-renderer.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/markdown/markdown-renderer.tsx b/apps/web/src/components/markdown/markdown-renderer.tsx index 45923e05..89a57e51 100644 --- a/apps/web/src/components/markdown/markdown-renderer.tsx +++ b/apps/web/src/components/markdown/markdown-renderer.tsx @@ -39,6 +39,7 @@ const MarkdownRenderer: React.FC = ({ content }) => ( return (
    = ({ content }) => ( marginTop: '0.5rem', fontSize: '0.9rem', color: '#555', - textAlign: 'center' + textAlign: 'center', + marginBottom: '1rem', }}> {props.alt}
    @@ -114,4 +116,4 @@ const MarkdownRenderer: React.FC = ({ content }) => ( ); -export default MarkdownRenderer; \ No newline at end of file +export default MarkdownRenderer; From 3495061da2060472e0b955ab9aca68ab871eb6b2 Mon Sep 17 00:00:00 2001 From: Hugo ChunHo Lin Date: Wed, 11 Sep 2024 17:23:44 +0800 Subject: [PATCH 4/6] docs(markdown): add solution with div in p (#233) --- apps/docs/pages/wiki.mdx | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/apps/docs/pages/wiki.mdx b/apps/docs/pages/wiki.mdx index 68455cd6..01590fa9 100644 --- a/apps/docs/pages/wiki.mdx +++ b/apps/docs/pages/wiki.mdx @@ -68,3 +68,46 @@ $ npm install next - [How to Migrate from create-react-app to Vite using Jest and Browserslist](https://www.freecodecamp.org/news/how-to-migrate-from-create-react-app-to-vite/) - [Migrating from Create React App](https://nextjs-ja-translation-docs.vercel.app/docs/migrating/from-create-react-app) +# Dangerously Set innerHTML + +https://dev.to/shareef/rendering-markdown-made-easy-with-react-markdown-in-reactjs-and-nextjs-web-apps-259d + +``` +In HTML,
    cannot be a descendant of

    . +This will cause a hydration error. +``` + +```tsx +... + +

    + ^^^ + +

    +``` + +```diff ++ const isImageNode = (node: any): node is Element => { ++ return node && node.type === 'element' && node.tagName === 'img'; ++ }; + +const MarkdownRenderer: React.FC = ({ content }) => ( + { ++ const hasImage = node && node.children && node.children.some(isImageNode); ++ if (hasImage) { ++ return <>{children}; ++ } ++ return

    {children}

    ; ++ }, + ... + > + {content} +
    +); + +export default MarkdownRenderer; +``` \ No newline at end of file From 79b95824f08130dddccfe47797100070d03b6e09 Mon Sep 17 00:00:00 2001 From: Hugo ChunHo Lin Date: Wed, 11 Sep 2024 17:27:34 +0800 Subject: [PATCH 5/6] refactor(markdown): extract MarkdownImage component for rendering images in markdown (#218) --- .../components/markdown/markdown-image.tsx | 55 +++++++++++++++++++ .../components/markdown/markdown-renderer.tsx | 48 +--------------- 2 files changed, 58 insertions(+), 45 deletions(-) create mode 100644 apps/web/src/components/markdown/markdown-image.tsx diff --git a/apps/web/src/components/markdown/markdown-image.tsx b/apps/web/src/components/markdown/markdown-image.tsx new file mode 100644 index 00000000..9984911a --- /dev/null +++ b/apps/web/src/components/markdown/markdown-image.tsx @@ -0,0 +1,55 @@ +"use client"; + +import React, { useState } from 'react'; +import Image from 'next/image'; + +interface MarkdownImageProps { + src: string; + alt?: string; +} + +const MarkdownImage: React.FC = ({ src, alt }) => { + const [imageSize, setImageSize] = useState({ width: 1, height: 1 }); + + return ( +
    + {alt { + setImageSize({ + width: target.naturalWidth, + height: target.naturalHeight, + }); + }} + width={imageSize.width} + height={imageSize.height} + /> + {alt && ( +
    + {alt} +
    + )} +
    + ); +}; + +export default MarkdownImage; diff --git a/apps/web/src/components/markdown/markdown-renderer.tsx b/apps/web/src/components/markdown/markdown-renderer.tsx index 89a57e51..5ead363f 100644 --- a/apps/web/src/components/markdown/markdown-renderer.tsx +++ b/apps/web/src/components/markdown/markdown-renderer.tsx @@ -1,14 +1,12 @@ -"use client"; - -import React, { useState } from 'react'; +import React from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import rehypeRaw from 'rehype-raw'; -import Image from 'next/image'; import Anchor from './anchor'; import BlockQuote from './block-quote'; import CodeBlock from './code-block'; +import MarkdownImage from './markdown-image'; interface MarkdownRendererProps { content: string; @@ -33,47 +31,7 @@ const MarkdownRenderer: React.FC = ({ content }) => ( a: (props) => , sup: 'sup', sub: 'sub', - img: (props) => { - const [imageSize, setImageSize] = useState({ width: 1, height: 1 }); - - return ( -
    - {props.alt { - setImageSize({ - width: target.naturalWidth, - height: target.naturalHeight, - }); - }} - width={imageSize.width} - height={imageSize.height} - /> - {props.alt && ( -
    - {props.alt} -
    - )} -
    - ); - }, + img: (props) => , ul: (props) => (
      Date: Wed, 11 Sep 2024 17:29:36 +0800 Subject: [PATCH 6/6] feat(blog): update metadata and getBlogPosts imported path --- apps/web/src/app/post/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/post/page.tsx b/apps/web/src/app/post/page.tsx index 90a98188..ddd76542 100644 --- a/apps/web/src/app/post/page.tsx +++ b/apps/web/src/app/post/page.tsx @@ -1,10 +1,10 @@ import Link from 'next/link'; -import { getBlogPosts } from '../db/blog'; +import { getBlogPosts } from '@/app/db/blog'; import PageHeader from '@/components/page-header'; import Image from 'next/image'; export const metadata = { - title: 'Blog', + title: 'Blog | Hugo ChunHo Lin (1chooo) | Open Source Enthusiast', description: 'Read my thoughts on software development, design, and more.', };