mirror of
https://github.com/Dokploy/website
synced 2025-06-26 18:16:01 +00:00
feat: enhance markdown rendering with GFM plugins and image handling
This commit is contained in:
@@ -1,9 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import { cn } from "@/lib/utils";
|
||||||
import { PhotoProvider, PhotoView } from "react-photo-view";
|
import { PhotoProvider, PhotoView } from "react-photo-view";
|
||||||
import "react-photo-view/dist/react-photo-view.css";
|
import "react-photo-view/dist/react-photo-view.css";
|
||||||
|
|
||||||
interface ZoomableImageProps {
|
interface ZoomableImageProps {
|
||||||
src: string;
|
src: string;
|
||||||
alt: string;
|
alt: string;
|
||||||
@@ -14,12 +13,7 @@ export function ZoomableImage({ src, alt, className }: ZoomableImageProps) {
|
|||||||
return (
|
return (
|
||||||
<PhotoProvider>
|
<PhotoProvider>
|
||||||
<PhotoView src={src}>
|
<PhotoView src={src}>
|
||||||
<Image
|
<img src={src} alt={alt} className={cn("object-cover", className)} />
|
||||||
src={src}
|
|
||||||
alt={alt}
|
|
||||||
fill
|
|
||||||
className={`object-cover cursor-zoom-in ${className || ""}`}
|
|
||||||
/>
|
|
||||||
</PhotoView>
|
</PhotoView>
|
||||||
</PhotoProvider>
|
</PhotoProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ import remarkGfm from "remark-gfm";
|
|||||||
import { codeToHtml } from "shiki";
|
import { codeToHtml } from "shiki";
|
||||||
import type { BundledLanguage } from "shiki/bundle/web";
|
import type { BundledLanguage } from "shiki/bundle/web";
|
||||||
import TurndownService from "turndown";
|
import TurndownService from "turndown";
|
||||||
|
// @ts-ignore
|
||||||
|
import * as turndownPluginGfm from "turndown-plugin-gfm";
|
||||||
import { ZoomableImage } from "./components/ZoomableImage";
|
import { ZoomableImage } from "./components/ZoomableImage";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
params: { locale: string; slug: string };
|
params: { locale: string; slug: string };
|
||||||
};
|
};
|
||||||
@@ -128,39 +131,13 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
headingStyle: "atx",
|
headingStyle: "atx",
|
||||||
codeBlockStyle: "fenced",
|
codeBlockStyle: "fenced",
|
||||||
});
|
});
|
||||||
|
const gfm = turndownPluginGfm.gfm;
|
||||||
// Configurar el manejo de tablas
|
const tables = turndownPluginGfm.tables;
|
||||||
turndownService.addRule("table", {
|
const strikethrough = turndownPluginGfm.strikethrough;
|
||||||
filter: ["table"],
|
turndownService.use([tables, strikethrough, gfm]);
|
||||||
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 markdown = turndownService.turndown(post.html);
|
const markdown = turndownService.turndown(post.html);
|
||||||
|
|
||||||
console.log(markdown);
|
|
||||||
|
|
||||||
const formattedDate = new Date(post.published_at).toLocaleDateString(locale, {
|
const formattedDate = new Date(post.published_at).toLocaleDateString(locale, {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
@@ -232,9 +209,11 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
<td className="p-4 text-muted-foreground" {...props} />
|
<td className="p-4 text-muted-foreground" {...props} />
|
||||||
),
|
),
|
||||||
img: ({ node, src, alt }) => (
|
img: ({ node, src, alt }) => (
|
||||||
<span className="relative w-64 h-64 my-6 rounded-lg ">
|
<ZoomableImage
|
||||||
{src && <ZoomableImage src={src} alt={alt || ""} />}
|
src={src || ""}
|
||||||
</span>
|
alt={alt || ""}
|
||||||
|
className="object-cover max-w-lg mx-auto rounded-lg border border-border"
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
code: ({ inline, className, children, ...props }: CodeProps) => {
|
code: ({ inline, className, children, ...props }: CodeProps) => {
|
||||||
const match = /language-(\w+)/.exec(className || "");
|
const match = /language-(\w+)/.exec(className || "");
|
||||||
@@ -319,11 +298,11 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{post.feature_image && (
|
{post.feature_image && (
|
||||||
<div className="relative w-full h-[400px] mb-8">
|
<div className="relative w-full h-[400px] mb-8">
|
||||||
<ZoomableImage
|
<ZoomableImage
|
||||||
src={post.feature_image}
|
src={post.feature_image}
|
||||||
alt={post.title}
|
alt={post.title}
|
||||||
className="rounded-lg"
|
className="rounded-lg h-full w-full object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -43,7 +43,11 @@
|
|||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"turndown": "^7.2.0",
|
"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": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.9",
|
"@babel/core": "^7.26.9",
|
||||||
|
|||||||
@@ -41,11 +41,5 @@
|
|||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@types/react": "18.3.5",
|
"@types/react": "18.3.5",
|
||||||
"@types/react-dom": "18.3.0"
|
"@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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
@@ -11,19 +11,6 @@ overrides:
|
|||||||
importers:
|
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:
|
devDependencies:
|
||||||
'@biomejs/biome':
|
'@biomejs/biome':
|
||||||
specifier: 1.8.3
|
specifier: 1.8.3
|
||||||
@@ -179,9 +166,18 @@ importers:
|
|||||||
react-ga4:
|
react-ga4:
|
||||||
specifier: ^2.1.0
|
specifier: ^2.1.0
|
||||||
version: 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:
|
react-photo-view:
|
||||||
specifier: ^1.2.7
|
specifier: ^1.2.7
|
||||||
version: 1.2.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
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:
|
shiki:
|
||||||
specifier: 1.22.2
|
specifier: 1.22.2
|
||||||
version: 1.22.2
|
version: 1.22.2
|
||||||
@@ -197,6 +193,9 @@ importers:
|
|||||||
turndown:
|
turndown:
|
||||||
specifier: ^7.2.0
|
specifier: ^7.2.0
|
||||||
version: 7.2.0
|
version: 7.2.0
|
||||||
|
turndown-plugin-gfm:
|
||||||
|
specifier: ^1.0.2
|
||||||
|
version: 1.0.2
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 5.1.6
|
specifier: 5.1.6
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
@@ -1660,9 +1659,6 @@ packages:
|
|||||||
'@types/node@22.9.0':
|
'@types/node@22.9.0':
|
||||||
resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==}
|
resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==}
|
||||||
|
|
||||||
'@types/prismjs@1.26.5':
|
|
||||||
resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==}
|
|
||||||
|
|
||||||
'@types/prop-types@15.7.12':
|
'@types/prop-types@15.7.12':
|
||||||
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
|
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
|
||||||
|
|
||||||
@@ -3127,11 +3123,6 @@ packages:
|
|||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
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:
|
property-information@6.5.0:
|
||||||
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
|
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
|
||||||
|
|
||||||
@@ -3532,6 +3523,9 @@ packages:
|
|||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
turndown-plugin-gfm@1.0.2:
|
||||||
|
resolution: {integrity: sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg==}
|
||||||
|
|
||||||
turndown@7.2.0:
|
turndown@7.2.0:
|
||||||
resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==}
|
resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==}
|
||||||
|
|
||||||
@@ -5286,8 +5280,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
|
|
||||||
'@types/prismjs@1.26.5': {}
|
|
||||||
|
|
||||||
'@types/prop-types@15.7.12': {}
|
'@types/prop-types@15.7.12': {}
|
||||||
|
|
||||||
'@types/react-dom@18.3.0':
|
'@types/react-dom@18.3.0':
|
||||||
@@ -7068,12 +7060,6 @@ snapshots:
|
|||||||
|
|
||||||
prettier@3.3.3: {}
|
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@6.5.0: {}
|
||||||
|
|
||||||
property-information@7.0.0: {}
|
property-information@7.0.0: {}
|
||||||
@@ -7104,7 +7090,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
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:
|
dependencies:
|
||||||
'@types/hast': 3.0.4
|
'@types/hast': 3.0.4
|
||||||
'@types/mdast': 4.0.4
|
'@types/mdast': 4.0.4
|
||||||
@@ -7113,7 +7099,7 @@ snapshots:
|
|||||||
hast-util-to-jsx-runtime: 2.3.2
|
hast-util-to-jsx-runtime: 2.3.2
|
||||||
html-url-attributes: 3.0.1
|
html-url-attributes: 3.0.1
|
||||||
mdast-util-to-hast: 13.2.0
|
mdast-util-to-hast: 13.2.0
|
||||||
react: 18.3.1
|
react: 18.2.0
|
||||||
remark-parse: 11.0.0
|
remark-parse: 11.0.0
|
||||||
remark-rehype: 11.1.1
|
remark-rehype: 11.1.1
|
||||||
unified: 11.0.5
|
unified: 11.0.5
|
||||||
@@ -7598,6 +7584,8 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
turndown-plugin-gfm@1.0.2: {}
|
||||||
|
|
||||||
turndown@7.2.0:
|
turndown@7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@mixmark-io/domino': 2.2.0
|
'@mixmark-io/domino': 2.2.0
|
||||||
|
|||||||
Reference in New Issue
Block a user