Skip to content

Commit 5c12d22

Browse files
authored
Merge pull request #231 from 1chooo/feature/#218
feat(markdown): update image tag
2 parents cbdb767 + c09b119 commit 5c12d22

File tree

4 files changed

+113
-4
lines changed

4 files changed

+113
-4
lines changed

apps/docs/pages/wiki.mdx

+43
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,46 @@ $ npm install next
6868
- [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/)
6969
- [Migrating from Create React App](https://nextjs-ja-translation-docs.vercel.app/docs/migrating/from-create-react-app)
7070

71+
# Dangerously Set innerHTML
72+
73+
https://dev.to/shareef/rendering-markdown-made-easy-with-react-markdown-in-reactjs-and-nextjs-web-apps-259d
74+
75+
```
76+
In HTML, <div> cannot be a descendant of <p>.
77+
This will cause a hydration error.
78+
```
79+
80+
```tsx
81+
...
82+
<Markdown>
83+
<p>
84+
^^^
85+
<http://localhost:3000/_next/static/chunks/src_dd03ef._.js:150:225>
86+
<div>
87+
```
88+
89+
```diff
90+
+ const isImageNode = (node: any): node is Element => {
91+
+ return node && node.type === 'element' && node.tagName === 'img';
92+
+ };
93+
94+
const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content }) => (
95+
<ReactMarkdown
96+
remarkPlugins={[remarkGfm]}
97+
rehypePlugins={[rehypeRaw]}
98+
components={{
99+
+ p: ({ node, children }) => {
100+
+ const hasImage = node && node.children && node.children.some(isImageNode);
101+
+ if (hasImage) {
102+
+ return <>{children}</>;
103+
+ }
104+
+ return <p>{children}</p>;
105+
+ },
106+
...
107+
>
108+
{content}
109+
</ReactMarkdown>
110+
);
111+
112+
export default MarkdownRenderer;
113+
```

apps/web/src/app/post/page.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import Link from 'next/link';
2-
import { getBlogPosts } from '../db/blog';
2+
import { getBlogPosts } from '@/app/db/blog';
33
import PageHeader from '@/components/page-header';
44
import Image from 'next/image';
55

66
export const metadata = {
7-
title: 'Blog',
7+
title: 'Blog | Hugo ChunHo Lin (1chooo) | Open Source Enthusiast',
88
description: 'Read my thoughts on software development, design, and more.',
99
};
1010

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use client";
2+
3+
import React, { useState } from 'react';
4+
import Image from 'next/image';
5+
6+
interface MarkdownImageProps {
7+
src: string;
8+
alt?: string;
9+
}
10+
11+
const MarkdownImage: React.FC<MarkdownImageProps> = ({ src, alt }) => {
12+
const [imageSize, setImageSize] = useState({ width: 1, height: 1 });
13+
14+
return (
15+
<div
16+
style={{
17+
marginTop: '1rem',
18+
maxWidth: '80%',
19+
margin: '0 auto',
20+
textAlign: 'center',
21+
}}
22+
>
23+
<Image
24+
src={src}
25+
alt={alt ?? 'Image'}
26+
layout="responsive"
27+
objectFit="contain"
28+
priority={true}
29+
onLoadingComplete={(target) => {
30+
setImageSize({
31+
width: target.naturalWidth,
32+
height: target.naturalHeight,
33+
});
34+
}}
35+
width={imageSize.width}
36+
height={imageSize.height}
37+
/>
38+
{alt && (
39+
<div
40+
style={{
41+
marginTop: '0.5rem',
42+
fontSize: '0.9rem',
43+
color: '#555',
44+
textAlign: 'center',
45+
marginBottom: '1rem',
46+
}}
47+
>
48+
{alt}
49+
</div>
50+
)}
51+
</div>
52+
);
53+
};
54+
55+
export default MarkdownImage;

apps/web/src/components/markdown/markdown-renderer.tsx

+13-2
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,32 @@ import rehypeRaw from 'rehype-raw';
66
import Anchor from './anchor';
77
import BlockQuote from './block-quote';
88
import CodeBlock from './code-block';
9-
9+
import MarkdownImage from './markdown-image';
1010

1111
interface MarkdownRendererProps {
1212
content: string;
1313
}
1414

15+
const isImageNode = (node: any): node is Element => {
16+
return node && node.type === 'element' && node.tagName === 'img';
17+
};
18+
1519
const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content }) => (
1620
<ReactMarkdown
1721
remarkPlugins={[remarkGfm]}
1822
rehypePlugins={[rehypeRaw]}
1923
components={{
24+
p: ({ node, children }) => {
25+
const hasImage = node && node.children && node.children.some(isImageNode);
26+
if (hasImage) {
27+
return <>{children}</>;
28+
}
29+
return <p>{children}</p>;
30+
},
2031
a: (props) => <Anchor {...props} />,
2132
sup: 'sup',
2233
sub: 'sub',
23-
img: (props) => <img {...props} style={{ maxWidth: '80%', margin: '0 auto' }} />,
34+
img: (props) => <MarkdownImage src={props.src ?? ''} alt={props.alt} />,
2435
ul: (props) => (
2536
<ul
2637
{...props}

0 commit comments

Comments
 (0)