From b19d453682a241ac06912274409213c0b5b8412c Mon Sep 17 00:00:00 2001
From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Date: Sun, 2 Mar 2025 17:12:46 -0600
Subject: [PATCH] feat: enhance markdown rendering with GFM plugins and image
handling
---
.../blog/[slug]/components/ZoomableImage.tsx | 10 +---
.../website/app/[locale]/blog/[slug]/page.tsx | 49 ++++++------------
apps/website/package.json | 6 ++-
package.json | 6 ---
pnpm-lock.yaml | 50 +++++++------------
5 files changed, 40 insertions(+), 81 deletions(-)
diff --git a/apps/website/app/[locale]/blog/[slug]/components/ZoomableImage.tsx b/apps/website/app/[locale]/blog/[slug]/components/ZoomableImage.tsx
index dd0c276..702c342 100644
--- a/apps/website/app/[locale]/blog/[slug]/components/ZoomableImage.tsx
+++ b/apps/website/app/[locale]/blog/[slug]/components/ZoomableImage.tsx
@@ -1,9 +1,8 @@
"use client";
-import Image from "next/image";
+import { cn } from "@/lib/utils";
import { PhotoProvider, PhotoView } from "react-photo-view";
import "react-photo-view/dist/react-photo-view.css";
-
interface ZoomableImageProps {
src: string;
alt: string;
@@ -14,12 +13,7 @@ export function ZoomableImage({ src, alt, className }: ZoomableImageProps) {
return (
-
+
);
diff --git a/apps/website/app/[locale]/blog/[slug]/page.tsx b/apps/website/app/[locale]/blog/[slug]/page.tsx
index 32af490..958431b 100644
--- a/apps/website/app/[locale]/blog/[slug]/page.tsx
+++ b/apps/website/app/[locale]/blog/[slug]/page.tsx
@@ -14,7 +14,10 @@ import remarkGfm from "remark-gfm";
import { codeToHtml } from "shiki";
import type { BundledLanguage } from "shiki/bundle/web";
import TurndownService from "turndown";
+// @ts-ignore
+import * as turndownPluginGfm from "turndown-plugin-gfm";
import { ZoomableImage } from "./components/ZoomableImage";
+
type Props = {
params: { locale: string; slug: string };
};
@@ -128,39 +131,13 @@ export default async function BlogPostPage({ params }: Props) {
headingStyle: "atx",
codeBlockStyle: "fenced",
});
-
- // Configurar el manejo de tablas
- turndownService.addRule("table", {
- filter: ["table"],
- replacement: (content, node) => {
- const rows = node.rows;
- let markdown = "\n";
-
- // Headers
- if (rows.length > 0) {
- const headers = Array.from(rows[0].cells).map((cell) =>
- cell.textContent.trim(),
- );
- markdown += `| ${headers.join(" | ")} |\n`;
- markdown += `| ${headers.map(() => "---").join(" | ")} |\n`;
- }
-
- // Body
- for (let i = 1; i < rows.length; i++) {
- const cells = Array.from(rows[i].cells).map((cell) =>
- cell.textContent.trim(),
- );
- markdown += `| ${cells.join(" | ")} |\n`;
- }
-
- return `${markdown}\n`;
- },
- });
+ const gfm = turndownPluginGfm.gfm;
+ const tables = turndownPluginGfm.tables;
+ const strikethrough = turndownPluginGfm.strikethrough;
+ turndownService.use([tables, strikethrough, gfm]);
const markdown = turndownService.turndown(post.html);
- console.log(markdown);
-
const formattedDate = new Date(post.published_at).toLocaleDateString(locale, {
year: "numeric",
month: "long",
@@ -232,9 +209,11 @@ export default async function BlogPostPage({ params }: Props) {
|
),
img: ({ node, src, alt }) => (
-
- {src && }
-
+
),
code: ({ inline, className, children, ...props }: CodeProps) => {
const match = /language-(\w+)/.exec(className || "");
@@ -319,11 +298,11 @@ export default async function BlogPostPage({ params }: Props) {
{post.feature_image && (
-
+
)}
diff --git a/apps/website/package.json b/apps/website/package.json
index dc118f1..ef3d913 100644
--- a/apps/website/package.json
+++ b/apps/website/package.json
@@ -43,7 +43,11 @@
"tailwindcss": "^3.4.1",
"tailwindcss-animate": "^1.0.7",
"turndown": "^7.2.0",
- "typescript": "5.1.6"
+ "turndown-plugin-gfm": "^1.0.2",
+ "typescript": "5.1.6",
+ "react-markdown": "^10.0.0",
+ "rehype-raw": "^7.0.0",
+ "remark-gfm": "^4.0.1"
},
"devDependencies": {
"@babel/core": "^7.26.9",
diff --git a/package.json b/package.json
index dd83963..b1400fb 100644
--- a/package.json
+++ b/package.json
@@ -41,11 +41,5 @@
"resolutions": {
"@types/react": "18.3.5",
"@types/react-dom": "18.3.0"
- },
- "dependencies": {
- "prism-react-renderer": "^2.4.1",
- "react-markdown": "^10.0.0",
- "rehype-raw": "^7.0.0",
- "remark-gfm": "^4.0.1"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d771ab9..b0945c2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,19 +11,6 @@ overrides:
importers:
.:
- dependencies:
- prism-react-renderer:
- specifier: ^2.4.1
- version: 2.4.1(react@18.3.1)
- react-markdown:
- specifier: ^10.0.0
- version: 10.0.0(@types/react@18.3.5)(react@18.3.1)
- rehype-raw:
- specifier: ^7.0.0
- version: 7.0.0
- remark-gfm:
- specifier: ^4.0.1
- version: 4.0.1
devDependencies:
'@biomejs/biome':
specifier: 1.8.3
@@ -179,9 +166,18 @@ importers:
react-ga4:
specifier: ^2.1.0
version: 2.1.0
+ react-markdown:
+ specifier: ^10.0.0
+ version: 10.0.0(@types/react@18.3.5)(react@18.2.0)
react-photo-view:
specifier: ^1.2.7
version: 1.2.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ rehype-raw:
+ specifier: ^7.0.0
+ version: 7.0.0
+ remark-gfm:
+ specifier: ^4.0.1
+ version: 4.0.1
shiki:
specifier: 1.22.2
version: 1.22.2
@@ -197,6 +193,9 @@ importers:
turndown:
specifier: ^7.2.0
version: 7.2.0
+ turndown-plugin-gfm:
+ specifier: ^1.0.2
+ version: 1.0.2
typescript:
specifier: 5.1.6
version: 5.1.6
@@ -1660,9 +1659,6 @@ packages:
'@types/node@22.9.0':
resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==}
- '@types/prismjs@1.26.5':
- resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==}
-
'@types/prop-types@15.7.12':
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
@@ -3127,11 +3123,6 @@ packages:
engines: {node: '>=14'}
hasBin: true
- prism-react-renderer@2.4.1:
- resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==}
- peerDependencies:
- react: '>=16.0.0'
-
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
@@ -3532,6 +3523,9 @@ packages:
engines: {node: '>=18.0.0'}
hasBin: true
+ turndown-plugin-gfm@1.0.2:
+ resolution: {integrity: sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg==}
+
turndown@7.2.0:
resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==}
@@ -5286,8 +5280,6 @@ snapshots:
dependencies:
undici-types: 6.19.8
- '@types/prismjs@1.26.5': {}
-
'@types/prop-types@15.7.12': {}
'@types/react-dom@18.3.0':
@@ -7068,12 +7060,6 @@ snapshots:
prettier@3.3.3: {}
- prism-react-renderer@2.4.1(react@18.3.1):
- dependencies:
- '@types/prismjs': 1.26.5
- clsx: 2.1.1
- react: 18.3.1
-
property-information@6.5.0: {}
property-information@7.0.0: {}
@@ -7104,7 +7090,7 @@ snapshots:
dependencies:
react: 18.3.1
- react-markdown@10.0.0(@types/react@18.3.5)(react@18.3.1):
+ react-markdown@10.0.0(@types/react@18.3.5)(react@18.2.0):
dependencies:
'@types/hast': 3.0.4
'@types/mdast': 4.0.4
@@ -7113,7 +7099,7 @@ snapshots:
hast-util-to-jsx-runtime: 2.3.2
html-url-attributes: 3.0.1
mdast-util-to-hast: 13.2.0
- react: 18.3.1
+ react: 18.2.0
remark-parse: 11.0.0
remark-rehype: 11.1.1
unified: 11.0.5
@@ -7598,6 +7584,8 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
+ turndown-plugin-gfm@1.0.2: {}
+
turndown@7.2.0:
dependencies:
'@mixmark-io/domino': 2.2.0